From 418ccd7cf3fa33818425e0aa892ecb9ef05e9687 Mon Sep 17 00:00:00 2001 From: Mounir Dhahri Date: Wed, 20 Aug 2025 17:53:55 +0200 Subject: [PATCH 001/123] chore: use react-native-launch-arguments new architecture supported version --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 88eab599e2a..3a245ef36b0 100644 --- a/package.json +++ b/package.json @@ -178,7 +178,7 @@ "react-native-in-app-review": "4.3.3", "react-native-keychain": "10.0.0", "react-native-keys": "0.7.13", - "react-native-launch-arguments": "4.1.0", + "react-native-launch-arguments": "git+https://github.com/artsy/react-native-launch-arguments.git#v4.0.1-new-arch", "react-native-linear-gradient": "2.8.3", "react-native-localize": "3.5.2", "react-native-pager-view": "6.7.1", diff --git a/yarn.lock b/yarn.lock index e6640821c93..02b32e3b7e2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -12739,7 +12739,7 @@ __metadata: react-native-in-app-review: "npm:4.3.3" react-native-keychain: "npm:10.0.0" react-native-keys: "npm:0.7.13" - react-native-launch-arguments: "npm:4.1.0" + react-native-launch-arguments: "git+https://github.com/artsy/react-native-launch-arguments.git#v4.0.1-new-arch" react-native-linear-gradient: "npm:2.8.3" react-native-localize: "npm:3.5.2" react-native-pager-view: "npm:6.7.1" @@ -21623,13 +21623,13 @@ __metadata: languageName: node linkType: hard -"react-native-launch-arguments@npm:4.1.0": +"react-native-launch-arguments@git+https://github.com/artsy/react-native-launch-arguments.git#v4.0.1-new-arch": version: 4.1.0 - resolution: "react-native-launch-arguments@npm:4.1.0" + resolution: "react-native-launch-arguments@https://github.com/artsy/react-native-launch-arguments.git#commit=b1623c84667fed965fd5a00193031f1b689e2120" peerDependencies: react: ">=16.8.1" react-native: ">=0.60.0-rc.0 <1.0.x" - checksum: 10c0/9ab5247ec436dc7741bb4cd43ade834a84b47c6cbe660e8ce6fb042166eac5a1fffbdda1826061a9e3194f114643d5694b01315fd9b451c777dfdc1942d46df1 + checksum: 10c0/99b6f146f0de280225bbe9b6914206b8ef18208336e0eace20d1dcdc124d92178b02e8d31bf539d804b85c2d5b8ba21626dffcfd8c7d3b31dd88ec92291c3b53 languageName: node linkType: hard From ab45748e35392d26dac33dda89842e9f23ee70d0 Mon Sep 17 00:00:00 2001 From: brainbicycle Date: Fri, 22 Aug 2025 13:41:14 -0400 Subject: [PATCH 002/123] enable new arch --- android/gradle.properties | 2 +- ios/Podfile | 2 +- ios/Podfile.properties.json | 3 ++- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/android/gradle.properties b/android/gradle.properties index 4042f1a591c..2d71ca5ec72 100644 --- a/android/gradle.properties +++ b/android/gradle.properties @@ -43,7 +43,7 @@ reactNativeArchitectures=armeabi-v7a,arm64-v8a,x86,x86_64 # your application. You should enable this flag either if you want # to write custom TurboModules/Fabric components OR use libraries that # are providing them. -newArchEnabled=false +newArchEnabled=true # Use this property to enable or disable the Hermes JS engine. # If set to false, you will be using JSC instead. diff --git a/ios/Podfile b/ios/Podfile index 89d43935b97..e86e2860157 100644 --- a/ios/Podfile +++ b/ios/Podfile @@ -98,7 +98,7 @@ target 'Artsy' do :production => ENV['CIRCLE_BUILD_NUM'], # An absolute path to your application root. :app_path => "#{Pod::Config.instance.installation_root}/..", - new_arch_enabled: false + new_arch_enabled: true ) # Networking diff --git a/ios/Podfile.properties.json b/ios/Podfile.properties.json index b1bd45da51d..125dd1f27c3 100644 --- a/ios/Podfile.properties.json +++ b/ios/Podfile.properties.json @@ -1,3 +1,4 @@ { - "expo.jsEngine": "hermes" + "expo.jsEngine": "hermes", + "expo.newArchEnabled": true } From 3b74b813c462b33a4d2eb37f0e84f4cf7bb2908e Mon Sep 17 00:00:00 2001 From: George Kartalis Date: Wed, 27 Aug 2025 18:20:13 +0200 Subject: [PATCH 003/123] fix: unleash error --- src/app/system/flags/Components/WrappedFlagProvider.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/system/flags/Components/WrappedFlagProvider.tsx b/src/app/system/flags/Components/WrappedFlagProvider.tsx index 102b33fbd26..a8a4936a2cb 100644 --- a/src/app/system/flags/Components/WrappedFlagProvider.tsx +++ b/src/app/system/flags/Components/WrappedFlagProvider.tsx @@ -39,7 +39,7 @@ export const WrappedFlagProvider: React.FC = ({ childre } return ( - + fn()} config={config} startClient={false}> {children} ) From 397efc53fbcf76639e09361e882d0e7606d44d0c Mon Sep 17 00:00:00 2001 From: brainbicycle Date: Tue, 7 Oct 2025 08:44:41 -0400 Subject: [PATCH 004/123] yarn install:all --- ios/Artsy/App_Resources/Info.plist | 2 +- ios/ArtsyStickers/Info.plist | 2 +- ios/ArtsyWidget/Info.plist | 2 +- ios/BrazePushServiceExtension/Info.plist | 2 +- ios/Podfile.lock | 534 +++++++++++++++++++++-- 5 files changed, 501 insertions(+), 41 deletions(-) diff --git a/ios/Artsy/App_Resources/Info.plist b/ios/Artsy/App_Resources/Info.plist index 02bbf1d6886..6bbc0428957 100644 --- a/ios/Artsy/App_Resources/Info.plist +++ b/ios/Artsy/App_Resources/Info.plist @@ -144,7 +144,7 @@ NSPhotoLibraryUsageDescription Photos will be used to gauge the quality of the work you are submitting. RCTNewArchEnabled - + UIAppFonts Unica77LL-Italic.otf diff --git a/ios/ArtsyStickers/Info.plist b/ios/ArtsyStickers/Info.plist index f7b5684bfc3..2e6a1fbfd69 100644 --- a/ios/ArtsyStickers/Info.plist +++ b/ios/ArtsyStickers/Info.plist @@ -14,6 +14,6 @@ StickerBrowserViewController RCTNewArchEnabled - + diff --git a/ios/ArtsyWidget/Info.plist b/ios/ArtsyWidget/Info.plist index 191171c7459..dcaf77ebeda 100644 --- a/ios/ArtsyWidget/Info.plist +++ b/ios/ArtsyWidget/Info.plist @@ -12,6 +12,6 @@ com.apple.widgetkit-extension RCTNewArchEnabled - + diff --git a/ios/BrazePushServiceExtension/Info.plist b/ios/BrazePushServiceExtension/Info.plist index bfdb202e319..e0f56bfcaf7 100644 --- a/ios/BrazePushServiceExtension/Info.plist +++ b/ios/BrazePushServiceExtension/Info.plist @@ -14,6 +14,6 @@ $(PRODUCT_MODULE_NAME).NotificationService RCTNewArchEnabled - + diff --git a/ios/Podfile.lock b/ios/Podfile.lock index b0aad1926af..0b5531da374 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -2108,7 +2108,33 @@ PODS: - ReactCommon/turbomodule/core - SocketRocket - react-native-blob-util (0.19.11): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - hermes-engine + - RCT-Folly + - RCT-Folly/Fabric + - RCTRequired + - RCTTypeSafety - React-Core + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-ImageManager + - React-jsi + - React-NativeModulesApple + - React-RCTFabric + - React-renderercss + - React-rendererdebug + - React-utils + - ReactCodegen + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - SocketRocket + - Yoga - react-native-blurhash (2.1.1): - boost - DoubleConversion @@ -2278,11 +2304,122 @@ PODS: - SocketRocket - Yoga - react-native-performance (5.1.4): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - hermes-engine + - RCT-Folly + - RCT-Folly/Fabric + - RCTRequired + - RCTTypeSafety - React-Core + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-ImageManager + - React-jsi + - React-NativeModulesApple + - React-RCTFabric + - React-renderercss + - React-rendererdebug + - React-utils + - ReactCodegen + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - SocketRocket + - Yoga - react-native-render-html (6.3.4): - React-Core - react-native-safe-area-context (5.6.1): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - hermes-engine + - RCT-Folly + - RCT-Folly/Fabric + - RCTRequired + - RCTTypeSafety + - React-Core + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-ImageManager + - React-jsi + - react-native-safe-area-context/common (= 5.6.1) + - react-native-safe-area-context/fabric (= 5.6.1) + - React-NativeModulesApple + - React-RCTFabric + - React-renderercss + - React-rendererdebug + - React-utils + - ReactCodegen + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - SocketRocket + - Yoga + - react-native-safe-area-context/common (5.6.1): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - hermes-engine + - RCT-Folly + - RCT-Folly/Fabric + - RCTRequired + - RCTTypeSafety - React-Core + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-ImageManager + - React-jsi + - React-NativeModulesApple + - React-RCTFabric + - React-renderercss + - React-rendererdebug + - React-utils + - ReactCodegen + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - SocketRocket + - Yoga + - react-native-safe-area-context/fabric (5.6.1): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - hermes-engine + - RCT-Folly + - RCT-Folly/Fabric + - RCTRequired + - RCTTypeSafety + - React-Core + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-ImageManager + - React-jsi + - react-native-safe-area-context/common + - React-NativeModulesApple + - React-RCTFabric + - React-renderercss + - React-rendererdebug + - React-utils + - ReactCodegen + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - SocketRocket + - Yoga - react-native-shake (6.8.1): - boost - DoubleConversion @@ -2875,20 +3012,124 @@ PODS: - RNAppleAuthentication (2.1.5): - React-Core - RNBootSplash (6.3.10): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - hermes-engine + - RCT-Folly + - RCT-Folly/Fabric + - RCTRequired + - RCTTypeSafety - React-Core + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-ImageManager + - React-jsi + - React-NativeModulesApple + - React-RCTFabric + - React-renderercss + - React-rendererdebug + - React-utils + - ReactCodegen + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - SocketRocket + - Yoga - RNCAsyncStorage (2.2.0): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - hermes-engine + - RCT-Folly + - RCT-Folly/Fabric + - RCTRequired + - RCTTypeSafety - React-Core + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-ImageManager + - React-jsi + - React-NativeModulesApple + - React-RCTFabric + - React-renderercss + - React-rendererdebug + - React-utils + - ReactCodegen + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - SocketRocket + - Yoga - RNCClipboard (1.16.2): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - hermes-engine + - RCT-Folly + - RCT-Folly/Fabric + - RCTRequired + - RCTTypeSafety - React-Core + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-ImageManager + - React-jsi + - React-NativeModulesApple + - React-RCTFabric + - React-renderercss + - React-rendererdebug + - React-utils + - ReactCodegen + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - SocketRocket + - Yoga - RNDeviceInfo (14.0.0): - React-Core - RNFastImage (8.12.0): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - hermes-engine - libavif/core (~> 0.11.1) - libavif/libdav1d (~> 0.11.1) + - RCT-Folly + - RCT-Folly/Fabric + - RCTRequired + - RCTTypeSafety - React-Core + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-ImageManager + - React-jsi + - React-NativeModulesApple + - React-RCTFabric + - React-renderercss + - React-rendererdebug + - React-utils + - ReactCodegen + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core - SDWebImage (>= 5.19.1) - SDWebImageAVIFCoder (~> 0.11.0) - SDWebImageWebPCoder (~> 0.14) + - SocketRocket + - Yoga - RNFBApp (23.1.0): - Firebase/CoreOnly (= 12.1.0) - React-Core @@ -3046,7 +3287,33 @@ PODS: - SocketRocket - Yoga - RNLocalize (3.5.2): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - hermes-engine + - RCT-Folly + - RCT-Folly/Fabric + - RCTRequired + - RCTTypeSafety - React-Core + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-ImageManager + - React-jsi + - React-NativeModulesApple + - React-RCTFabric + - React-renderercss + - React-rendererdebug + - React-utils + - ReactCodegen + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - SocketRocket + - Yoga - rnmapbox-maps (10.1.44): - MapboxMaps (~> 10.19.0) - React @@ -3054,17 +3321,64 @@ PODS: - rnmapbox-maps/DynamicLibrary (= 10.1.44) - Turf - rnmapbox-maps/DynamicLibrary (10.1.44): + - boost + - DoubleConversion + - fast_float + - fmt + - hermes-engine - MapboxMaps (~> 10.19.0) + - RCT-Folly + - RCT-Folly/Fabric + - RCTRequired + - RCTTypeSafety - React - React-Core + - React-featureflags + - React-ImageManager + - React-jsi + - React-NativeModulesApple + - React-RCTFabric + - React-renderercss + - React-rendererdebug + - ReactCodegen + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - SocketRocket - Turf + - Yoga - RNNotifee (9.1.8): - React-Core - RNNotifee/NotifeeCore (= 9.1.8) - RNNotifee/NotifeeCore (9.1.8): - React-Core - RNPermissions (3.8.4): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - hermes-engine + - RCT-Folly + - RCT-Folly/Fabric + - RCTRequired + - RCTTypeSafety - React-Core + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-ImageManager + - React-jsi + - React-NativeModulesApple + - React-RCTFabric + - React-renderercss + - React-rendererdebug + - React-utils + - ReactCodegen + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - SocketRocket + - Yoga - RNReactNativeHapticFeedback (1.13.0): - React-Core - RNReanimated (3.19.4): @@ -3217,6 +3531,36 @@ PODS: - SocketRocket - Yoga - RNScreens (4.16.0): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - hermes-engine + - RCT-Folly + - RCT-Folly/Fabric + - RCTRequired + - RCTTypeSafety + - React-Core + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-ImageManager + - React-jsi + - React-NativeModulesApple + - React-RCTFabric + - React-RCTImage + - React-renderercss + - React-rendererdebug + - React-utils + - ReactCodegen + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - RNScreens/common (= 4.16.0) + - SocketRocket + - Yoga + - RNScreens/common (4.16.0): - boost - DoubleConversion - fast_float @@ -3304,7 +3648,62 @@ PODS: - SocketRocket - Yoga - RNSVG (15.14.0): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - hermes-engine + - RCT-Folly + - RCT-Folly/Fabric + - RCTRequired + - RCTTypeSafety + - React-Core + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-ImageManager + - React-jsi + - React-NativeModulesApple + - React-RCTFabric + - React-renderercss + - React-rendererdebug + - React-utils + - ReactCodegen + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - RNSVG/common (= 15.14.0) + - SocketRocket + - Yoga + - RNSVG/common (15.14.0): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - hermes-engine + - RCT-Folly + - RCT-Folly/Fabric + - RCTRequired + - RCTTypeSafety - React-Core + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-ImageManager + - React-jsi + - React-NativeModulesApple + - React-RCTFabric + - React-renderercss + - React-rendererdebug + - React-utils + - ReactCodegen + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - SocketRocket + - Yoga - SDWebImage (5.19.1): - SDWebImage/Core (= 5.19.1) - SDWebImage/Core (5.19.1) @@ -3334,13 +3733,74 @@ PODS: - StripePaymentsUI (= 24.19.0) - StripeUICore (= 24.19.0) - stripe-react-native (0.50.3): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - hermes-engine + - RCT-Folly + - RCT-Folly/Fabric + - RCTRequired + - RCTTypeSafety + - React-Core + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-ImageManager + - React-jsi + - React-NativeModulesApple + - React-RCTFabric + - React-renderercss + - React-rendererdebug + - React-utils + - ReactCodegen + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - SocketRocket + - Stripe (~> 24.19.0) + - stripe-react-native/NewArch (= 0.50.3) + - StripeApplePay (~> 24.19.0) + - StripeFinancialConnections (~> 24.19.0) + - StripePayments (~> 24.19.0) + - StripePaymentSheet (~> 24.19.0) + - StripePaymentsUI (~> 24.19.0) + - Yoga + - stripe-react-native/NewArch (0.50.3): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - hermes-engine + - RCT-Folly + - RCT-Folly/Fabric + - RCTRequired + - RCTTypeSafety - React-Core + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-ImageManager + - React-jsi + - React-NativeModulesApple + - React-RCTFabric + - React-renderercss + - React-rendererdebug + - React-utils + - ReactCodegen + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - SocketRocket - Stripe (~> 24.19.0) - StripeApplePay (~> 24.19.0) - StripeFinancialConnections (~> 24.19.0) - StripePayments (~> 24.19.0) - StripePaymentSheet (~> 24.19.0) - StripePaymentsUI (~> 24.19.0) + - Yoga - StripeApplePay (24.19.0): - StripeCore (= 24.19.0) - StripeCore (24.19.0) @@ -3943,7 +4403,7 @@ SPEC CHECKSUMS: AFNetworking: 9d57de7506959955d82fb5274ee4bec86b930e52 AppAuth: d4f13a8fe0baf391b2108511793e4b479691fb73 boost: 7e761d76ca2ce687f7cc98e698152abd03a18f90 - braze-react-native-sdk: 85a849ef0e6a2d35cc261f982013d06f0e0907ef + braze-react-native-sdk: 06e01f3e619ee54edaae49ab6470f643df118422 BrazeKit: 4dff9532234bb6faa1721a87f7927cc4c2880f28 BrazeLocation: 7c828b42008203ae512e0ed846c4e0e294c27052 BrazeUI: df3abdd46d2fe158cac147e9a8651d56be67a337 @@ -3961,16 +4421,16 @@ SPEC CHECKSUMS: EXManifests: 224345a575fca389073c416297b6348163f28d1a Expecta: 3b6bd90a64b9a1dcb0b70aa0e10a7f8f631667d5 "Expecta+Snapshots": 7a3ac7ad2b9bae43aadb4dca08113bb495c98f3e - Expo: fcdc7d98a60a5762f18a47676b7245b1849cf3fb + Expo: 038e807e43fecf6e306f04df6542d22f2da92d5e ExpoAdapterFBSDKNext: 16c905ebd6449c37bd5dfbb2784a678ce084b26e ExpoAdapterGoogleSignIn: 3a02de846d07a35ed9d505bb45f66592d20c1de0 ExpoAsset: 9ba6fbd677fb8e241a3899ac00fa735bc911eadf ExpoFileSystem: b79eadbda7b7f285f378f95f959cc9313a1c9c61 ExpoFont: cf9d90ec1d3b97c4f513211905724c8171f82961 ExpoKeepAwake: 1a2e820692e933c94a565ec3fbbe38ac31658ffe - ExpoModulesCore: 891cb597118e80dd7f600153f2a7e643b9bca6f7 + ExpoModulesCore: c38e2b16c117698c4ac907d1b929d111601d5db8 EXStructuredHeaders: c951e77f2d936f88637421e9588c976da5827368 - EXUpdates: 0c59ecce7971e00c27785feededd97ef1aeaa14a + EXUpdates: 1751b113e229ba77c6dbb9c076a44a7d90917447 EXUpdatesInterface: 5adf50cb41e079c861da6d9b4b954c3db9a50734 fast_float: b32c788ed9c6a8c584d114d0047beda9664e7cc6 FBAEMKit: b2ed182002dbcb65d5a60059c9693d322186cd00 @@ -4057,39 +4517,39 @@ SPEC CHECKSUMS: React-logger: a913317214a26565cd4c045347edf1bcacb80a3f React-Mapbuffer: 94f4264de2cb156960cd82b338a403f4653f2fd9 React-microtasksnativemodule: 6c4ee39a36958c39c97b074d28f360246a335e84 - react-native-blob-util: f7234c91ad0e3faeee51b3edee80b61553f74993 - react-native-blurhash: b9ce90b66b73b8483cb4f510ece10b25d901ea33 + react-native-blob-util: 10c78778354e6c92b7a5afa4a1027cf0f18a9bb9 + react-native-blurhash: c1721deafe7a685088ea14ab4712a1c460be9fe4 react-native-context-menu-view: 74fbcf8a5f842c4802d0121addda2f8ffca43604 react-native-cookies: b90327af903c8a7652100201d890c50a98697799 - react-native-document-picker: a5b16a4479790738a9536013121331d9108d25c0 + react-native-document-picker: f26f09a90cce65b5d682f21b511e8eb09a506fdc react-native-fbsdk-next: 52f81e60eb3e8e0e06cf9728b4572d3509ca9d01 - react-native-geolocation: 2679f2c50cc4923545b57024bebb58d78b134a57 + react-native-geolocation: 95e48fe2687e5a8280103085372fa62c2297c5d6 react-native-get-random-values: d16467cf726c618e9c7a8c3c39c31faa2244bbba react-native-in-app-review: b3d1eed3d1596ebf6539804778272c4c65e4a400 - react-native-keys: c61a7d6e52300fccb68a60b849940ad5cd904b98 + react-native-keys: 80dc5f204b236ff384be06a514294eb24c65bd1f react-native-launch-arguments: 165260aba9544f00c66fae3e136b11484d0cb49b react-native-netinfo: cec9c4e86083cb5b6aba0e0711f563e2fbbff187 - react-native-pager-view: 972919b76c6dbe92566554b2fb500d37ceca4f35 - react-native-performance: 49e245623a3ecee9dc6b228ad7870a98dbedf9ea + react-native-pager-view: 4669cb3244c99fec52997f8906dd92f44b6ae17e + react-native-performance: 1cff1830de6c7b64d56b5c0c92b6dbece74acc03 react-native-render-html: 5afc4751f1a98621b3009432ef84c47019dcb2bd - react-native-safe-area-context: 2243039f43d10cb1ea30ec5ac57fc6d1448413f4 - react-native-shake: 76be733c1142bd741fd5ebcf2a1c9dd2c9bca126 - react-native-view-shot: b5fc41b75f8ce016389105414e7d9225bc6a7cd3 - react-native-webview: 94ae920685a61c5e36438a30ce47fe521011c5bd + react-native-safe-area-context: c6e2edd1c1da07bdce287fa9d9e60c5f7b514616 + react-native-shake: a701ed43830d9d7940893f4f7b837970d322ae63 + react-native-view-shot: 6c008e58f4720de58370848201c5d4a082c6d4ca + react-native-webview: 4cbb7f05f2c50671a7dcff4012d3e85faad271e4 React-NativeModulesApple: ebf2ce72b35870036900d6498b33724386540a71 React-oscompat: eb0626e8ba1a2c61673c991bf9dc21834898475d React-perflogger: 509e1f9a3ee28df71b0a66de806ac515ce951246 React-performancetimeline: 43a1ea36ac47853b479ae85e04c1c339721e99f1 React-RCTActionSheet: 30fe8f9f8d86db4a25ff34595a658ecd837485fc React-RCTAnimation: 3126eb1cb8e7a6ca33a52fd833d8018aa9311af1 - React-RCTAppDelegate: 580873aef88cf9f054559f53193333c64844ed02 + React-RCTAppDelegate: b03981c790aa40cf26e0f78cc0f1f2df8287ead4 React-RCTBlob: 53c35e85c85d6bdaa55dc81a0b290d4e78431095 - React-RCTFabric: 2116086e4b0f9cdb3ae7882fab54af91add55675 - React-RCTFBReactNativeSpec: 6964bed5a0ee4cff46af08e8720e9f4732b72371 + React-RCTFabric: 4e2a4176f99b6b8f2d2eda9fc82453a3e6c3ef8e + React-RCTFBReactNativeSpec: 947126c649e04b95457a40bc97c4b2a76206534b React-RCTImage: 074b2faa71a152a456c974e118b60c9eeda94a64 React-RCTLinking: e5ca17a4f7ae2ad7b0c0483be77e1b383ecd0a8a React-RCTNetwork: c508d7548c9eceac30a8100a846ea00033a03366 - React-RCTRuntime: 90cad3ae18c9e8e273dea74a54068ded36e870b9 + React-RCTRuntime: 6813778046c775c124179d9e4d7b33d4129bbd84 React-RCTSettings: dd84c857a4fce42c1e08c1dabcda894e25af4a6e React-RCTText: 6e4b177d047f98bccb90d6fb1ebdd3391cf8b299 React-RCTVibration: 9572d4a06a0c92650bcc62913e50eb2a89f19fb6 @@ -4107,28 +4567,28 @@ SPEC CHECKSUMS: ReactCodegen: 6c26f8c25d0b5ae66f86a1cce1777076ac8bcbd8 ReactCommon: 5f0e5c09a64a2717215dd84380e1a747810406f2 RNAppleAuthentication: 98f367520bd647ea4c094dc3e133106ac523798a - RNBootSplash: 866866f2a3856cd76547a24c6a63be79aeca40f8 - RNCAsyncStorage: b44e8a4e798c3e1f56bffccd0f591f674fb9198f - RNCClipboard: e1d17c9d093d8129ef50b39b63a17a0e8ccd0ade + RNBootSplash: a3179e35cb328629176b7891e1ef1fb9ef364fc3 + RNCAsyncStorage: 29f0230e1a25f36c20b05f65e2eb8958d6526e82 + RNCClipboard: adba6334687b7fb2c37760e26dedd550b4846a72 RNDeviceInfo: f632df5f5d9262794c03eac265e4a0f6dbb14f0a - RNFastImage: d08eb15eaa651ba916e0304febfe2ee342afc65c + RNFastImage: 4b6aa4ec13de8dc57deef25f89f00aa93a2cf139 RNFBApp: fcac8339a5ffd5a735c62d5f0101f79e4d9a7670 RNFBMessaging: 8c72e2f7d5eb2cc24d87e60c8be21eb2c94da272 - RNFlashList: 3ff55e40f74f7cd92cb5bc7486390b8c5c9648b6 - RNGestureHandler: 12a436b5074378be95468a57b62c165a1e24cfc9 + RNFlashList: b1f92e77d19aca4f9112bd977ca2ff8a2d61bf69 + RNGestureHandler: 3a73f098d74712952870e948b3d9cf7b6cae9961 RNGoogleSignin: b8f09e3ec56e09497e1e53b0ff66d5a45916c6b1 - RNImageCropPicker: f7969b3ba456deaab9ca771b457baa91088e1004 - RNKeychain: d9571527e40c1616307e6d213628b266fee8485b - RNLocalize: 3c4d0abd777a546fa77bdb6caef85a87fb9ea349 - rnmapbox-maps: e066ffa5925108bce9b965936d956fce32c1258b + RNImageCropPicker: 07691ec35bc874cf46b39d7710d82f63c9ca0817 + RNKeychain: a2c134ab796272c3d605e035ab727591000b30f3 + RNLocalize: a0ec66afe0980934cfe13f3bc30f476443388a36 + rnmapbox-maps: bc9868374cefc4778722375fcb3de859a9fff16f RNNotifee: 5e3b271e8ea7456a36eec994085543c9adca9168 - RNPermissions: 92430517fd4353d5b2b7217cd1ca48ddd2875245 + RNPermissions: 663a639fdc5aa46b853f514ae8a86dd4deb160cb RNReactNativeHapticFeedback: 7601768ee65ffc86fc93d7c30dd917031144ed3d - RNReanimated: 9282065c1fb748d2d1945ba46d6592c2cf4e5cc8 - RNScreens: 35525ebfe219c8709da0d26aebbc9a5e02e1077b - RNSentry: 5610abc54c3671db8fc807853486d9646bd806e0 - RNShare: d6b60469ede41726ec1d6eadbcc83f07ffb6efb1 - RNSVG: ad69b385e35653fd9694935c48840117e96ccc1d + RNReanimated: 196d4b56ac1d7ffa2f168d4d36631f0add849456 + RNScreens: 0bbf16c074ae6bb1058a7bf2d1ae017f4306797c + RNSentry: ab7ba8bd678713c94762d2d3f2087d47105b6cf3 + RNShare: 1dba46787d6e5543e05655efaefa0e4bb98380d9 + RNSVG: c5807de8e337c7a643f9bad2ecf48a15aefcc23c SDWebImage: 40b0b4053e36c660a764958bff99eed16610acbb SDWebImageAVIFCoder: afe194a084e851f70228e4be35ef651df0fc5c57 SDWebImageWebPCoder: e38c0a70396191361d60c092933e22c20d5b1380 @@ -4141,7 +4601,7 @@ SPEC CHECKSUMS: Specta: b79d84043684b35ffdc2680df578dc318ec2efc2 Starscream: 19b5533ddb925208db698f0ac508a100b884a1b9 Stripe: d1824162e4bcb6ead10401a0dc8e8a3d5ffee41f - stripe-react-native: 4f749e365d363c17224c422b8ca1a94bc5519171 + stripe-react-native: f2af1d3769363ae90b2a6c4bb9642232c2c4d2c9 StripeApplePay: eb64705d3c919492b1b28876652fd0aca2db38cc StripeCore: b5bee05167f0c8ccce936244a031a9972fdeade8 StripeFinancialConnections: fd6c661f86f47b1d26a32f588b3a0b09826aba84 @@ -4158,6 +4618,6 @@ SPEC CHECKSUMS: "XCTest+OHHTTPStubSuiteCleanUp": 4469ec8863c6bc022c5089a9b94233eb3416c5ee Yoga: 728df40394d49f3f471688747cf558158b3a3bd1 -PODFILE CHECKSUM: f3790c93d54682971a16b91465ae379544733d26 +PODFILE CHECKSUM: 5c033294f419df048a310e7e29058e1883cd10b5 COCOAPODS: 1.16.2 From 26fb4a78e9c62a5fc44087668d41bb3e7fce5e74 Mon Sep 17 00:00:00 2001 From: brainbicycle Date: Tue, 7 Oct 2025 14:16:34 -0400 Subject: [PATCH 005/123] convert photopicker to c++ module to fix new arch compilation error --- ios/Artsy.xcodeproj/project.pbxproj | 22 +++++++++++++++---- ...ickerModule.m => ARPHPhotoPickerModule.mm} | 0 2 files changed, 18 insertions(+), 4 deletions(-) rename ios/Artsy/Emission/EigenCommunications/{ARPHPhotoPickerModule.m => ARPHPhotoPickerModule.mm} (100%) diff --git a/ios/Artsy.xcodeproj/project.pbxproj b/ios/Artsy.xcodeproj/project.pbxproj index 02e20f284b0..1ffccb64158 100644 --- a/ios/Artsy.xcodeproj/project.pbxproj +++ b/ios/Artsy.xcodeproj/project.pbxproj @@ -14,7 +14,7 @@ 1A4B97C1283CDD5A00878EAE /* ARTemporaryAPIModule.m in Sources */ = {isa = PBXBuildFile; fileRef = 1A4B979D283CDD5900878EAE /* ARTemporaryAPIModule.m */; }; 1A4B97C3283CDD5A00878EAE /* ARMediaPreviewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 1A4B97A1283CDD5900878EAE /* ARMediaPreviewController.m */; }; 1A4B97C6283CDD5A00878EAE /* ARComponentViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 1A4B97A9283CDD5900878EAE /* ARComponentViewController.m */; }; - 1A4B97C8283CDD5A00878EAE /* ARPHPhotoPickerModule.m in Sources */ = {isa = PBXBuildFile; fileRef = 1A4B97AF283CDD5900878EAE /* ARPHPhotoPickerModule.m */; }; + 1A4B97C8283CDD5A00878EAE /* ARPHPhotoPickerModule.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1A4B97AF283CDD5900878EAE /* ARPHPhotoPickerModule.mm */; }; 1A4B97C9283CDD5A00878EAE /* ARNotificationsManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 1A4B97B0283CDD5900878EAE /* ARNotificationsManager.m */; }; 1A4E5119283F91BA0008EF35 /* Artsy+UILabels.m in Sources */ = {isa = PBXBuildFile; fileRef = 1A4E50FB283F91B90008EF35 /* Artsy+UILabels.m */; }; 1A4E511A283F91BA0008EF35 /* UIView+ARDrawing.m in Sources */ = {isa = PBXBuildFile; fileRef = 1A4E50FC283F91B90008EF35 /* UIView+ARDrawing.m */; }; @@ -555,7 +555,7 @@ 1A4B97A9283CDD5900878EAE /* ARComponentViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ARComponentViewController.m; sourceTree = ""; }; 1A4B97AC283CDD5900878EAE /* ARPHPhotoPickerModule.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ARPHPhotoPickerModule.h; sourceTree = ""; }; 1A4B97AD283CDD5900878EAE /* ARNotificationsManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ARNotificationsManager.h; sourceTree = ""; }; - 1A4B97AF283CDD5900878EAE /* ARPHPhotoPickerModule.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ARPHPhotoPickerModule.m; sourceTree = ""; }; + 1A4B97AF283CDD5900878EAE /* ARPHPhotoPickerModule.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ARPHPhotoPickerModule.mm; sourceTree = ""; }; 1A4B97B0283CDD5900878EAE /* ARNotificationsManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ARNotificationsManager.m; sourceTree = ""; }; 1A4E50FB283F91B90008EF35 /* Artsy+UILabels.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "Artsy+UILabels.m"; sourceTree = ""; }; 1A4E50FC283F91B90008EF35 /* UIView+ARDrawing.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIView+ARDrawing.m"; sourceTree = ""; }; @@ -1429,7 +1429,7 @@ children = ( 1A4B97AC283CDD5900878EAE /* ARPHPhotoPickerModule.h */, 1A4B97AD283CDD5900878EAE /* ARNotificationsManager.h */, - 1A4B97AF283CDD5900878EAE /* ARPHPhotoPickerModule.m */, + 1A4B97AF283CDD5900878EAE /* ARPHPhotoPickerModule.mm */, 1A4B97B0283CDD5900878EAE /* ARNotificationsManager.m */, ); path = EigenCommunications; @@ -3703,10 +3703,14 @@ inputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-Artsy/Pods-Artsy-frameworks-${CONFIGURATION}-input-files.xcfilelist", ); + inputPaths = ( + ); name = "[CP] Embed Pods Frameworks"; outputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-Artsy/Pods-Artsy-frameworks-${CONFIGURATION}-output-files.xcfilelist", ); + outputPaths = ( + ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Artsy/Pods-Artsy-frameworks.sh\"\n"; @@ -3720,10 +3724,14 @@ inputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-ArtsyTests/Pods-ArtsyTests-frameworks-${CONFIGURATION}-input-files.xcfilelist", ); + inputPaths = ( + ); name = "[CP] Embed Pods Frameworks"; outputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-ArtsyTests/Pods-ArtsyTests-frameworks-${CONFIGURATION}-output-files.xcfilelist", ); + outputPaths = ( + ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-ArtsyTests/Pods-ArtsyTests-frameworks.sh\"\n"; @@ -3802,10 +3810,14 @@ inputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-Artsy/Pods-Artsy-resources-${CONFIGURATION}-input-files.xcfilelist", ); + inputPaths = ( + ); name = "[CP] Copy Pods Resources"; outputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-Artsy/Pods-Artsy-resources-${CONFIGURATION}-output-files.xcfilelist", ); + outputPaths = ( + ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Artsy/Pods-Artsy-resources.sh\"\n"; @@ -3820,6 +3832,8 @@ "$(BUILT_PRODUCTS_DIR)/$(INFOPLIST_PATH)", ); name = "[CP-User] [RNFB] Core Configuration"; + outputPaths = ( + ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "#!/usr/bin/env bash\n#\n# Copyright (c) 2016-present Invertase Limited & Contributors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this library except in compliance with the License.\n# You may obtain a copy of the License at\n#\n# http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\n##########################################################################\n##########################################################################\n#\n# NOTE THAT IF YOU CHANGE THIS FILE YOU MUST RUN pod install AFTERWARDS\n#\n# This file is installed as an Xcode build script in the project file\n# by cocoapods, and you will not see your changes until you pod install\n#\n##########################################################################\n##########################################################################\n\nset -e\n\n_MAX_LOOKUPS=2;\n_SEARCH_RESULT=''\n_RN_ROOT_EXISTS=''\n_CURRENT_LOOKUPS=1\n_JSON_ROOT=\"'react-native'\"\n_JSON_FILE_NAME='firebase.json'\n_JSON_OUTPUT_BASE64='e30=' # { }\n_CURRENT_SEARCH_DIR=${PROJECT_DIR}\n_PLIST_BUDDY=/usr/libexec/PlistBuddy\n_TARGET_PLIST=\"${BUILT_PRODUCTS_DIR}/${INFOPLIST_PATH}\"\n_DSYM_PLIST=\"${DWARF_DSYM_FOLDER_PATH}/${DWARF_DSYM_FILE_NAME}/Contents/Info.plist\"\n\n# plist arrays\n_PLIST_ENTRY_KEYS=()\n_PLIST_ENTRY_TYPES=()\n_PLIST_ENTRY_VALUES=()\n\nfunction setPlistValue {\n echo \"info: setting plist entry '$1' of type '$2' in file '$4'\"\n ${_PLIST_BUDDY} -c \"Add :$1 $2 '$3'\" $4 || echo \"info: '$1' already exists\"\n}\n\nfunction getFirebaseJsonKeyValue () {\n if [[ ${_RN_ROOT_EXISTS} ]]; then\n ruby -Ku -e \"require 'rubygems';require 'json'; output=JSON.parse('$1'); puts output[$_JSON_ROOT]['$2']\"\n else\n echo \"\"\n fi;\n}\n\nfunction jsonBoolToYesNo () {\n if [[ $1 == \"false\" ]]; then\n echo \"NO\"\n elif [[ $1 == \"true\" ]]; then\n echo \"YES\"\n else echo \"NO\"\n fi\n}\n\necho \"info: -> RNFB build script started\"\necho \"info: 1) Locating ${_JSON_FILE_NAME} file:\"\n\nif [[ -z ${_CURRENT_SEARCH_DIR} ]]; then\n _CURRENT_SEARCH_DIR=$(pwd)\nfi;\n\nwhile true; do\n _CURRENT_SEARCH_DIR=$(dirname \"$_CURRENT_SEARCH_DIR\")\n if [[ \"$_CURRENT_SEARCH_DIR\" == \"/\" ]] || [[ ${_CURRENT_LOOKUPS} -gt ${_MAX_LOOKUPS} ]]; then break; fi;\n echo \"info: ($_CURRENT_LOOKUPS of $_MAX_LOOKUPS) Searching in '$_CURRENT_SEARCH_DIR' for a ${_JSON_FILE_NAME} file.\"\n _SEARCH_RESULT=$(find \"$_CURRENT_SEARCH_DIR\" -maxdepth 2 -name ${_JSON_FILE_NAME} -print | /usr/bin/head -n 1)\n if [[ ${_SEARCH_RESULT} ]]; then\n echo \"info: ${_JSON_FILE_NAME} found at $_SEARCH_RESULT\"\n break;\n fi;\n _CURRENT_LOOKUPS=$((_CURRENT_LOOKUPS+1))\ndone\n\nif [[ ${_SEARCH_RESULT} ]]; then\n _JSON_OUTPUT_RAW=$(cat \"${_SEARCH_RESULT}\")\n if ! _RN_ROOT_EXISTS=$(ruby -Ku -e \"require 'json'; output=JSON.parse('$_JSON_OUTPUT_RAW'); puts output[$_JSON_ROOT]\"); then\n echo \"error: Failed to parse firebase.json, check for syntax errors.\"\n exit 1\n fi\n\n if [[ ${_RN_ROOT_EXISTS} ]]; then\n if ! python3 --version >/dev/null 2>&1; then echo \"python3 not found, firebase.json file processing error.\" && exit 1; fi\n _JSON_OUTPUT_BASE64=$(python3 -c 'import json,sys,base64;print(base64.b64encode(bytes(json.dumps(json.loads(open('\"'${_SEARCH_RESULT}'\"', '\"'rb'\"').read())['${_JSON_ROOT}']), '\"'utf-8'\"')).decode())' || echo \"e30=\")\n fi\n\n _PLIST_ENTRY_KEYS+=(\"firebase_json_raw\")\n _PLIST_ENTRY_TYPES+=(\"string\")\n _PLIST_ENTRY_VALUES+=(\"$_JSON_OUTPUT_BASE64\")\n\n # config.app_data_collection_default_enabled\n _APP_DATA_COLLECTION_ENABLED=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"app_data_collection_default_enabled\")\n if [[ $_APP_DATA_COLLECTION_ENABLED ]]; then\n _PLIST_ENTRY_KEYS+=(\"FirebaseDataCollectionDefaultEnabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_APP_DATA_COLLECTION_ENABLED\")\")\n fi\n\n # config.analytics_auto_collection_enabled\n _ANALYTICS_AUTO_COLLECTION=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"analytics_auto_collection_enabled\")\n if [[ $_ANALYTICS_AUTO_COLLECTION ]]; then\n _PLIST_ENTRY_KEYS+=(\"FIREBASE_ANALYTICS_COLLECTION_ENABLED\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_ANALYTICS_AUTO_COLLECTION\")\")\n fi\n\n # config.analytics_collection_deactivated\n _ANALYTICS_DEACTIVATED=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"analytics_collection_deactivated\")\n if [[ $_ANALYTICS_DEACTIVATED ]]; then\n _PLIST_ENTRY_KEYS+=(\"FIREBASE_ANALYTICS_COLLECTION_DEACTIVATED\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_ANALYTICS_DEACTIVATED\")\")\n fi\n\n # config.analytics_idfv_collection_enabled\n _ANALYTICS_IDFV_COLLECTION=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"analytics_idfv_collection_enabled\")\n if [[ $_ANALYTICS_IDFV_COLLECTION ]]; then\n _PLIST_ENTRY_KEYS+=(\"GOOGLE_ANALYTICS_IDFV_COLLECTION_ENABLED\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_ANALYTICS_IDFV_COLLECTION\")\")\n fi\n\n # config.analytics_default_allow_analytics_storage\n _ANALYTICS_STORAGE=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"analytics_default_allow_analytics_storage\")\n if [[ $_ANALYTICS_STORAGE ]]; then\n _PLIST_ENTRY_KEYS+=(\"GOOGLE_ANALYTICS_DEFAULT_ALLOW_ANALYTICS_STORAGE\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_ANALYTICS_STORAGE\")\")\n fi\n\n # config.analytics_default_allow_ad_storage\n _ANALYTICS_AD_STORAGE=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"analytics_default_allow_ad_storage\")\n if [[ $_ANALYTICS_AD_STORAGE ]]; then\n _PLIST_ENTRY_KEYS+=(\"GOOGLE_ANALYTICS_DEFAULT_ALLOW_AD_STORAGE\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_ANALYTICS_AD_STORAGE\")\")\n fi\n\n # config.analytics_default_allow_ad_user_data\n _ANALYTICS_AD_USER_DATA=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"analytics_default_allow_ad_user_data\")\n if [[ $_ANALYTICS_AD_USER_DATA ]]; then\n _PLIST_ENTRY_KEYS+=(\"GOOGLE_ANALYTICS_DEFAULT_ALLOW_AD_USER_DATA\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_ANALYTICS_AD_USER_DATA\")\")\n fi\n\n # config.analytics_default_allow_ad_personalization_signals\n _ANALYTICS_PERSONALIZATION=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"analytics_default_allow_ad_personalization_signals\")\n if [[ $_ANALYTICS_PERSONALIZATION ]]; then\n _PLIST_ENTRY_KEYS+=(\"GOOGLE_ANALYTICS_DEFAULT_ALLOW_AD_PERSONALIZATION_SIGNALS\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_ANALYTICS_PERSONALIZATION\")\")\n fi\n\n # config.analytics_registration_with_ad_network_enabled\n _ANALYTICS_REGISTRATION_WITH_AD_NETWORK=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"google_analytics_registration_with_ad_network_enabled\")\n if [[ $_ANALYTICS_REGISTRATION_WITH_AD_NETWORK ]]; then\n _PLIST_ENTRY_KEYS+=(\"GOOGLE_ANALYTICS_REGISTRATION_WITH_AD_NETWORK_ENABLED\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_ANALYTICS_REGISTRATION_WITH_AD_NETWORK\")\")\n fi\n\n # config.google_analytics_automatic_screen_reporting_enabled\n _ANALYTICS_AUTO_SCREEN_REPORTING=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"google_analytics_automatic_screen_reporting_enabled\")\n if [[ $_ANALYTICS_AUTO_SCREEN_REPORTING ]]; then\n _PLIST_ENTRY_KEYS+=(\"FirebaseAutomaticScreenReportingEnabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_ANALYTICS_AUTO_SCREEN_REPORTING\")\")\n fi\n\n # config.perf_auto_collection_enabled\n _PERF_AUTO_COLLECTION=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"perf_auto_collection_enabled\")\n if [[ $_PERF_AUTO_COLLECTION ]]; then\n _PLIST_ENTRY_KEYS+=(\"firebase_performance_collection_enabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_PERF_AUTO_COLLECTION\")\")\n fi\n\n # config.perf_collection_deactivated\n _PERF_DEACTIVATED=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"perf_collection_deactivated\")\n if [[ $_PERF_DEACTIVATED ]]; then\n _PLIST_ENTRY_KEYS+=(\"firebase_performance_collection_deactivated\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_PERF_DEACTIVATED\")\")\n fi\n\n # config.messaging_auto_init_enabled\n _MESSAGING_AUTO_INIT=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"messaging_auto_init_enabled\")\n if [[ $_MESSAGING_AUTO_INIT ]]; then\n _PLIST_ENTRY_KEYS+=(\"FirebaseMessagingAutoInitEnabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_MESSAGING_AUTO_INIT\")\")\n fi\n\n # config.in_app_messaging_auto_colllection_enabled\n _FIAM_AUTO_INIT=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"in_app_messaging_auto_collection_enabled\")\n if [[ $_FIAM_AUTO_INIT ]]; then\n _PLIST_ENTRY_KEYS+=(\"FirebaseInAppMessagingAutomaticDataCollectionEnabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_FIAM_AUTO_INIT\")\")\n fi\n\n # config.app_check_token_auto_refresh\n _APP_CHECK_TOKEN_AUTO_REFRESH=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"app_check_token_auto_refresh\")\n if [[ $_APP_CHECK_TOKEN_AUTO_REFRESH ]]; then\n _PLIST_ENTRY_KEYS+=(\"FirebaseAppCheckTokenAutoRefreshEnabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_APP_CHECK_TOKEN_AUTO_REFRESH\")\")\n fi\n\n # config.crashlytics_disable_auto_disabler - undocumented for now - mainly for debugging, document if becomes useful\n _CRASHLYTICS_AUTO_DISABLE_ENABLED=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"crashlytics_disable_auto_disabler\")\n if [[ $_CRASHLYTICS_AUTO_DISABLE_ENABLED == \"true\" ]]; then\n echo \"Disabled Crashlytics auto disabler.\" # do nothing\n else\n _PLIST_ENTRY_KEYS+=(\"FirebaseCrashlyticsCollectionEnabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"NO\")\n fi\nelse\n _PLIST_ENTRY_KEYS+=(\"firebase_json_raw\")\n _PLIST_ENTRY_TYPES+=(\"string\")\n _PLIST_ENTRY_VALUES+=(\"$_JSON_OUTPUT_BASE64\")\n echo \"warning: A firebase.json file was not found, whilst this file is optional it is recommended to include it to configure firebase services in React Native Firebase.\"\nfi;\n\necho \"info: 2) Injecting Info.plist entries: \"\n\n# Log out the keys we're adding\nfor i in \"${!_PLIST_ENTRY_KEYS[@]}\"; do\n echo \" -> $i) ${_PLIST_ENTRY_KEYS[$i]}\" \"${_PLIST_ENTRY_TYPES[$i]}\" \"${_PLIST_ENTRY_VALUES[$i]}\"\ndone\n\nfor plist in \"${_TARGET_PLIST}\" \"${_DSYM_PLIST}\" ; do\n if [[ -f \"${plist}\" ]]; then\n\n # paths with spaces break the call to setPlistValue. temporarily modify\n # the shell internal field separator variable (IFS), which normally\n # includes spaces, to consist only of line breaks\n oldifs=$IFS\n IFS=\"\n\"\n\n for i in \"${!_PLIST_ENTRY_KEYS[@]}\"; do\n setPlistValue \"${_PLIST_ENTRY_KEYS[$i]}\" \"${_PLIST_ENTRY_TYPES[$i]}\" \"${_PLIST_ENTRY_VALUES[$i]}\" \"${plist}\"\n done\n\n # restore the original internal field separator value\n IFS=$oldifs\n else\n echo \"warning: A Info.plist build output file was not found (${plist})\"\n fi\ndone\n\necho \"info: <- RNFB build script finished\"\n"; @@ -3892,7 +3906,7 @@ CBD794D72BBB5622003B3CB5 /* StarscreamExtensions.swift in Sources */, CBE326AF27E275A300395A93 /* LiveAuctionLoadingView.swift in Sources */, CBE326E127E275A300395A93 /* ARFileUtils.m in Sources */, - 1A4B97C8283CDD5A00878EAE /* ARPHPhotoPickerModule.m in Sources */, + 1A4B97C8283CDD5A00878EAE /* ARPHPhotoPickerModule.mm in Sources */, CBE3269727E275A300395A93 /* AppDelegate+ShortcutItems.m in Sources */, CBE326E627E275A300395A93 /* UIApplicationStateEnum.m in Sources */, CBE3270E27E275A300395A93 /* AuctionTitleView.swift in Sources */, diff --git a/ios/Artsy/Emission/EigenCommunications/ARPHPhotoPickerModule.m b/ios/Artsy/Emission/EigenCommunications/ARPHPhotoPickerModule.mm similarity index 100% rename from ios/Artsy/Emission/EigenCommunications/ARPHPhotoPickerModule.m rename to ios/Artsy/Emission/EigenCommunications/ARPHPhotoPickerModule.mm From 65d10223bd96ca569dd406d7009504a858737d02 Mon Sep 17 00:00:00 2001 From: brainbicycle Date: Tue, 7 Oct 2025 14:32:46 -0400 Subject: [PATCH 006/123] convert helper to C++ and add needed imports to fix compilation issue --- ios/Artsy.xcodeproj/project.pbxproj | 8 ++++---- .../{ARAppDelegateHelper.m => ARAppDelegateHelper.mm} | 9 ++++++++- 2 files changed, 12 insertions(+), 5 deletions(-) rename ios/Artsy/App/{ARAppDelegateHelper.m => ARAppDelegateHelper.mm} (96%) diff --git a/ios/Artsy.xcodeproj/project.pbxproj b/ios/Artsy.xcodeproj/project.pbxproj index 1ffccb64158..51a7a7b5d3f 100644 --- a/ios/Artsy.xcodeproj/project.pbxproj +++ b/ios/Artsy.xcodeproj/project.pbxproj @@ -216,7 +216,7 @@ CB762B3E2911A5E100881194 /* ar_vir_opening_frame.jpg in Resources */ = {isa = PBXBuildFile; fileRef = CB762B362911A5E100881194 /* ar_vir_opening_frame.jpg */; }; CBA500F32C654F8400DDBCC0 /* AppDelegate+DeeplinkTimeout.m in Sources */ = {isa = PBXBuildFile; fileRef = CBA500F22C654F8400DDBCC0 /* AppDelegate+DeeplinkTimeout.m */; }; CBA500F62C6553FF00DDBCC0 /* ARTDeeplinkTimeoutModule.m in Sources */ = {isa = PBXBuildFile; fileRef = CBA500F52C6553FF00DDBCC0 /* ARTDeeplinkTimeoutModule.m */; }; - CBC1F3F12E68CF11008CCF48 /* ARAppDelegateHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = CBC1F3F02E68CF11008CCF48 /* ARAppDelegateHelper.m */; }; + CBC1F3F12E68CF11008CCF48 /* ARAppDelegateHelper.mm in Sources */ = {isa = PBXBuildFile; fileRef = CBC1F3F02E68CF11008CCF48 /* ARAppDelegateHelper.mm */; }; CBC1F3F42E68D0D7008CCF48 /* ARWindow.m in Sources */ = {isa = PBXBuildFile; fileRef = CBC1F3F32E68D0D4008CCF48 /* ARWindow.m */; }; CBD794D72BBB5622003B3CB5 /* StarscreamExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = CBD794D62BBB5622003B3CB5 /* StarscreamExtensions.swift */; }; CBD794DB2BBC40A4003B3CB5 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = CBD794DA2BBC40A4003B3CB5 /* PrivacyInfo.xcprivacy */; }; @@ -916,7 +916,7 @@ CBA500F52C6553FF00DDBCC0 /* ARTDeeplinkTimeoutModule.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ARTDeeplinkTimeoutModule.m; sourceTree = ""; }; CBA7CF22282BF6310025AEA5 /* Artsy_Tests-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "Artsy_Tests-Info.plist"; sourceTree = ""; }; CBC1F3EF2E68CF11008CCF48 /* ARAppDelegateHelper.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ARAppDelegateHelper.h; sourceTree = ""; }; - CBC1F3F02E68CF11008CCF48 /* ARAppDelegateHelper.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ARAppDelegateHelper.m; sourceTree = ""; }; + CBC1F3F02E68CF11008CCF48 /* ARAppDelegateHelper.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = ARAppDelegateHelper.mm; sourceTree = ""; }; CBC1F3F22E68D0CC008CCF48 /* ARWindow.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ARWindow.h; sourceTree = ""; }; CBC1F3F32E68D0D4008CCF48 /* ARWindow.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ARWindow.m; sourceTree = ""; }; CBD794D62BBB5622003B3CB5 /* StarscreamExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StarscreamExtensions.swift; sourceTree = ""; }; @@ -2543,7 +2543,7 @@ CBC1F3F22E68D0CC008CCF48 /* ARWindow.h */, CBC1F3F32E68D0D4008CCF48 /* ARWindow.m */, CBC1F3EF2E68CF11008CCF48 /* ARAppDelegateHelper.h */, - CBC1F3F02E68CF11008CCF48 /* ARAppDelegateHelper.m */, + CBC1F3F02E68CF11008CCF48 /* ARAppDelegateHelper.mm */, CB2033332E56593700A06281 /* main.swift */, CB51280D2DB2EBCE00C6A884 /* AppDelegateCategories */, CBE3249927E275A100395A93 /* ARTArtsyNativeModule.h */, @@ -3958,7 +3958,7 @@ CBE3267727E275A300395A93 /* UIImageView+AsyncImageLoading.m in Sources */, CB18284829DF3F75006A0805 /* Utilities.swift in Sources */, CBE3271D27E275A300395A93 /* ARNotificationView.m in Sources */, - CBC1F3F12E68CF11008CCF48 /* ARAppDelegateHelper.m in Sources */, + CBC1F3F12E68CF11008CCF48 /* ARAppDelegateHelper.mm in Sources */, CBE3276C27E275A400395A93 /* MTLModel+Dictionary.m in Sources */, CBE326E427E275A300395A93 /* ARNetworkErrorManager.m in Sources */, CBE326A027E275A300395A93 /* ARUserActivity.m in Sources */, diff --git a/ios/Artsy/App/ARAppDelegateHelper.m b/ios/Artsy/App/ARAppDelegateHelper.mm similarity index 96% rename from ios/Artsy/App/ARAppDelegateHelper.m rename to ios/Artsy/App/ARAppDelegateHelper.mm index f1f473b9d73..71cb5ec91e5 100644 --- a/ios/Artsy/App/ARAppDelegateHelper.m +++ b/ios/Artsy/App/ARAppDelegateHelper.mm @@ -10,12 +10,19 @@ #import "ARUserManager.h" #import "Keys.h" #import "ARAppStatus.h" -#import + + +#import +#import +#import + + #import #import "BrazeReactBridge.h" #import "BrazeReactUtils.h" #import + @interface ARAppDelegateHelper () @property (strong, nonatomic, readwrite) NSString *referralURLRepresentation; @property (strong, nonatomic, readwrite) NSString *landingURLRepresentation; From fd576ec56e839e2e2c7bc6c5c1785264a574c606 Mon Sep 17 00:00:00 2001 From: brainbicycle Date: Tue, 7 Oct 2025 14:59:10 -0400 Subject: [PATCH 007/123] point to fixed version of context menu --- ios/Artsy.xcodeproj/project.pbxproj | 14 -------------- ios/Podfile.lock | 4 ++-- package.json | 2 +- yarn.lock | 10 +++++----- 4 files changed, 8 insertions(+), 22 deletions(-) diff --git a/ios/Artsy.xcodeproj/project.pbxproj b/ios/Artsy.xcodeproj/project.pbxproj index 51a7a7b5d3f..68b167e4b62 100644 --- a/ios/Artsy.xcodeproj/project.pbxproj +++ b/ios/Artsy.xcodeproj/project.pbxproj @@ -3703,14 +3703,10 @@ inputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-Artsy/Pods-Artsy-frameworks-${CONFIGURATION}-input-files.xcfilelist", ); - inputPaths = ( - ); name = "[CP] Embed Pods Frameworks"; outputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-Artsy/Pods-Artsy-frameworks-${CONFIGURATION}-output-files.xcfilelist", ); - outputPaths = ( - ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Artsy/Pods-Artsy-frameworks.sh\"\n"; @@ -3724,14 +3720,10 @@ inputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-ArtsyTests/Pods-ArtsyTests-frameworks-${CONFIGURATION}-input-files.xcfilelist", ); - inputPaths = ( - ); name = "[CP] Embed Pods Frameworks"; outputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-ArtsyTests/Pods-ArtsyTests-frameworks-${CONFIGURATION}-output-files.xcfilelist", ); - outputPaths = ( - ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-ArtsyTests/Pods-ArtsyTests-frameworks.sh\"\n"; @@ -3810,14 +3802,10 @@ inputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-Artsy/Pods-Artsy-resources-${CONFIGURATION}-input-files.xcfilelist", ); - inputPaths = ( - ); name = "[CP] Copy Pods Resources"; outputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-Artsy/Pods-Artsy-resources-${CONFIGURATION}-output-files.xcfilelist", ); - outputPaths = ( - ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Artsy/Pods-Artsy-resources.sh\"\n"; @@ -3832,8 +3820,6 @@ "$(BUILT_PRODUCTS_DIR)/$(INFOPLIST_PATH)", ); name = "[CP-User] [RNFB] Core Configuration"; - outputPaths = ( - ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "#!/usr/bin/env bash\n#\n# Copyright (c) 2016-present Invertase Limited & Contributors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this library except in compliance with the License.\n# You may obtain a copy of the License at\n#\n# http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\n##########################################################################\n##########################################################################\n#\n# NOTE THAT IF YOU CHANGE THIS FILE YOU MUST RUN pod install AFTERWARDS\n#\n# This file is installed as an Xcode build script in the project file\n# by cocoapods, and you will not see your changes until you pod install\n#\n##########################################################################\n##########################################################################\n\nset -e\n\n_MAX_LOOKUPS=2;\n_SEARCH_RESULT=''\n_RN_ROOT_EXISTS=''\n_CURRENT_LOOKUPS=1\n_JSON_ROOT=\"'react-native'\"\n_JSON_FILE_NAME='firebase.json'\n_JSON_OUTPUT_BASE64='e30=' # { }\n_CURRENT_SEARCH_DIR=${PROJECT_DIR}\n_PLIST_BUDDY=/usr/libexec/PlistBuddy\n_TARGET_PLIST=\"${BUILT_PRODUCTS_DIR}/${INFOPLIST_PATH}\"\n_DSYM_PLIST=\"${DWARF_DSYM_FOLDER_PATH}/${DWARF_DSYM_FILE_NAME}/Contents/Info.plist\"\n\n# plist arrays\n_PLIST_ENTRY_KEYS=()\n_PLIST_ENTRY_TYPES=()\n_PLIST_ENTRY_VALUES=()\n\nfunction setPlistValue {\n echo \"info: setting plist entry '$1' of type '$2' in file '$4'\"\n ${_PLIST_BUDDY} -c \"Add :$1 $2 '$3'\" $4 || echo \"info: '$1' already exists\"\n}\n\nfunction getFirebaseJsonKeyValue () {\n if [[ ${_RN_ROOT_EXISTS} ]]; then\n ruby -Ku -e \"require 'rubygems';require 'json'; output=JSON.parse('$1'); puts output[$_JSON_ROOT]['$2']\"\n else\n echo \"\"\n fi;\n}\n\nfunction jsonBoolToYesNo () {\n if [[ $1 == \"false\" ]]; then\n echo \"NO\"\n elif [[ $1 == \"true\" ]]; then\n echo \"YES\"\n else echo \"NO\"\n fi\n}\n\necho \"info: -> RNFB build script started\"\necho \"info: 1) Locating ${_JSON_FILE_NAME} file:\"\n\nif [[ -z ${_CURRENT_SEARCH_DIR} ]]; then\n _CURRENT_SEARCH_DIR=$(pwd)\nfi;\n\nwhile true; do\n _CURRENT_SEARCH_DIR=$(dirname \"$_CURRENT_SEARCH_DIR\")\n if [[ \"$_CURRENT_SEARCH_DIR\" == \"/\" ]] || [[ ${_CURRENT_LOOKUPS} -gt ${_MAX_LOOKUPS} ]]; then break; fi;\n echo \"info: ($_CURRENT_LOOKUPS of $_MAX_LOOKUPS) Searching in '$_CURRENT_SEARCH_DIR' for a ${_JSON_FILE_NAME} file.\"\n _SEARCH_RESULT=$(find \"$_CURRENT_SEARCH_DIR\" -maxdepth 2 -name ${_JSON_FILE_NAME} -print | /usr/bin/head -n 1)\n if [[ ${_SEARCH_RESULT} ]]; then\n echo \"info: ${_JSON_FILE_NAME} found at $_SEARCH_RESULT\"\n break;\n fi;\n _CURRENT_LOOKUPS=$((_CURRENT_LOOKUPS+1))\ndone\n\nif [[ ${_SEARCH_RESULT} ]]; then\n _JSON_OUTPUT_RAW=$(cat \"${_SEARCH_RESULT}\")\n if ! _RN_ROOT_EXISTS=$(ruby -Ku -e \"require 'json'; output=JSON.parse('$_JSON_OUTPUT_RAW'); puts output[$_JSON_ROOT]\"); then\n echo \"error: Failed to parse firebase.json, check for syntax errors.\"\n exit 1\n fi\n\n if [[ ${_RN_ROOT_EXISTS} ]]; then\n if ! python3 --version >/dev/null 2>&1; then echo \"python3 not found, firebase.json file processing error.\" && exit 1; fi\n _JSON_OUTPUT_BASE64=$(python3 -c 'import json,sys,base64;print(base64.b64encode(bytes(json.dumps(json.loads(open('\"'${_SEARCH_RESULT}'\"', '\"'rb'\"').read())['${_JSON_ROOT}']), '\"'utf-8'\"')).decode())' || echo \"e30=\")\n fi\n\n _PLIST_ENTRY_KEYS+=(\"firebase_json_raw\")\n _PLIST_ENTRY_TYPES+=(\"string\")\n _PLIST_ENTRY_VALUES+=(\"$_JSON_OUTPUT_BASE64\")\n\n # config.app_data_collection_default_enabled\n _APP_DATA_COLLECTION_ENABLED=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"app_data_collection_default_enabled\")\n if [[ $_APP_DATA_COLLECTION_ENABLED ]]; then\n _PLIST_ENTRY_KEYS+=(\"FirebaseDataCollectionDefaultEnabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_APP_DATA_COLLECTION_ENABLED\")\")\n fi\n\n # config.analytics_auto_collection_enabled\n _ANALYTICS_AUTO_COLLECTION=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"analytics_auto_collection_enabled\")\n if [[ $_ANALYTICS_AUTO_COLLECTION ]]; then\n _PLIST_ENTRY_KEYS+=(\"FIREBASE_ANALYTICS_COLLECTION_ENABLED\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_ANALYTICS_AUTO_COLLECTION\")\")\n fi\n\n # config.analytics_collection_deactivated\n _ANALYTICS_DEACTIVATED=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"analytics_collection_deactivated\")\n if [[ $_ANALYTICS_DEACTIVATED ]]; then\n _PLIST_ENTRY_KEYS+=(\"FIREBASE_ANALYTICS_COLLECTION_DEACTIVATED\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_ANALYTICS_DEACTIVATED\")\")\n fi\n\n # config.analytics_idfv_collection_enabled\n _ANALYTICS_IDFV_COLLECTION=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"analytics_idfv_collection_enabled\")\n if [[ $_ANALYTICS_IDFV_COLLECTION ]]; then\n _PLIST_ENTRY_KEYS+=(\"GOOGLE_ANALYTICS_IDFV_COLLECTION_ENABLED\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_ANALYTICS_IDFV_COLLECTION\")\")\n fi\n\n # config.analytics_default_allow_analytics_storage\n _ANALYTICS_STORAGE=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"analytics_default_allow_analytics_storage\")\n if [[ $_ANALYTICS_STORAGE ]]; then\n _PLIST_ENTRY_KEYS+=(\"GOOGLE_ANALYTICS_DEFAULT_ALLOW_ANALYTICS_STORAGE\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_ANALYTICS_STORAGE\")\")\n fi\n\n # config.analytics_default_allow_ad_storage\n _ANALYTICS_AD_STORAGE=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"analytics_default_allow_ad_storage\")\n if [[ $_ANALYTICS_AD_STORAGE ]]; then\n _PLIST_ENTRY_KEYS+=(\"GOOGLE_ANALYTICS_DEFAULT_ALLOW_AD_STORAGE\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_ANALYTICS_AD_STORAGE\")\")\n fi\n\n # config.analytics_default_allow_ad_user_data\n _ANALYTICS_AD_USER_DATA=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"analytics_default_allow_ad_user_data\")\n if [[ $_ANALYTICS_AD_USER_DATA ]]; then\n _PLIST_ENTRY_KEYS+=(\"GOOGLE_ANALYTICS_DEFAULT_ALLOW_AD_USER_DATA\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_ANALYTICS_AD_USER_DATA\")\")\n fi\n\n # config.analytics_default_allow_ad_personalization_signals\n _ANALYTICS_PERSONALIZATION=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"analytics_default_allow_ad_personalization_signals\")\n if [[ $_ANALYTICS_PERSONALIZATION ]]; then\n _PLIST_ENTRY_KEYS+=(\"GOOGLE_ANALYTICS_DEFAULT_ALLOW_AD_PERSONALIZATION_SIGNALS\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_ANALYTICS_PERSONALIZATION\")\")\n fi\n\n # config.analytics_registration_with_ad_network_enabled\n _ANALYTICS_REGISTRATION_WITH_AD_NETWORK=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"google_analytics_registration_with_ad_network_enabled\")\n if [[ $_ANALYTICS_REGISTRATION_WITH_AD_NETWORK ]]; then\n _PLIST_ENTRY_KEYS+=(\"GOOGLE_ANALYTICS_REGISTRATION_WITH_AD_NETWORK_ENABLED\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_ANALYTICS_REGISTRATION_WITH_AD_NETWORK\")\")\n fi\n\n # config.google_analytics_automatic_screen_reporting_enabled\n _ANALYTICS_AUTO_SCREEN_REPORTING=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"google_analytics_automatic_screen_reporting_enabled\")\n if [[ $_ANALYTICS_AUTO_SCREEN_REPORTING ]]; then\n _PLIST_ENTRY_KEYS+=(\"FirebaseAutomaticScreenReportingEnabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_ANALYTICS_AUTO_SCREEN_REPORTING\")\")\n fi\n\n # config.perf_auto_collection_enabled\n _PERF_AUTO_COLLECTION=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"perf_auto_collection_enabled\")\n if [[ $_PERF_AUTO_COLLECTION ]]; then\n _PLIST_ENTRY_KEYS+=(\"firebase_performance_collection_enabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_PERF_AUTO_COLLECTION\")\")\n fi\n\n # config.perf_collection_deactivated\n _PERF_DEACTIVATED=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"perf_collection_deactivated\")\n if [[ $_PERF_DEACTIVATED ]]; then\n _PLIST_ENTRY_KEYS+=(\"firebase_performance_collection_deactivated\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_PERF_DEACTIVATED\")\")\n fi\n\n # config.messaging_auto_init_enabled\n _MESSAGING_AUTO_INIT=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"messaging_auto_init_enabled\")\n if [[ $_MESSAGING_AUTO_INIT ]]; then\n _PLIST_ENTRY_KEYS+=(\"FirebaseMessagingAutoInitEnabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_MESSAGING_AUTO_INIT\")\")\n fi\n\n # config.in_app_messaging_auto_colllection_enabled\n _FIAM_AUTO_INIT=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"in_app_messaging_auto_collection_enabled\")\n if [[ $_FIAM_AUTO_INIT ]]; then\n _PLIST_ENTRY_KEYS+=(\"FirebaseInAppMessagingAutomaticDataCollectionEnabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_FIAM_AUTO_INIT\")\")\n fi\n\n # config.app_check_token_auto_refresh\n _APP_CHECK_TOKEN_AUTO_REFRESH=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"app_check_token_auto_refresh\")\n if [[ $_APP_CHECK_TOKEN_AUTO_REFRESH ]]; then\n _PLIST_ENTRY_KEYS+=(\"FirebaseAppCheckTokenAutoRefreshEnabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_APP_CHECK_TOKEN_AUTO_REFRESH\")\")\n fi\n\n # config.crashlytics_disable_auto_disabler - undocumented for now - mainly for debugging, document if becomes useful\n _CRASHLYTICS_AUTO_DISABLE_ENABLED=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"crashlytics_disable_auto_disabler\")\n if [[ $_CRASHLYTICS_AUTO_DISABLE_ENABLED == \"true\" ]]; then\n echo \"Disabled Crashlytics auto disabler.\" # do nothing\n else\n _PLIST_ENTRY_KEYS+=(\"FirebaseCrashlyticsCollectionEnabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"NO\")\n fi\nelse\n _PLIST_ENTRY_KEYS+=(\"firebase_json_raw\")\n _PLIST_ENTRY_TYPES+=(\"string\")\n _PLIST_ENTRY_VALUES+=(\"$_JSON_OUTPUT_BASE64\")\n echo \"warning: A firebase.json file was not found, whilst this file is optional it is recommended to include it to configure firebase services in React Native Firebase.\"\nfi;\n\necho \"info: 2) Injecting Info.plist entries: \"\n\n# Log out the keys we're adding\nfor i in \"${!_PLIST_ENTRY_KEYS[@]}\"; do\n echo \" -> $i) ${_PLIST_ENTRY_KEYS[$i]}\" \"${_PLIST_ENTRY_TYPES[$i]}\" \"${_PLIST_ENTRY_VALUES[$i]}\"\ndone\n\nfor plist in \"${_TARGET_PLIST}\" \"${_DSYM_PLIST}\" ; do\n if [[ -f \"${plist}\" ]]; then\n\n # paths with spaces break the call to setPlistValue. temporarily modify\n # the shell internal field separator variable (IFS), which normally\n # includes spaces, to consist only of line breaks\n oldifs=$IFS\n IFS=\"\n\"\n\n for i in \"${!_PLIST_ENTRY_KEYS[@]}\"; do\n setPlistValue \"${_PLIST_ENTRY_KEYS[$i]}\" \"${_PLIST_ENTRY_TYPES[$i]}\" \"${_PLIST_ENTRY_VALUES[$i]}\" \"${plist}\"\n done\n\n # restore the original internal field separator value\n IFS=$oldifs\n else\n echo \"warning: A Info.plist build output file was not found (${plist})\"\n fi\ndone\n\necho \"info: <- RNFB build script finished\"\n"; diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 0b5531da374..046baf84167 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -2163,7 +2163,7 @@ PODS: - ReactCommon/turbomodule/core - SocketRocket - Yoga - - react-native-context-menu-view (1.10.0): + - react-native-context-menu-view (1.11.0): - React - react-native-cookies (6.0.11): - React-Core @@ -4519,7 +4519,7 @@ SPEC CHECKSUMS: React-microtasksnativemodule: 6c4ee39a36958c39c97b074d28f360246a335e84 react-native-blob-util: 10c78778354e6c92b7a5afa4a1027cf0f18a9bb9 react-native-blurhash: c1721deafe7a685088ea14ab4712a1c460be9fe4 - react-native-context-menu-view: 74fbcf8a5f842c4802d0121addda2f8ffca43604 + react-native-context-menu-view: dc362920c823ef1021e9a9ccd09d2e29c526852f react-native-cookies: b90327af903c8a7652100201d890c50a98697799 react-native-document-picker: f26f09a90cce65b5d682f21b511e8eb09a506fdc react-native-fbsdk-next: 52f81e60eb3e8e0e06cf9728b4572d3509ca9d01 diff --git a/package.json b/package.json index 3a245ef36b0..cd3015f60da 100644 --- a/package.json +++ b/package.json @@ -168,7 +168,7 @@ "react-native-blurhash": "2.1.1", "react-native-bootsplash": "6.3.10", "react-native-collapsible-tab-view": "8.0.1", - "react-native-context-menu-view": "git+https://github.com/artsy/react-native-context-menu-view.git#v1.10.10-artsy", + "react-native-context-menu-view": "git+https://github.com/artsy/react-native-context-menu-view.git#brian/new-arch-woes", "react-native-device-info": "14.0.0", "react-native-fbsdk-next": "13.4.1", "react-native-gesture-handler": "2.28.0", diff --git a/yarn.lock b/yarn.lock index 02b32e3b7e2..7200868f17c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -12729,7 +12729,7 @@ __metadata: react-native-blurhash: "npm:2.1.1" react-native-bootsplash: "npm:6.3.10" react-native-collapsible-tab-view: "npm:8.0.1" - react-native-context-menu-view: "git+https://github.com/artsy/react-native-context-menu-view.git#v1.10.10-artsy" + react-native-context-menu-view: "git+https://github.com/artsy/react-native-context-menu-view.git#brian/new-arch-woes" react-native-device-info: "npm:14.0.0" react-native-fbsdk-next: "npm:13.4.1" react-native-gesture-handler: "npm:2.28.0" @@ -21497,13 +21497,13 @@ __metadata: languageName: node linkType: hard -"react-native-context-menu-view@git+https://github.com/artsy/react-native-context-menu-view.git#v1.10.10-artsy": - version: 1.10.0 - resolution: "react-native-context-menu-view@https://github.com/artsy/react-native-context-menu-view.git#commit=e5a6bf3abba774936cac9ae2988704f0d7443c14" +"react-native-context-menu-view@git+https://github.com/artsy/react-native-context-menu-view.git#brian/new-arch-woes": + version: 1.11.0 + resolution: "react-native-context-menu-view@https://github.com/artsy/react-native-context-menu-view.git#commit=8332543bf6534660d0781fa6b0d085b8d42aefc9" peerDependencies: react: ^16.8.1 || ^17.0.0 || ^18.0.0 react-native: ">=0.60.0-rc.0 <1.0.x" - checksum: 10c0/d583a3508d9b35754ffddb5a971cf138f04cb3737ae9020a52b3b5a2552e9e2f35ff18491a5851202e211340c34dcffaeef31f2afe974481cb8d82f76d2cbb2e + checksum: 10c0/2acd060207d08bcf1e57aeb3639a85c507c97da4b1ee7f37d73b4a51124e314a13534819e1b693c9ea0b5a3bd0d468dd1702b80691a1632a91baf6689ac9c8b7 languageName: node linkType: hard From 9924ef68375444efbc709bfa474b6df3265d8f36 Mon Sep 17 00:00:00 2001 From: Mounir Dhahri Date: Fri, 14 Nov 2025 10:04:12 +0100 Subject: [PATCH 008/123] chore: upgrade flashlist to v2 --- docs/best_practices.md | 1 - ios/Podfile.lock | 32 ------- package.json | 4 +- .../Artist/ArtistArtworks/ArtistArtworks.tsx | 57 ++++++------ .../MasonryInfiniteScrollArtworkGrid.tsx | 86 +++++++++---------- src/app/Components/Gene/GeneArtworks.tsx | 9 +- .../Components/InfiniteScrollFlashList.tsx | 3 - src/app/Components/WorksForYouArtworks.tsx | 1 - .../components/NotificationArtworkList.tsx | 1 - .../Components/ArticleSlideShow.tsx | 1 - .../ArtistSeries/ArtistSeriesArtworks.tsx | 55 ++++++------ src/app/Scenes/Collect/Collect.tsx | 1 - .../Collection/Screens/CollectionArtworks.tsx | 60 +++++++------ .../Components/CollectionsByCategoryBody.tsx | 1 - .../Scenes/Fair/Components/FairArtworks.tsx | 60 +++++++------ .../HomeViewSectionScreenArtworks.tsx | 1 - .../InfiniteDiscoveryMoreWorksTab.tsx | 15 ++-- .../MyCollection/MyCollectionArtworks.tsx | 10 +-- .../Components/ArtworkAutosuggestResults.tsx | 11 +-- .../OnboardingMarketingCollection.tsx | 1 - .../Partner/Components/PartnerArtwork.tsx | 50 ++++++----- .../Components/PartnerOverviewList.tsx | 3 +- src/app/Scenes/Search/SearchArtworksGrid.tsx | 13 +-- .../Search/components/EntitySearchResults.tsx | 6 +- .../Scenes/Show/Components/ShowArtworks.tsx | 1 - src/app/Scenes/Tag/TagArtworks.tsx | 13 +-- src/app/utils/masonryHelpers/index.tsx | 7 +- src/setupJest.tsx | 1 - yarn.lock | 77 +++++++---------- 29 files changed, 258 insertions(+), 323 deletions(-) diff --git a/docs/best_practices.md b/docs/best_practices.md index 590d34cf310..46346eb7c69 100644 --- a/docs/best_practices.md +++ b/docs/best_practices.md @@ -222,7 +222,6 @@ const App = () => { return ( ) diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 046baf84167..0435ca63277 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -3138,34 +3138,6 @@ PODS: - FirebaseCoreExtension - React-Core - RNFBApp - - RNFlashList (1.8.3): - - boost - - DoubleConversion - - fast_float - - fmt - - glog - - hermes-engine - - RCT-Folly - - RCT-Folly/Fabric - - RCTRequired - - RCTTypeSafety - - React-Core - - React-debug - - React-Fabric - - React-featureflags - - React-graphics - - React-ImageManager - - React-jsi - - React-NativeModulesApple - - React-RCTFabric - - React-renderercss - - React-rendererdebug - - React-utils - - ReactCodegen - - ReactCommon/turbomodule/bridging - - ReactCommon/turbomodule/core - - SocketRocket - - Yoga - RNGestureHandler (2.28.0): - boost - DoubleConversion @@ -3983,7 +3955,6 @@ DEPENDENCIES: - "RNFastImage (from `../node_modules/@d11/react-native-fast-image`)" - "RNFBApp (from `../node_modules/@react-native-firebase/app`)" - "RNFBMessaging (from `../node_modules/@react-native-firebase/messaging`)" - - "RNFlashList (from `../node_modules/@shopify/flash-list`)" - RNGestureHandler (from `../node_modules/react-native-gesture-handler`) - "RNGoogleSignin (from `../node_modules/@react-native-google-signin/google-signin`)" - RNImageCropPicker (from `../node_modules/react-native-image-crop-picker`) @@ -4339,8 +4310,6 @@ EXTERNAL SOURCES: :path: "../node_modules/@react-native-firebase/app" RNFBMessaging: :path: "../node_modules/@react-native-firebase/messaging" - RNFlashList: - :path: "../node_modules/@shopify/flash-list" RNGestureHandler: :path: "../node_modules/react-native-gesture-handler" RNGoogleSignin: @@ -4574,7 +4543,6 @@ SPEC CHECKSUMS: RNFastImage: 4b6aa4ec13de8dc57deef25f89f00aa93a2cf139 RNFBApp: fcac8339a5ffd5a735c62d5f0101f79e4d9a7670 RNFBMessaging: 8c72e2f7d5eb2cc24d87e60c8be21eb2c94da272 - RNFlashList: b1f92e77d19aca4f9112bd977ca2ff8a2d61bf69 RNGestureHandler: 3a73f098d74712952870e948b3d9cf7b6cae9961 RNGoogleSignin: b8f09e3ec56e09497e1e53b0ff66d5a45916c6b1 RNImageCropPicker: 07691ec35bc874cf46b39d7710d82f63c9ca0817 diff --git a/package.json b/package.json index cd3015f60da..5dcc33e8404 100644 --- a/package.json +++ b/package.json @@ -109,7 +109,7 @@ "dependencies": { "@artsy/cohesion": "4.336.0", "@artsy/icons": "3.63.0", - "@artsy/palette-mobile": "22.1.0", + "@artsy/palette-mobile": "22.1.0--canary.424.5073.0", "@artsy/to-title-case": "1.2.0", "@braze/react-native-sdk": "16.1.0", "@d11/react-native-fast-image": "8.12.0", @@ -140,7 +140,7 @@ "@segment/analytics-react-native-plugin-braze": "0.9.0", "@segment/sovran-react-native": "1.1.3", "@sentry/react-native": "6.21.0", - "@shopify/flash-list": "1.8.3", + "@shopify/flash-list": "2.2.0", "@stripe/stripe-react-native": "0.50.3", "@styled-system/theme-get": "5.1.2", "@unleash/proxy-client-react": "4.5.2", diff --git a/src/app/Components/Artist/ArtistArtworks/ArtistArtworks.tsx b/src/app/Components/Artist/ArtistArtworks/ArtistArtworks.tsx index 7726321ca96..ed01fe0e347 100644 --- a/src/app/Components/Artist/ArtistArtworks/ArtistArtworks.tsx +++ b/src/app/Components/Artist/ArtistArtworks/ArtistArtworks.tsx @@ -13,7 +13,7 @@ import { useScreenDimensions, useSpace, } from "@artsy/palette-mobile" -import { MasonryFlashListRef, MasonryListRenderItem } from "@shopify/flash-list" +import { FlashListRef, ListRenderItem } from "@shopify/flash-list" import { ArtistArtworksQuery, ArtistArtworksQuery$data, @@ -50,7 +50,7 @@ import { extractNodes } from "app/utils/extractNodes" import { useFeatureFlag } from "app/utils/hooks/useFeatureFlag" import { withSuspense } from "app/utils/hooks/withSuspense" import { - ESTIMATED_MASONRY_ITEM_SIZE, + getColumnIndex, MASONRY_LIST_PAGE_SIZE, NUM_COLUMNS_MASONRY, ON_END_REACHED_THRESHOLD_MASONRY, @@ -106,7 +106,7 @@ const ArtworksGrid: React.FC = ({ const artworks = useMemo(() => extractNodes(artist.artworks), [artist.artworks]) const artworksCount = artist.artworks?.counts?.total ?? 0 - const gridRef = useRef>(null) + const gridRef = useRef>(null) const appliedFilters = ArtworksFiltersStore.useStoreState((state) => state.appliedFilters) @@ -181,32 +181,30 @@ const ArtworksGrid: React.FC = ({ } } - const renderItem: MasonryListRenderItem = useCallback( - ({ item, index, columnIndex }) => { - const imgAspectRatio = item.image?.aspectRatio ?? 1 - const imgWidth = width / NUM_COLUMNS_MASONRY - space(2) - space(1) - const imgHeight = imgWidth / imgAspectRatio - - return ( - - - - ) - }, - [] - ) + const renderItem: ListRenderItem = useCallback(({ item, index }) => { + const columnIndex = getColumnIndex(index) + const imgAspectRatio = item.image?.aspectRatio ?? 1 + const imgWidth = width / NUM_COLUMNS_MASONRY - space(2) - space(1) + const imgHeight = imgWidth / imgAspectRatio + + return ( + + + + ) + }, []) const listFooterComponent = useMemo( () => ( @@ -276,7 +274,6 @@ const ArtworksGrid: React.FC = ({ , - "renderItem" | "data" -> +type MasonryFlashListOmittedProps = Omit, "renderItem" | "data"> interface MasonryInfiniteScrollArtworkGridProps extends MasonryFlashListOmittedProps { animated?: boolean @@ -93,37 +89,41 @@ export const MasonryInfiniteScrollArtworkGrid: React.FC ( - - ), + const renderItem: ListRenderItem = useCallback( + ({ item, index }) => { + const columnIndex = getColumnIndex(index, rest.numColumns) + + return ( + + ) + }, [ contextModule, contextScreenOwnerType, @@ -146,7 +146,7 @@ export const MasonryInfiniteScrollArtworkGrid: React.FC { return rest.numColumns ?? NUM_COLUMNS_MASONRY @@ -160,6 +160,7 @@ export const MasonryInfiniteScrollArtworkGrid: React.FC, "numColumns" | "data" | "renderItem"> }, [shouldDisplayHeader, ListHeaderComponent, ListEmptyComponent, refreshControl, rest.onScroll]) @@ -181,7 +182,7 @@ export const MasonryInfiniteScrollArtworkGrid: React.FC item.id} numColumns={getAdjustedNumColumns()} renderItem={renderItem} @@ -190,7 +191,6 @@ export const MasonryInfiniteScrollArtworkGrid: React.FC ) : null } - estimatedItemSize={ESTIMATED_MASONRY_ITEM_SIZE} onEndReached={onEndReached} contentContainerStyle={{ // No paddings are needed for single column grids @@ -219,5 +219,5 @@ const Footer: FC<{ } const AnimatedMasonryFlashList = Animated.createAnimatedComponent( - MasonryFlashList -) as unknown as typeof MasonryFlashList + FlashList +) as unknown as typeof FlashList diff --git a/src/app/Components/Gene/GeneArtworks.tsx b/src/app/Components/Gene/GeneArtworks.tsx index f4aeee90953..b364843db1c 100644 --- a/src/app/Components/Gene/GeneArtworks.tsx +++ b/src/app/Components/Gene/GeneArtworks.tsx @@ -8,7 +8,7 @@ import { useScreenDimensions, useSpace, } from "@artsy/palette-mobile" -import { MasonryListRenderItem } from "@shopify/flash-list" +import { ListRenderItem } from "@shopify/flash-list" import { GeneArtworks_gene$data } from "__generated__/GeneArtworks_gene.graphql" import { ArtworkFilterNavigator, FilterModalMode } from "app/Components/ArtworkFilter" import { useArtworkFilters } from "app/Components/ArtworkFilter/useArtworkFilters" @@ -17,7 +17,7 @@ import { FilteredArtworkGridZeroState } from "app/Components/ArtworkGrids/Filter import { GeneArtworksFilterHeader } from "app/Components/Gene/GeneArtworksFilterHeader" import { extractNodes } from "app/utils/extractNodes" import { - ESTIMATED_MASONRY_ITEM_SIZE, + getColumnIndex, MASONRY_LIST_PAGE_SIZE, NUM_COLUMNS_MASONRY, ON_END_REACHED_THRESHOLD_MASONRY, @@ -85,7 +85,9 @@ export const GeneArtworksContainer: React.FC = ({ ge } }, [relay.hasMore(), relay.isLoading()]) - const renderItem: MasonryListRenderItem = useCallback(({ item, columnIndex }) => { + const renderItem: ListRenderItem = useCallback(({ item, index }) => { + const columnIndex = getColumnIndex(index) + const imgAspectRatio = item.image?.aspectRatio ?? 1 const imgWidth = width / NUM_COLUMNS_MASONRY - space(2) - space(1) const imgHeight = imgWidth / imgAspectRatio @@ -112,7 +114,6 @@ export const GeneArtworksContainer: React.FC = ({ ge = { initialNumToRender?: number } & FlashListProps -const ESTIMATED_ITEM_SIZE = 60 - export function InfiniteScrollFlashList(props: InfiniteScrollFlashListProps) { const { listRef, onScrollBeginDrag, ...restProps } = props @@ -17,7 +15,6 @@ export function InfiniteScrollFlashList(props: InfiniteScrollFlashList {...restProps} ref={listRef} - estimatedItemSize={ESTIMATED_ITEM_SIZE} onScrollBeginDrag={(event) => { if (onScrollBeginDrag) { onScrollBeginDrag(event) diff --git a/src/app/Components/WorksForYouArtworks.tsx b/src/app/Components/WorksForYouArtworks.tsx index d5dced15dbf..07e7f86c718 100644 --- a/src/app/Components/WorksForYouArtworks.tsx +++ b/src/app/Components/WorksForYouArtworks.tsx @@ -43,7 +43,6 @@ export const WorksForYouArtworks: React.FC = ({ viewer }) = loadMore={loadNext} hasMore={hasNext} numColumns={numColumns} - disableAutoLayout pageSize={PAGE_SIZE} contextModule={ContextModule.newWorksForYouRail} contextScreenOwnerType={OwnerType.newWorksForYou} diff --git a/src/app/Scenes/Activity/components/NotificationArtworkList.tsx b/src/app/Scenes/Activity/components/NotificationArtworkList.tsx index 9850f3c978b..a233c8da90d 100644 --- a/src/app/Scenes/Activity/components/NotificationArtworkList.tsx +++ b/src/app/Scenes/Activity/components/NotificationArtworkList.tsx @@ -32,7 +32,6 @@ export const NotificationArtworkList: FC = ({ animated artworks={artworks} numColumns={1} - disableAutoLayout contextScreenOwnerType={OwnerType.activity} contextScreen={OwnerType.activity} hasMore={false} diff --git a/src/app/Scenes/ArticleSlideShow/Components/ArticleSlideShow.tsx b/src/app/Scenes/ArticleSlideShow/Components/ArticleSlideShow.tsx index e3f67e97d97..800e8b5e755 100644 --- a/src/app/Scenes/ArticleSlideShow/Components/ArticleSlideShow.tsx +++ b/src/app/Scenes/ArticleSlideShow/Components/ArticleSlideShow.tsx @@ -86,7 +86,6 @@ export const ArticleSlideShow: React.FC = ({ article, cov horizontal keyExtractor={({ id }) => `ArticleSlideShowItem-${id}`} snapToInterval={width} - estimatedItemSize={width} pagingEnabled initialScrollIndex={currentIndex} viewabilityConfig={{ diff --git a/src/app/Scenes/ArtistSeries/ArtistSeriesArtworks.tsx b/src/app/Scenes/ArtistSeries/ArtistSeriesArtworks.tsx index 2988319aec3..1b58dbb1abb 100644 --- a/src/app/Scenes/ArtistSeries/ArtistSeriesArtworks.tsx +++ b/src/app/Scenes/ArtistSeries/ArtistSeriesArtworks.tsx @@ -1,6 +1,6 @@ import { OwnerType } from "@artsy/cohesion" import { Box, Flex, Tabs, useScreenDimensions, useSpace } from "@artsy/palette-mobile" -import { MasonryFlashListRef, MasonryListRenderItem } from "@shopify/flash-list" +import { FlashListRef, ListRenderItem } from "@shopify/flash-list" import { ArtistSeriesArtworks_artistSeries$data, ArtistSeriesArtworks_artistSeries$key, @@ -13,7 +13,7 @@ import { FilteredArtworkGridZeroState } from "app/Components/ArtworkGrids/Filter import { HeaderArtworksFilterWithTotalArtworks } from "app/Components/HeaderArtworksFilter/HeaderArtworksFilterWithTotalArtworks" import { extractNodes } from "app/utils/extractNodes" import { - ESTIMATED_MASONRY_ITEM_SIZE, + getColumnIndex, NUM_COLUMNS_MASONRY, ON_END_REACHED_THRESHOLD_MASONRY, } from "app/utils/masonryHelpers" @@ -49,7 +49,7 @@ export const ArtistSeriesArtworks: React.FC = ({ arti [data.artistSeriesArtworks] ) const shouldDisplaySpinner = isLoadingNext && hasNext - const gridRef = useRef>(null) + const gridRef = useRef>(null) const setFiltersCountAction = ArtworksFiltersStore.useStoreActions( (state) => state.setFiltersCountAction ) @@ -96,31 +96,29 @@ export const ArtistSeriesArtworks: React.FC = ({ arti tracking.trackEvent(tracks.clearFilters(id, slug)) } - const renderItem: MasonryListRenderItem = useCallback( - ({ item, index, columnIndex }) => { - const imgAspectRatio = item.image?.aspectRatio ?? 1 - const imgWidth = width / NUM_COLUMNS_MASONRY - space(2) - space(1) - const imgHeight = imgWidth / imgAspectRatio - - return ( - - - - ) - }, - [] - ) + const renderItem: ListRenderItem = useCallback(({ item, index }) => { + const columnIndex = getColumnIndex(index) + const imgAspectRatio = item.image?.aspectRatio ?? 1 + const imgWidth = width / NUM_COLUMNS_MASONRY - space(2) - space(1) + const imgHeight = imgWidth / imgAspectRatio + + return ( + + + + ) + }, []) return ( <> @@ -128,7 +126,6 @@ export const ArtistSeriesArtworks: React.FC = ({ arti testID="ArtistSeriesArtworksGrid" data={artworksList} numColumns={NUM_COLUMNS_MASONRY} - estimatedItemSize={ESTIMATED_MASONRY_ITEM_SIZE} keyboardShouldPersistTaps="handled" innerRef={gridRef} ListEmptyComponent={ diff --git a/src/app/Scenes/Collect/Collect.tsx b/src/app/Scenes/Collect/Collect.tsx index 4e6022995e5..15290ac007a 100644 --- a/src/app/Scenes/Collect/Collect.tsx +++ b/src/app/Scenes/Collect/Collect.tsx @@ -111,7 +111,6 @@ export const CollectContent: React.FC = ({ viewer }) => { loadMore={() => loadNext(PAGE_SIZE)} hasMore={hasNext} numColumns={NUM_COLUMNS_MASONRY} - disableAutoLayout pageSize={PAGE_SIZE} contextModule={ContextModule.artworkGrid} // TODO: Add tracking diff --git a/src/app/Scenes/Collection/Screens/CollectionArtworks.tsx b/src/app/Scenes/Collection/Screens/CollectionArtworks.tsx index 1c0daa9aa89..480c8aaeffb 100644 --- a/src/app/Scenes/Collection/Screens/CollectionArtworks.tsx +++ b/src/app/Scenes/Collection/Screens/CollectionArtworks.tsx @@ -1,6 +1,6 @@ import { OwnerType } from "@artsy/cohesion" import { Box, Flex, Tabs, useScreenDimensions, useSpace } from "@artsy/palette-mobile" -import { MasonryFlashListRef, MasonryListRenderItem } from "@shopify/flash-list" +import { FlashListRef, ListRenderItem } from "@shopify/flash-list" import { CollectionArtworks_collection$data } from "__generated__/CollectionArtworks_collection.graphql" import { ArtworkFilterNavigator, FilterModalMode } from "app/Components/ArtworkFilter" import { ArtworksFiltersStore } from "app/Components/ArtworkFilter/ArtworkFilterStore" @@ -11,7 +11,7 @@ import { HeaderArtworksFilterWithTotalArtworks } from "app/Components/HeaderArtw import { extractNodes } from "app/utils/extractNodes" import { get } from "app/utils/get" import { - ESTIMATED_MASONRY_ITEM_SIZE, + getColumnIndex, MASONRY_LIST_PAGE_SIZE, NUM_COLUMNS_MASONRY, ON_END_REACHED_THRESHOLD_MASONRY, @@ -46,7 +46,7 @@ export const CollectionArtworks: React.FC = ({ collecti () => extractNodes(collection.collectionArtworks), [collection.collectionArtworks] ) - const gridRef = useRef>(null) + const gridRef = useRef>(null) const scrollToTop = () => { gridRef?.current?.scrollToOffset({ offset: 0, animated: true }) @@ -106,42 +106,40 @@ export const CollectionArtworks: React.FC = ({ collecti }) } - const renderItem: MasonryListRenderItem = useCallback( - ({ item, index, columnIndex }) => { - const imgAspectRatio = item.image?.aspectRatio ?? 1 - const imgWidth = width / NUM_COLUMNS_MASONRY - space(2) - space(1) - const imgHeight = imgWidth / imgAspectRatio + const renderItem: ListRenderItem = useCallback(({ item, index }) => { + const columnIndex = getColumnIndex(index) - const hideSignals = CURATORS_PICKS_SLUGS.includes(collection.slug) + const imgAspectRatio = item.image?.aspectRatio ?? 1 + const imgWidth = width / NUM_COLUMNS_MASONRY - space(2) - space(1) + const imgHeight = imgWidth / imgAspectRatio - return ( - - - - ) - }, - [] - ) + const hideSignals = CURATORS_PICKS_SLUGS.includes(collection.slug) + + return ( + + + + ) + }, []) return ( <> ) }} renderItem={({ item }) => item.jsx()} - estimatedItemSize={230} // Value from RN Debugger Inspector keyExtractor={(item) => item.key} ItemSeparatorComponent={() => } /> diff --git a/src/app/Scenes/Fair/Components/FairArtworks.tsx b/src/app/Scenes/Fair/Components/FairArtworks.tsx index a82b7a3ef1a..46058fc6918 100644 --- a/src/app/Scenes/Fair/Components/FairArtworks.tsx +++ b/src/app/Scenes/Fair/Components/FairArtworks.tsx @@ -1,6 +1,6 @@ import { OwnerType } from "@artsy/cohesion" import { Flex, SkeletonText, Spacer, Spinner, Tabs, useSpace } from "@artsy/palette-mobile" -import { MasonryFlashList, MasonryListRenderItem } from "@shopify/flash-list" +import { FlashList, ListRenderItem } from "@shopify/flash-list" import { FairArtworksQuery } from "__generated__/FairArtworksQuery.graphql" import { FairArtworks_fair$data, @@ -23,7 +23,7 @@ import { extractNodes } from "app/utils/extractNodes" import { useScreenDimensions } from "app/utils/hooks" import { withSuspense } from "app/utils/hooks/withSuspense" import { - ESTIMATED_MASONRY_ITEM_SIZE, + getColumnIndex, MASONRY_LIST_PAGE_SIZE, NUM_COLUMNS_MASONRY, ON_END_REACHED_THRESHOLD_MASONRY, @@ -94,31 +94,29 @@ export const FairArtworks: React.FC = ({ setFiltersCountAction({ ...counts, total: artworksTotal }) }, [artworksTotal]) - const renderItem: MasonryListRenderItem = useCallback( - ({ item, index, columnIndex }) => { - const imgAspectRatio = item.image?.aspectRatio ?? 1 - const imgWidth = width / NUM_COLUMNS_MASONRY - space(2) - space(1) - const imgHeight = imgWidth / imgAspectRatio - - return ( - - - - ) - }, - [] - ) + const renderItem: ListRenderItem = useCallback(({ item, index }) => { + const columnIndex = getColumnIndex(index) + const imgAspectRatio = item.image?.aspectRatio ?? 1 + const imgWidth = width / NUM_COLUMNS_MASONRY - space(2) - space(1) + const imgHeight = imgWidth / imgAspectRatio + + return ( + + + + ) + }, []) if (!data) { return null @@ -160,7 +158,6 @@ export const FairArtworks: React.FC = ({ data={filteredArtworks} keyExtractor={(item) => item.id} numColumns={NUM_COLUMNS_MASONRY} - estimatedItemSize={ESTIMATED_MASONRY_ITEM_SIZE} keyboardShouldPersistTaps="handled" ListEmptyComponent={ @@ -285,11 +282,10 @@ export const FairArtworksWithoutTabs: React.FC = ({ return ( <> - item.id} numColumns={NUM_COLUMNS_MASONRY} - estimatedItemSize={ESTIMATED_MASONRY_ITEM_SIZE} keyboardShouldPersistTaps="handled" ListEmptyComponent={ @@ -310,7 +306,9 @@ export const FairArtworksWithoutTabs: React.FC = ({ } onEndReached={handleOnEndReached} onEndReachedThreshold={ON_END_REACHED_THRESHOLD_MASONRY} - renderItem={({ item, index, columnIndex }) => { + renderItem={({ item, index }) => { + const columnIndex = getColumnIndex(index) + const imgAspectRatio = item.image?.aspectRatio ?? 1 const imgWidth = width / NUM_COLUMNS_MASONRY - space(2) - space(1) const imgHeight = imgWidth / imgAspectRatio diff --git a/src/app/Scenes/HomeViewSectionScreen/Components/HomeViewSectionScreenArtworks.tsx b/src/app/Scenes/HomeViewSectionScreen/Components/HomeViewSectionScreenArtworks.tsx index 223d42811fd..a4cd4209b2e 100644 --- a/src/app/Scenes/HomeViewSectionScreen/Components/HomeViewSectionScreenArtworks.tsx +++ b/src/app/Scenes/HomeViewSectionScreen/Components/HomeViewSectionScreenArtworks.tsx @@ -184,7 +184,6 @@ export const HomeViewSectionScreenArtworks: React.FC animated artworks={artworks} numColumns={numOfColumns} - disableAutoLayout pageSize={PAGE_SIZE} ListEmptyComponent={ Nothing yet. Please check back later. diff --git a/src/app/Scenes/InfiniteDiscovery/Components/InfiniteDiscoveryMoreWorksTab.tsx b/src/app/Scenes/InfiniteDiscovery/Components/InfiniteDiscoveryMoreWorksTab.tsx index 4574035c67e..d953c11448d 100644 --- a/src/app/Scenes/InfiniteDiscovery/Components/InfiniteDiscoveryMoreWorksTab.tsx +++ b/src/app/Scenes/InfiniteDiscovery/Components/InfiniteDiscoveryMoreWorksTab.tsx @@ -1,7 +1,7 @@ import { ContextModule, OwnerType } from "@artsy/cohesion" import { Flex, SimpleMessage, Tabs, useScreenDimensions, useSpace } from "@artsy/palette-mobile" import { BottomSheetScrollView } from "@gorhom/bottom-sheet" -import { MasonryListRenderItem } from "@shopify/flash-list" +import { ListRenderItem } from "@shopify/flash-list" import { InfiniteDiscoveryMoreWorksTabQuery } from "__generated__/InfiniteDiscoveryMoreWorksTabQuery.graphql" import { InfiniteDiscoveryMoreWorksTab_artworks$key } from "__generated__/InfiniteDiscoveryMoreWorksTab_artworks.graphql" import ArtworkGridItem from "app/Components/ArtworkGrids/ArtworkGridItem" @@ -10,7 +10,7 @@ import { PAGE_SIZE } from "app/Components/constants" import { extractNodes } from "app/utils/extractNodes" import { withSuspense } from "app/utils/hooks/withSuspense" import { - ESTIMATED_MASONRY_ITEM_SIZE, + getColumnIndex, NUM_COLUMNS_MASONRY, ON_END_REACHED_THRESHOLD_MASONRY, } from "app/utils/masonryHelpers" @@ -38,8 +38,10 @@ export const MoreWorksTab: FC = ({ artworks: _artworks }) => } } - const renderItem: MasonryListRenderItem> = - useCallback(({ item, index, columnIndex }) => { + const renderItem: ListRenderItem> = useCallback( + ({ item, index }) => { + const columnIndex = getColumnIndex(index) + const imgAspectRatio = item.image?.aspectRatio ?? 1 const imgWidth = width / NUM_COLUMNS_MASONRY - space(2) - space(1) const imgHeight = imgWidth / imgAspectRatio @@ -61,13 +63,14 @@ export const MoreWorksTab: FC = ({ artworks: _artworks }) => /> ) - }, []) + }, + [] + ) const masonry = ( item?.internalID} ListEmptyComponent={} diff --git a/src/app/Scenes/MyCollection/MyCollectionArtworks.tsx b/src/app/Scenes/MyCollection/MyCollectionArtworks.tsx index 640d23afac3..d47c5074bc8 100644 --- a/src/app/Scenes/MyCollection/MyCollectionArtworks.tsx +++ b/src/app/Scenes/MyCollection/MyCollectionArtworks.tsx @@ -1,5 +1,5 @@ import { Box, Flex, Tabs, useSpace } from "@artsy/palette-mobile" -import { MasonryListRenderItem } from "@shopify/flash-list" +import { ListRenderItem } from "@shopify/flash-list" import { MyCollectionArtworksQuery } from "__generated__/MyCollectionArtworksQuery.graphql" import { MyCollectionArtworks_me$key } from "__generated__/MyCollectionArtworks_me.graphql" import { ArtworkFilterNavigator, FilterModalMode } from "app/Components/ArtworkFilter" @@ -20,7 +20,7 @@ import { cleanLocalImages } from "app/utils/LocalImageStore" import { extractNodes } from "app/utils/extractNodes" import { withSuspense } from "app/utils/hooks/withSuspense" import { - ESTIMATED_MASONRY_ITEM_SIZE, + getColumnIndex, NUM_COLUMNS_MASONRY, ON_END_REACHED_THRESHOLD_MASONRY, } from "app/utils/masonryHelpers" @@ -75,8 +75,9 @@ export const MyCollectionArtworks: React.FC = ({ me } cleanLocalImages() }, []) - const renderItem: MasonryListRenderItem<(typeof filteredArtworks)[0]> = useCallback( - ({ item, index: _index, columnIndex }) => { + const renderItem: ListRenderItem<(typeof filteredArtworks)[0]> = useCallback( + ({ item, index }) => { + const columnIndex = getColumnIndex(index) return ( = ({ me } diff --git a/src/app/Scenes/MyCollection/Screens/ArtworkForm/Components/ArtworkAutosuggestResults.tsx b/src/app/Scenes/MyCollection/Screens/ArtworkForm/Components/ArtworkAutosuggestResults.tsx index 79115b791d3..df2be14053d 100644 --- a/src/app/Scenes/MyCollection/Screens/ArtworkForm/Components/ArtworkAutosuggestResults.tsx +++ b/src/app/Scenes/MyCollection/Screens/ArtworkForm/Components/ArtworkAutosuggestResults.tsx @@ -8,7 +8,7 @@ import { Text, useSpace, } from "@artsy/palette-mobile" -import { MasonryFlashList } from "@shopify/flash-list" +import { FlashList } from "@shopify/flash-list" import { ArtworkAutosuggestResultsContainerQuery } from "__generated__/ArtworkAutosuggestResultsContainerQuery.graphql" import { ArtworkAutosuggestResults_viewer$data } from "__generated__/ArtworkAutosuggestResults_viewer.graphql" import ArtworkGridItem from "app/Components/ArtworkGrids/ArtworkGridItem" @@ -19,7 +19,7 @@ import { getRelayEnvironment } from "app/system/relay/defaultEnvironment" import { extractNodes } from "app/utils/extractNodes" import { useScreenDimensions } from "app/utils/hooks" import { - ESTIMATED_MASONRY_ITEM_SIZE, + getColumnIndex, NUM_COLUMNS_MASONRY, ON_END_REACHED_THRESHOLD_MASONRY, } from "app/utils/masonryHelpers" @@ -64,13 +64,13 @@ const ArtworkAutosuggestResults: React.FC = ({ }, [viewer.artworks?.edges?.length]) return ( - item.id} - estimatedItemSize={ESTIMATED_MASONRY_ITEM_SIZE} keyboardShouldPersistTaps="handled" onEndReached={loadMore} onEndReachedThreshold={ON_END_REACHED_THRESHOLD_MASONRY} @@ -96,7 +96,8 @@ const ArtworkAutosuggestResults: React.FC = ({ } - renderItem={({ item, index, columnIndex }) => { + renderItem={({ item, index }) => { + const columnIndex = getColumnIndex(index) const imgAspectRatio = item.image?.aspectRatio ?? 1 const imgWidth = width / NUM_COLUMNS_MASONRY - space(2) - space(1) diff --git a/src/app/Scenes/Onboarding/Screens/OnboardingQuiz/OnboardingMarketingCollection.tsx b/src/app/Scenes/Onboarding/Screens/OnboardingQuiz/OnboardingMarketingCollection.tsx index 96ad59468d3..6804d7d8641 100644 --- a/src/app/Scenes/Onboarding/Screens/OnboardingQuiz/OnboardingMarketingCollection.tsx +++ b/src/app/Scenes/Onboarding/Screens/OnboardingQuiz/OnboardingMarketingCollection.tsx @@ -58,7 +58,6 @@ const OnboardingMarketingCollection: React.FC null} hasMore={false} numColumns={NUM_COLUMNS_MASONRY} - disableAutoLayout onScroll={scrollHandler} ListHeaderComponent={ <> diff --git a/src/app/Scenes/Partner/Components/PartnerArtwork.tsx b/src/app/Scenes/Partner/Components/PartnerArtwork.tsx index 58e055a7454..f61b2ffec2e 100644 --- a/src/app/Scenes/Partner/Components/PartnerArtwork.tsx +++ b/src/app/Scenes/Partner/Components/PartnerArtwork.tsx @@ -1,6 +1,6 @@ import { OwnerType } from "@artsy/cohesion" import { Box, Flex, Tabs, useScreenDimensions, useSpace } from "@artsy/palette-mobile" -import { MasonryListRenderItem } from "@shopify/flash-list" +import { ListRenderItem } from "@shopify/flash-list" import { PartnerArtwork_partner$data } from "__generated__/PartnerArtwork_partner.graphql" import { ArtworkFilterNavigator, FilterModalMode } from "app/Components/ArtworkFilter" import { @@ -13,7 +13,7 @@ import { TabEmptyState } from "app/Components/TabEmptyState" import { extractNodes } from "app/utils/extractNodes" import { - ESTIMATED_MASONRY_ITEM_SIZE, + getColumnIndex, MASONRY_LIST_PAGE_SIZE, NUM_COLUMNS_MASONRY, ON_END_REACHED_THRESHOLD_MASONRY, @@ -62,37 +62,35 @@ export const PartnerArtwork: React.FC<{ const emptyText = "There are no matching works from this gallery.\nTry changing your search filters" - const renderItem: MasonryListRenderItem = useCallback( - ({ item, columnIndex }) => { - const imgAspectRatio = item.image?.aspectRatio ?? 1 - const imgWidth = width / NUM_COLUMNS_MASONRY - space(2) - space(1) - const imgHeight = imgWidth / imgAspectRatio + const renderItem: ListRenderItem = useCallback(({ item, index }) => { + const columnIndex = getColumnIndex(index) - return ( - - - - ) - }, - [] - ) + const imgAspectRatio = item.image?.aspectRatio ?? 1 + const imgWidth = width / NUM_COLUMNS_MASONRY - space(2) - space(1) + const imgHeight = imgWidth / imgAspectRatio + + return ( + + + + ) + }, []) return ( <> diff --git a/src/app/Scenes/Partner/Components/PartnerOverviewList.tsx b/src/app/Scenes/Partner/Components/PartnerOverviewList.tsx index ec2d4358b6f..b18091ebb07 100644 --- a/src/app/Scenes/Partner/Components/PartnerOverviewList.tsx +++ b/src/app/Scenes/Partner/Components/PartnerOverviewList.tsx @@ -2,8 +2,8 @@ import { Flex, Spacer, Tabs, Text } from "@artsy/palette-mobile" import { ListRenderItem } from "@shopify/flash-list" import { PartnerOverviewListArtistsQuery } from "__generated__/PartnerOverviewListArtistsQuery.graphql" import { - PartnerOverviewListArtists_partner$key, PartnerOverviewListArtists_partner$data, + PartnerOverviewListArtists_partner$key, } from "__generated__/PartnerOverviewListArtists_partner.graphql" import { ArtistListItemContainer as ArtistListItem } from "app/Components/ArtistListItem" import { ReadMore } from "app/Components/ReadMore" @@ -55,7 +55,6 @@ export const PartnerOverviewList: React.FC = ({ return ( { diff --git a/src/app/Scenes/Search/SearchArtworksGrid.tsx b/src/app/Scenes/Search/SearchArtworksGrid.tsx index b73b11a79ff..c4fe5886576 100644 --- a/src/app/Scenes/Search/SearchArtworksGrid.tsx +++ b/src/app/Scenes/Search/SearchArtworksGrid.tsx @@ -8,7 +8,7 @@ import { useScreenDimensions, useTheme, } from "@artsy/palette-mobile" -import { MasonryFlashList } from "@shopify/flash-list" +import { FlashList } from "@shopify/flash-list" import { SearchArtworksGrid_viewer$data } from "__generated__/SearchArtworksGrid_viewer.graphql" import { ArtworkFilterNavigator, FilterModalMode } from "app/Components/ArtworkFilter" import { ArtworksFiltersStore } from "app/Components/ArtworkFilter/ArtworkFilterStore" @@ -21,7 +21,7 @@ import { ArtworksFilterHeader } from "app/Components/ArtworkGrids/ArtworksFilter import { SCROLLVIEW_SEARCH_RESULTS_PADDING_BOTTOM_OFFSET } from "app/Components/constants" import { extractNodes } from "app/utils/extractNodes" import { - ESTIMATED_MASONRY_ITEM_SIZE, + getColumnIndex, NUM_COLUMNS_MASONRY, ON_END_REACHED_THRESHOLD_MASONRY, } from "app/utils/masonryHelpers" @@ -108,13 +108,12 @@ const SearchArtworksGrid: React.FC = ({ viewer, relay, - item.id} numColumns={NUM_COLUMNS_MASONRY} - // this number is the estimated size of the artworkGridItem component - estimatedItemSize={ESTIMATED_MASONRY_ITEM_SIZE} keyboardShouldPersistTaps="handled" keyboardDismissMode="on-drag" ListEmptyComponent={ @@ -135,7 +134,9 @@ const SearchArtworksGrid: React.FC = ({ viewer, relay, ListFooterComponent={() => ( )} - renderItem={({ item, index, columnIndex }) => { + renderItem={({ item, index }) => { + const columnIndex = getColumnIndex(index) + const imgAspectRatio = item.image?.aspectRatio ?? 1 const imgWidth = width / NUM_COLUMNS_MASONRY - space(2) - space(1) diff --git a/src/app/Scenes/Search/components/EntitySearchResults.tsx b/src/app/Scenes/Search/components/EntitySearchResults.tsx index 4b46b4b0b00..364360975f5 100644 --- a/src/app/Scenes/Search/components/EntitySearchResults.tsx +++ b/src/app/Scenes/Search/components/EntitySearchResults.tsx @@ -1,5 +1,5 @@ import { Flex, Spacer, Spinner, useSpace } from "@artsy/palette-mobile" -import { FlashList, ListRenderItem } from "@shopify/flash-list" +import { FlashList, FlashListRef, ListRenderItem } from "@shopify/flash-list" import { EntitySearchResultsQuery } from "__generated__/EntitySearchResultsQuery.graphql" import { EntitySearchResults_searchConnection$key } from "__generated__/EntitySearchResults_searchConnection.graphql" import { SimpleErrorMessage } from "app/Components/ErrorView/SimpleErrorMessage" @@ -22,11 +22,10 @@ interface SearchResultsProps { } const PAGE_SIZE = isTablet() ? 40 : 20 -const ESTIMATED_ITEM_SIZE = 56 export const EntitySearchResults: React.FC = ({ query, selectedPill }) => { const space = useSpace() - const flashListRef = useRef>(null) + const flashListRef = useRef>(null) const { inputRef } = useContext(SearchContext) const selectedEntity = SEARCH_PILL_KEY_TO_SEARCH_ENTITY?.[selectedPill.key] @@ -94,7 +93,6 @@ export const EntitySearchResults: React.FC = ({ query, selec extraData={{ query, selectedPill }} keyExtractor={(item, index) => item.internalID ?? index.toString()} renderItem={renderItem} - estimatedItemSize={ESTIMATED_ITEM_SIZE} showsVerticalScrollIndicator={false} ItemSeparatorComponent={() => } keyboardDismissMode="on-drag" diff --git a/src/app/Scenes/Show/Components/ShowArtworks.tsx b/src/app/Scenes/Show/Components/ShowArtworks.tsx index cf6ec59e522..df8890e1a8d 100644 --- a/src/app/Scenes/Show/Components/ShowArtworks.tsx +++ b/src/app/Scenes/Show/Components/ShowArtworks.tsx @@ -110,7 +110,6 @@ export const ShowArtworks: React.FC = ({ show, initiallyAppliedFilter }) artworks={artworks} isLoading={isLoadingNext} hasMore={hasNext} - disableAutoLayout pageSize={PAGE_SIZE} contextScreenOwnerType={OwnerType.show} contextScreenOwnerId={data.internalID} diff --git a/src/app/Scenes/Tag/TagArtworks.tsx b/src/app/Scenes/Tag/TagArtworks.tsx index 7dba22d1bfb..1d9b86e529a 100644 --- a/src/app/Scenes/Tag/TagArtworks.tsx +++ b/src/app/Scenes/Tag/TagArtworks.tsx @@ -1,14 +1,14 @@ import { OwnerType } from "@artsy/cohesion" import { Box, - Text, + Flex, SimpleMessage, Tabs, + Text, useScreenDimensions, - Flex, useSpace, } from "@artsy/palette-mobile" -import { MasonryListRenderItem } from "@shopify/flash-list" +import { ListRenderItem } from "@shopify/flash-list" import { TagArtworks_tag$data } from "__generated__/TagArtworks_tag.graphql" import { ArtworkFilterNavigator } from "app/Components/ArtworkFilter" import { FilterModalMode } from "app/Components/ArtworkFilter/ArtworkFilterOptionsScreen" @@ -18,7 +18,7 @@ import { FilteredArtworkGridZeroState } from "app/Components/ArtworkGrids/Filter import { TagArtworksFilterHeader } from "app/Scenes/Tag/TagArtworksFilterHeader" import { extractNodes } from "app/utils/extractNodes" import { - ESTIMATED_MASONRY_ITEM_SIZE, + getColumnIndex, MASONRY_LIST_PAGE_SIZE, NUM_COLUMNS_MASONRY, ON_END_REACHED_THRESHOLD_MASONRY, @@ -91,7 +91,9 @@ const TagArtworks: React.FC = ({ tag, relay }) => { } }, [relay.hasMore(), relay.isLoading()]) - const renderItem: MasonryListRenderItem = useCallback(({ item, columnIndex }) => { + const renderItem: ListRenderItem = useCallback(({ item, index }) => { + const columnIndex = getColumnIndex(index) + const imgAspectRatio = item.image?.aspectRatio ?? 1 const imgWidth = width / NUM_COLUMNS_MASONRY - space(2) - space(1) const imgHeight = imgWidth / imgAspectRatio @@ -118,7 +120,6 @@ const TagArtworks: React.FC = ({ tag, relay }) => { } + +export const getColumnIndex = (index: number, numColumns: number = NUM_COLUMNS_MASONRY) => { + return index % numColumns +} diff --git a/src/setupJest.tsx b/src/setupJest.tsx index 78c9d415da0..3f9bafb2541 100644 --- a/src/setupJest.tsx +++ b/src/setupJest.tsx @@ -651,7 +651,6 @@ jest.mock("@shopify/flash-list", () => { const { FlatList } = require("react-native") return { ...jest.requireActual("@shopify/flash-list"), - MasonryFlashList: FlatList, FlashList: FlatList, } }) diff --git a/yarn.lock b/yarn.lock index 7200868f17c..1d6b6db6931 100644 --- a/yarn.lock +++ b/yarn.lock @@ -72,19 +72,19 @@ __metadata: languageName: node linkType: hard -"@artsy/palette-mobile@npm:22.1.0": - version: 22.1.0 - resolution: "@artsy/palette-mobile@npm:22.1.0" +"@artsy/palette-mobile@npm:22.1.0--canary.424.5073.0": + version: 22.1.0--canary.424.5073.0 + resolution: "@artsy/palette-mobile@npm:22.1.0--canary.424.5073.0" dependencies: "@artsy/icons": "npm:^3.49.0" "@artsy/palette-tokens": "npm:7.0.0" "@d11/react-native-fast-image": "npm:8.12.0" "@react-spring/native": "npm:^10.0.3" - "@shopify/flash-list": "npm:^1.8.3" + "@shopify/flash-list": "npm:2.2.0" "@styled-system/theme-get": "npm:^5.1.2" events: "npm:^3.3.0" lodash: "npm:^4.17.21" - moti: "npm:0.30.0" + moti: "npm:^0.25.3" react-nanny: "npm:^2.15.0" react-native-blurhash: "npm:2.1.2" react-native-collapsible-tab-view: "npm:^8.0.1" @@ -101,7 +101,7 @@ __metadata: react-native-reanimated: "*" react-native-svg: "*" styled-components: ">= 5" - checksum: 10c0/caa227676c44ab89722a7adf8cae6b48aa5d9cdae2fc2546f7ea2fbcbcb768b629dbd202d9b51d1339e417279a8782a3ea677786e47a6e94462b2518f3ea53fe + checksum: 10c0/0af80c54bf14a58794bc51f603b2a4503da6f29b4f0b5853ac59b025405a91c2e8d1502796124b9853cd085368dc350443aa9564351b3fbfddb74aaab0144eb2 languageName: node linkType: hard @@ -6903,17 +6903,14 @@ __metadata: languageName: node linkType: hard -"@shopify/flash-list@npm:1.8.3, @shopify/flash-list@npm:^1.8.3": - version: 1.8.3 - resolution: "@shopify/flash-list@npm:1.8.3" - dependencies: - recyclerlistview: "npm:4.2.3" - tslib: "npm:2.8.1" +"@shopify/flash-list@npm:2.2.0": + version: 2.2.0 + resolution: "@shopify/flash-list@npm:2.2.0" peerDependencies: "@babel/runtime": "*" react: "*" react-native: "*" - checksum: 10c0/0900250ce45157d144e3fef4d1cd8c5dfb03495ecb66da1f512697a6834f4eee7bf0755a3772b3c131135784757e5b36566ed365ea0890d9c10ad872885ef650 + checksum: 10c0/ce6bb2096abf1b826e716804106013955c145c0c37d3a277ce294eb0044047af1aeea410fd7c297cc1352b6029b853de5fca2503340f116ccd0281049290625e languageName: node linkType: hard @@ -12569,7 +12566,7 @@ __metadata: dependencies: "@artsy/cohesion": "npm:4.336.0" "@artsy/icons": "npm:3.63.0" - "@artsy/palette-mobile": "npm:22.1.0" + "@artsy/palette-mobile": "npm:22.1.0--canary.424.5073.0" "@artsy/to-title-case": "npm:1.2.0" "@artsy/update-repo": "npm:0.7.0" "@babel/core": "npm:7.25.2" @@ -12624,7 +12621,7 @@ __metadata: "@segment/analytics-react-native-plugin-braze": "npm:0.9.0" "@segment/sovran-react-native": "npm:1.1.3" "@sentry/react-native": "npm:6.21.0" - "@shopify/flash-list": "npm:1.8.3" + "@shopify/flash-list": "npm:2.2.0" "@stripe/stripe-react-native": "npm:0.50.3" "@styled-system/theme-get": "npm:5.1.2" "@testing-library/react-native": "npm:13.2.0" @@ -18207,7 +18204,7 @@ __metadata: languageName: node linkType: hard -"lodash.debounce@npm:4.0.8, lodash.debounce@npm:^4.0.8": +"lodash.debounce@npm:^4.0.8": version: 4.0.8 resolution: "lodash.debounce@npm:4.0.8" checksum: 10c0/762998a63e095412b6099b8290903e0a8ddcb353ac6e2e0f2d7e7d03abd4275fe3c689d88960eb90b0dde4f177554d51a690f22a343932ecbc50a5d111849987 @@ -19626,6 +19623,17 @@ __metadata: languageName: node linkType: hard +"moti@npm:^0.25.3": + version: 0.25.4 + resolution: "moti@npm:0.25.4" + dependencies: + framer-motion: "npm:^6.5.1" + peerDependencies: + react-native-reanimated: "*" + checksum: 10c0/622b8fb2ef48af06a22854e23dbe73acc16bf48e2d9f79f4061139123044ef8227a14a5ae3dbc617110763eaffd74ad99dd55aa4c0da8a5200c7069981ef06ef + languageName: node + linkType: hard + "ms@npm:2.0.0": version: 2.0.0 resolution: "ms@npm:2.0.0" @@ -21045,7 +21053,7 @@ __metadata: languageName: node linkType: hard -"prop-types@npm:*, prop-types@npm:15.8.1, prop-types@npm:^15.5.7, prop-types@npm:^15.8.1": +"prop-types@npm:*, prop-types@npm:^15.5.7, prop-types@npm:^15.8.1": version: 15.8.1 resolution: "prop-types@npm:15.8.1" dependencies: @@ -22167,20 +22175,6 @@ __metadata: languageName: node linkType: hard -"recyclerlistview@npm:4.2.3": - version: 4.2.3 - resolution: "recyclerlistview@npm:4.2.3" - dependencies: - lodash.debounce: "npm:4.0.8" - prop-types: "npm:15.8.1" - ts-object-utils: "npm:0.0.5" - peerDependencies: - react: ">= 15.2.1" - react-native: ">= 0.30.0" - checksum: 10c0/40b8b948d09f560ce98842e9141d2ce7ee5677ae2c20f7e30de901136d7764a42cc4e5ba3242fca0934055d5fef99c5b03430fcba28d7cfc27155b4ef97f70d5 - languageName: node - linkType: hard - "redent@npm:^3.0.0": version: 3.0.0 resolution: "redent@npm:3.0.0" @@ -24785,13 +24779,6 @@ __metadata: languageName: node linkType: hard -"ts-object-utils@npm:0.0.5": - version: 0.0.5 - resolution: "ts-object-utils@npm:0.0.5" - checksum: 10c0/0279f8a7504b3905f2b14769769985f214154f1aedc60077c3baaced078369ae465aecc6acc04c614f40893e559d05697f6f4ef9fc411e3b6d1d15e6269a5e14 - languageName: node - linkType: hard - "ts-toolbelt@npm:^6.15.1": version: 6.15.5 resolution: "ts-toolbelt@npm:6.15.5" @@ -24825,13 +24812,6 @@ __metadata: languageName: node linkType: hard -"tslib@npm:2.8.1, tslib@npm:^2.1.0, tslib@npm:^2.3.0, tslib@npm:^2.3.1": - version: 2.8.1 - resolution: "tslib@npm:2.8.1" - checksum: 10c0/9c4759110a19c53f992d9aae23aac5ced636e99887b51b9e61def52611732872ff7668757d4e4c61f19691e36f4da981cd9485e869b4a7408d689f6bf1f14e62 - languageName: node - linkType: hard - "tslib@npm:^1.10.0, tslib@npm:^1.8.1, tslib@npm:^1.9.0": version: 1.14.1 resolution: "tslib@npm:1.14.1" @@ -24846,6 +24826,13 @@ __metadata: languageName: node linkType: hard +"tslib@npm:^2.1.0, tslib@npm:^2.3.0, tslib@npm:^2.3.1": + version: 2.8.1 + resolution: "tslib@npm:2.8.1" + checksum: 10c0/9c4759110a19c53f992d9aae23aac5ced636e99887b51b9e61def52611732872ff7668757d4e4c61f19691e36f4da981cd9485e869b4a7408d689f6bf1f14e62 + languageName: node + linkType: hard + "tslib@npm:^2.4.0": version: 2.4.1 resolution: "tslib@npm:2.4.1" From ac5c5ab4145180d28063e6d5716b6a869cbb031d Mon Sep 17 00:00:00 2001 From: Mounir Dhahri Date: Fri, 14 Nov 2025 13:00:04 +0100 Subject: [PATCH 009/123] chore: upgrade reanimated to v4 --- HACKS.md | 12 ++ babel.config.js | 2 +- ios/Podfile.lock | 86 +++++++---- package.json | 11 +- patches/react-native+0.81.5.patch | 28 ++++ .../ArtworkLists/components/ArtworkLists.tsx | 4 +- src/app/Components/Disappearable.tsx | 10 +- src/app/Components/HeaderButton.tsx | 6 +- src/app/Components/Swipeable/Swipeable.tsx | 10 +- .../HomeView/hooks/useImpressionsTracking.ts | 5 +- .../Components/Swiper/Swiper.tsx | 12 +- .../Components/SavedSearchListItem.tsx | 4 +- yarn.lock | 136 ++++++++++++------ 13 files changed, 226 insertions(+), 100 deletions(-) diff --git a/HACKS.md b/HACKS.md index 0a89f2bfa88..e6095364863 100644 --- a/HACKS.md +++ b/HACKS.md @@ -283,3 +283,15 @@ not reset. This causes the module to never start listening again causing events #### When can we remove this: It can be removed once if we stop using the singleton pattern or get rid of ARNotificationsManagerModule, or it is fixed upstream. + +## react-native-reanimated package.json flags + +### USE_COMMIT_HOOK_ONLY_FOR_REACT_COMMITS + +#### Explanation/Context: + +This feature flag was added to fix performance issues with scrolling. See https://docs.swmansion.com/react-native-reanimated/docs/guides/performance/#%EF%B8%8F-lower-fps-while-scrolling + +#### When can we remove this: + +When reanimated adopts this by default. diff --git a/babel.config.js b/babel.config.js index 31ecee15e1a..1328ea4209d 100644 --- a/babel.config.js +++ b/babel.config.js @@ -24,7 +24,7 @@ module.exports = (api) => { "relay", ["module-resolver", { alias: moduleResolverAlias }], - "react-native-reanimated/plugin", // has to be listed last according to the documentation. https://docs.swmansion.com/react-native-reanimated/docs/fundamentals/installation/#babel-plugin + "react-native-worklets/plugin", // has to be listed last according to the documentation. https://docs.swmansion.com/react-native-reanimated/docs/fundamentals/installation/#babel-plugin ] const prodPlugins = [["transform-remove-console", { exclude: ["error"] }], ...plugins] diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 0435ca63277..e42efa39504 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -3353,7 +3353,7 @@ PODS: - Yoga - RNReactNativeHapticFeedback (1.13.0): - React-Core - - RNReanimated (3.19.4): + - RNReanimated (4.1.5): - boost - DoubleConversion - fast_float @@ -3380,11 +3380,11 @@ PODS: - ReactCodegen - ReactCommon/turbomodule/bridging - ReactCommon/turbomodule/core - - RNReanimated/reanimated (= 3.19.4) - - RNReanimated/worklets (= 3.19.4) + - RNReanimated/reanimated (= 4.1.5) + - RNWorklets - SocketRocket - Yoga - - RNReanimated/reanimated (3.19.4): + - RNReanimated/reanimated (4.1.5): - boost - DoubleConversion - fast_float @@ -3411,10 +3411,11 @@ PODS: - ReactCodegen - ReactCommon/turbomodule/bridging - ReactCommon/turbomodule/core - - RNReanimated/reanimated/apple (= 3.19.4) + - RNReanimated/reanimated/apple (= 4.1.5) + - RNWorklets - SocketRocket - Yoga - - RNReanimated/reanimated/apple (3.19.4): + - RNReanimated/reanimated/apple (4.1.5): - boost - DoubleConversion - fast_float @@ -3441,9 +3442,40 @@ PODS: - ReactCodegen - ReactCommon/turbomodule/bridging - ReactCommon/turbomodule/core + - RNWorklets - SocketRocket - Yoga - - RNReanimated/worklets (3.19.4): + - RNScreens (4.16.0): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - hermes-engine + - RCT-Folly + - RCT-Folly/Fabric + - RCTRequired + - RCTTypeSafety + - React-Core + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-ImageManager + - React-jsi + - React-NativeModulesApple + - React-RCTFabric + - React-RCTImage + - React-renderercss + - React-rendererdebug + - React-utils + - ReactCodegen + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - RNScreens/common (= 4.16.0) + - SocketRocket + - Yoga + - RNScreens/common (4.16.0): - boost - DoubleConversion - fast_float @@ -3459,21 +3491,20 @@ PODS: - React-Fabric - React-featureflags - React-graphics - - React-hermes - React-ImageManager - React-jsi - React-NativeModulesApple - React-RCTFabric + - React-RCTImage - React-renderercss - React-rendererdebug - React-utils - ReactCodegen - ReactCommon/turbomodule/bridging - ReactCommon/turbomodule/core - - RNReanimated/worklets/apple (= 3.19.4) - SocketRocket - Yoga - - RNReanimated/worklets/apple (3.19.4): + - RNSentry (6.21.0): - boost - DoubleConversion - fast_float @@ -3500,9 +3531,10 @@ PODS: - ReactCodegen - ReactCommon/turbomodule/bridging - ReactCommon/turbomodule/core + - Sentry/HybridSDK (= 8.53.2) - SocketRocket - Yoga - - RNScreens (4.16.0): + - RNShare (12.0.9): - boost - DoubleConversion - fast_float @@ -3522,17 +3554,15 @@ PODS: - React-jsi - React-NativeModulesApple - React-RCTFabric - - React-RCTImage - React-renderercss - React-rendererdebug - React-utils - ReactCodegen - ReactCommon/turbomodule/bridging - ReactCommon/turbomodule/core - - RNScreens/common (= 4.16.0) - SocketRocket - Yoga - - RNScreens/common (4.16.0): + - RNSVG (15.14.0): - boost - DoubleConversion - fast_float @@ -3552,16 +3582,16 @@ PODS: - React-jsi - React-NativeModulesApple - React-RCTFabric - - React-RCTImage - React-renderercss - React-rendererdebug - React-utils - ReactCodegen - ReactCommon/turbomodule/bridging - ReactCommon/turbomodule/core + - RNSVG/common (= 15.14.0) - SocketRocket - Yoga - - RNSentry (6.21.0): + - RNSVG/common (15.14.0): - boost - DoubleConversion - fast_float @@ -3577,7 +3607,6 @@ PODS: - React-Fabric - React-featureflags - React-graphics - - React-hermes - React-ImageManager - React-jsi - React-NativeModulesApple @@ -3588,10 +3617,9 @@ PODS: - ReactCodegen - ReactCommon/turbomodule/bridging - ReactCommon/turbomodule/core - - Sentry/HybridSDK (= 8.53.2) - SocketRocket - Yoga - - RNShare (12.0.9): + - RNWorklets (0.6.1): - boost - DoubleConversion - fast_float @@ -3607,6 +3635,7 @@ PODS: - React-Fabric - React-featureflags - React-graphics + - React-hermes - React-ImageManager - React-jsi - React-NativeModulesApple @@ -3617,9 +3646,10 @@ PODS: - ReactCodegen - ReactCommon/turbomodule/bridging - ReactCommon/turbomodule/core + - RNWorklets/worklets (= 0.6.1) - SocketRocket - Yoga - - RNSVG (15.14.0): + - RNWorklets/worklets (0.6.1): - boost - DoubleConversion - fast_float @@ -3635,6 +3665,7 @@ PODS: - React-Fabric - React-featureflags - React-graphics + - React-hermes - React-ImageManager - React-jsi - React-NativeModulesApple @@ -3645,10 +3676,10 @@ PODS: - ReactCodegen - ReactCommon/turbomodule/bridging - ReactCommon/turbomodule/core - - RNSVG/common (= 15.14.0) + - RNWorklets/worklets/apple (= 0.6.1) - SocketRocket - Yoga - - RNSVG/common (15.14.0): + - RNWorklets/worklets/apple (0.6.1): - boost - DoubleConversion - fast_float @@ -3664,6 +3695,7 @@ PODS: - React-Fabric - React-featureflags - React-graphics + - React-hermes - React-ImageManager - React-jsi - React-NativeModulesApple @@ -3819,7 +3851,7 @@ DEPENDENCIES: - CocoaLumberjack (= 3.9.0) - DoubleConversion (from `../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec`) - EASClient (from `../node_modules/expo-eas-client/ios`) - - EXConstants (from `../node_modules/expo/node_modules/expo-constants/ios`) + - EXConstants (from `../node_modules/expo-constants/ios`) - EXJSONUtils (from `../node_modules/expo-json-utils/ios`) - EXManifests (from `../node_modules/expo-manifests/ios`) - Expecta (= 1.0.6) @@ -3969,6 +4001,7 @@ DEPENDENCIES: - "RNSentry (from `../node_modules/@sentry/react-native`)" - RNShare (from `../node_modules/react-native-share`) - RNSVG (from `../node_modules/react-native-svg`) + - RNWorklets (from `../node_modules/react-native-worklets`) - SDWebImage (= 5.19.1) - "segment-analytics-react-native (from `../node_modules/@segment/analytics-react-native`)" - sift-react-native (from `../node_modules/sift-react-native`) @@ -4084,7 +4117,7 @@ EXTERNAL SOURCES: EASClient: :path: "../node_modules/expo-eas-client/ios" EXConstants: - :path: "../node_modules/expo/node_modules/expo-constants/ios" + :path: "../node_modules/expo-constants/ios" EXJSONUtils: :path: "../node_modules/expo-json-utils/ios" EXManifests: @@ -4338,6 +4371,8 @@ EXTERNAL SOURCES: :path: "../node_modules/react-native-share" RNSVG: :path: "../node_modules/react-native-svg" + RNWorklets: + :path: "../node_modules/react-native-worklets" segment-analytics-react-native: :path: "../node_modules/@segment/analytics-react-native" sift-react-native: @@ -4552,11 +4587,12 @@ SPEC CHECKSUMS: RNNotifee: 5e3b271e8ea7456a36eec994085543c9adca9168 RNPermissions: 663a639fdc5aa46b853f514ae8a86dd4deb160cb RNReactNativeHapticFeedback: 7601768ee65ffc86fc93d7c30dd917031144ed3d - RNReanimated: 196d4b56ac1d7ffa2f168d4d36631f0add849456 + RNReanimated: b1f6ab0ddbe94e003e1e60fdbc03da9ffa103730 RNScreens: 0bbf16c074ae6bb1058a7bf2d1ae017f4306797c RNSentry: ab7ba8bd678713c94762d2d3f2087d47105b6cf3 RNShare: 1dba46787d6e5543e05655efaefa0e4bb98380d9 RNSVG: c5807de8e337c7a643f9bad2ecf48a15aefcc23c + RNWorklets: ab618bf7d1c7fd2cb793b9f0f39c3e29274b3ebf SDWebImage: 40b0b4053e36c660a764958bff99eed16610acbb SDWebImageAVIFCoder: afe194a084e851f70228e4be35ef651df0fc5c57 SDWebImageWebPCoder: e38c0a70396191361d60c092933e22c20d5b1380 diff --git a/package.json b/package.json index 5dcc33e8404..372aa3adcff 100644 --- a/package.json +++ b/package.json @@ -109,7 +109,7 @@ "dependencies": { "@artsy/cohesion": "4.336.0", "@artsy/icons": "3.63.0", - "@artsy/palette-mobile": "22.1.0--canary.424.5073.0", + "@artsy/palette-mobile": "22.1.0--canary.425.5080.0", "@artsy/to-title-case": "1.2.0", "@braze/react-native-sdk": "16.1.0", "@d11/react-native-fast-image": "8.12.0", @@ -183,7 +183,7 @@ "react-native-localize": "3.5.2", "react-native-pager-view": "6.7.1", "react-native-permissions": "3.8.4", - "react-native-reanimated": "3.19.4", + "react-native-reanimated": "4.1.5", "react-native-reanimated-zoom": "0.3.3", "react-native-render-html": "6.3.4", "react-native-safe-area-context": "5.6.1", @@ -195,6 +195,7 @@ "react-native-view-shot": "4.0.3", "react-native-vimeo-iframe": "1.2.1", "react-native-webview": "13.15.0", + "react-native-worklets": "0.6.1", "react-native-youtube-iframe": "^2.4.1", "react-relay": "18.2.0", "react-tracking": "9.3.2", @@ -355,5 +356,11 @@ "yarn prettier-write" ] }, + "reanimated": { + "staticFeatureFlags": { + "USE_COMMIT_HOOK_ONLY_FOR_REACT_COMMITS": true, + "DISABLE_COMMIT_PAUSING_MECHANISM": true + } + }, "packageManager": "yarn@4.10.3" } diff --git a/patches/react-native+0.81.5.patch b/patches/react-native+0.81.5.patch index 7f406048816..ea99383bc5e 100644 --- a/patches/react-native+0.81.5.patch +++ b/patches/react-native+0.81.5.patch @@ -12,4 +12,32 @@ index 6cdec32..8f7cf70 100644 + _listenerCount = 0; } } +diff --git a/node_modules/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDefaults.h b/node_modules/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDefaults.h +index e0742c9..77fab8b 100644 +--- a/node_modules/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDefaults.h ++++ b/node_modules/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDefaults.h +@@ -72,7 +72,7 @@ class ReactNativeFeatureFlagsDefaults : public ReactNativeFeatureFlagsProvider { + } + + bool enableCppPropsIteratorSetter() override { +- return false; ++ return true; + } + + bool enableCustomFocusSearchOnClippedElementsAndroid() override { +@@ -216,7 +216,7 @@ class ReactNativeFeatureFlagsDefaults : public ReactNativeFeatureFlagsProvider { + } + + bool preventShadowTreeCommitExhaustion() override { +- return false; ++ return true; + } + bool traceTurboModulePromiseRejectionsOnAndroid() override { +diff --git a/node_modules/react-native/scripts/.packager.env b/node_modules/react-native/scripts/.packager.env +new file mode 100644 +index 0000000..361f5fb +--- /dev/null ++++ b/node_modules/react-native/scripts/.packager.env +@@ -0,0 +1 @@ ++export RCT_METRO_PORT=8081 diff --git a/src/app/Components/ArtworkLists/components/ArtworkLists.tsx b/src/app/Components/ArtworkLists/components/ArtworkLists.tsx index 1dc13934376..6f5d81dcac7 100644 --- a/src/app/Components/ArtworkLists/components/ArtworkLists.tsx +++ b/src/app/Components/ArtworkLists/components/ArtworkLists.tsx @@ -132,8 +132,8 @@ export const ArtworkLists: FC = (props) => { return ( item.internalID} - renderItem={({ item }) => { + keyExtractor={(item: ArtworkList) => item.internalID} + renderItem={({ item }: { item: ArtworkList }) => { return ( @@ -32,7 +28,7 @@ export const Disappearable = forwardRef withTiming(0, { duration: 500 }, () => { - runOnJS(setShowContent)(false) + scheduleOnRN(setShowContent, false) }) ) }, diff --git a/src/app/Components/HeaderButton.tsx b/src/app/Components/HeaderButton.tsx index bbb7f2fe4c9..ca12d2ecef9 100644 --- a/src/app/Components/HeaderButton.tsx +++ b/src/app/Components/HeaderButton.tsx @@ -1,10 +1,10 @@ import { Touchable, useColor } from "@artsy/palette-mobile" import { useScreenDimensions } from "app/utils/hooks" import { StyleProp, ViewProps, ViewStyle } from "react-native" -import Animated, { AnimateProps, FadeIn, FadeOut } from "react-native-reanimated" +import Animated, { AnimatedProps, AnimatedStyle, FadeIn, FadeOut } from "react-native-reanimated" -interface HeaderButtonProps extends AnimateProps { - style?: StyleProp> +interface HeaderButtonProps extends AnimatedProps { + style?: StyleProp> shouldHide?: boolean position: "left" | "right" applySafeAreaTopInsets?: boolean diff --git a/src/app/Components/Swipeable/Swipeable.tsx b/src/app/Components/Swipeable/Swipeable.tsx index 549959c5619..7d3f1326c5f 100644 --- a/src/app/Components/Swipeable/Swipeable.tsx +++ b/src/app/Components/Swipeable/Swipeable.tsx @@ -6,12 +6,8 @@ import ReanimatedSwipeable, { SwipeableProps, } from "react-native-gesture-handler/ReanimatedSwipeable" import ReactNativeHapticFeedback from "react-native-haptic-feedback" -import Animated, { - runOnJS, - SharedValue, - useAnimatedStyle, - useSharedValue, -} from "react-native-reanimated" +import Animated, { SharedValue, useAnimatedStyle, useSharedValue } from "react-native-reanimated" +import { scheduleOnRN } from "react-native-worklets" const FRICTION = 1 const SWIPE_TO_INTERACT_THRESHOLD = 80 @@ -72,7 +68,7 @@ export const Swipeable = forwardRef(( const swipeDistance = width.get() + dragX.get() * FRICTION if (swipeDistance <= SWIPE_TO_INTERACT_THRESHOLD) { - runOnJS(handleSwipeToInteract)(swipeDistance) + scheduleOnRN(handleSwipeToInteract, swipeDistance) } return style diff --git a/src/app/Scenes/HomeView/hooks/useImpressionsTracking.ts b/src/app/Scenes/HomeView/hooks/useImpressionsTracking.ts index feecaa18ea9..e64db8a9a8b 100644 --- a/src/app/Scenes/HomeView/hooks/useImpressionsTracking.ts +++ b/src/app/Scenes/HomeView/hooks/useImpressionsTracking.ts @@ -4,7 +4,8 @@ import { useFeatureFlag } from "app/utils/hooks/useFeatureFlag" import { useViewabilityConfig } from "app/utils/hooks/useViewabilityConfig" import { useCallback, useEffect, useRef, useState } from "react" import { ViewToken } from "react-native" -import { runOnJS, useAnimatedReaction, useSharedValue } from "react-native-reanimated" +import { useAnimatedReaction, useSharedValue } from "react-native-reanimated" +import { scheduleOnRN } from "react-native-worklets" import { useTracking } from "react-tracking" type TrackableItem = { id: string; index: number | null } @@ -103,7 +104,7 @@ export const useItemsImpressionsTracking = ({ () => renderedItems.value, (currentItems) => { if (!__TEST__) { - runOnJS(trackItems)(currentItems) + scheduleOnRN(trackItems, currentItems) } }, [enableItemsViewsTracking, isInViewport, contextScreenOwnerType, contextModule] diff --git a/src/app/Scenes/InfiniteDiscovery/Components/Swiper/Swiper.tsx b/src/app/Scenes/InfiniteDiscovery/Components/Swiper/Swiper.tsx index 6761bd7222d..b92b4235e78 100644 --- a/src/app/Scenes/InfiniteDiscovery/Components/Swiper/Swiper.tsx +++ b/src/app/Scenes/InfiniteDiscovery/Components/Swiper/Swiper.tsx @@ -9,13 +9,13 @@ import { Easing, Extrapolation, interpolate, - runOnJS, useAnimatedReaction, useSharedValue, withDelay, withSequence, withTiming, } from "react-native-reanimated" +import { scheduleOnRN } from "react-native-worklets" type SwiperProps = { cards: InfiniteDiscoveryArtwork[] @@ -67,7 +67,7 @@ export const Swiper = forwardRef( () => _activeIndex.value, (current, previous) => { if (current !== previous) { - runOnJS(setActiveIndex)(current) + scheduleOnRN(setActiveIndex, current) } } ) @@ -126,7 +126,7 @@ export const Swiper = forwardRef( // if this is the first time that the user has navigated to this card, record it if (nextCardKey && !seenCardKeys.value.includes(nextCardKey) && onNewCardReached) { seenCardKeys.value = [...seenCardKeys.value, nextCardKey] - runOnJS(onNewCardReached)(nextCardKey) + scheduleOnRN(onNewCardReached, nextCardKey) } activeCardX.value = withTiming(-width, { duration: 300, easing: Easing.linear }, () => { @@ -136,7 +136,7 @@ export const Swiper = forwardRef( return }) - runOnJS(onSwipe)(swipedCardKey, nextCardKey) + scheduleOnRN(onSwipe, swipedCardKey, nextCardKey) } const swipeRight = () => { @@ -155,7 +155,7 @@ export const Swiper = forwardRef( swipedCardX.value = -width } ) - runOnJS(onRewind)(lastSwipedCardKey as Key) + scheduleOnRN(onRewind, lastSwipedCardKey as Key) return } @@ -180,7 +180,7 @@ export const Swiper = forwardRef( // Fetching more cards on the 3rd, 8th, 13th... swipe if (isSwipeLeft && !isLastCard && cards.length - 1 - _activeIndex.value === triggerIndex) { - runOnJS(onReachTriggerIndex)(_activeIndex.value + 1) + scheduleOnRN(onReachTriggerIndex, _activeIndex.value + 1) } const swipedCardIndex = _activeIndex.value diff --git a/src/app/Scenes/SavedSearchAlertsList/Components/SavedSearchListItem.tsx b/src/app/Scenes/SavedSearchAlertsList/Components/SavedSearchListItem.tsx index 632240f292b..82f5e76adde 100644 --- a/src/app/Scenes/SavedSearchAlertsList/Components/SavedSearchListItem.tsx +++ b/src/app/Scenes/SavedSearchAlertsList/Components/SavedSearchListItem.tsx @@ -10,11 +10,11 @@ import { Alert } from "react-native" import { Gesture, GestureDetector } from "react-native-gesture-handler" import Animated, { Easing, - runOnJS, useAnimatedStyle, useSharedValue, withTiming, } from "react-native-reanimated" +import { scheduleOnRN } from "react-native-worklets" import { graphql, useFragment } from "react-relay" import { useTracking } from "react-tracking" @@ -58,7 +58,7 @@ export const SavedSearchListItem: React.FC = (props) = .activeOffsetX([-5, 5]) .withTestId(`pan-alert-${alert.internalID}`) .onBegin(() => { - runOnJS(onSwipeBegin)(alert.internalID) + scheduleOnRN(onSwipeBegin, alert.internalID) }) .onChange((event) => { // Prevent swiping to the right diff --git a/yarn.lock b/yarn.lock index 1d6b6db6931..4f2c6bcd136 100644 --- a/yarn.lock +++ b/yarn.lock @@ -72,9 +72,9 @@ __metadata: languageName: node linkType: hard -"@artsy/palette-mobile@npm:22.1.0--canary.424.5073.0": - version: 22.1.0--canary.424.5073.0 - resolution: "@artsy/palette-mobile@npm:22.1.0--canary.424.5073.0" +"@artsy/palette-mobile@npm:22.1.0--canary.425.5080.0": + version: 22.1.0--canary.425.5080.0 + resolution: "@artsy/palette-mobile@npm:22.1.0--canary.425.5080.0" dependencies: "@artsy/icons": "npm:^3.49.0" "@artsy/palette-tokens": "npm:7.0.0" @@ -101,7 +101,7 @@ __metadata: react-native-reanimated: "*" react-native-svg: "*" styled-components: ">= 5" - checksum: 10c0/0af80c54bf14a58794bc51f603b2a4503da6f29b4f0b5853ac59b025405a91c2e8d1502796124b9853cd085368dc350443aa9564351b3fbfddb74aaab0144eb2 + checksum: 10c0/1a51c5286cf89f4d63d75dd22a9cf0dd24e82c9b8ffe81ada94d0b374c211360c8464398bc0721b5c91de35b099ccaa2c79ed0651242f1c809515abff65e1ae9 languageName: node linkType: hard @@ -3374,7 +3374,7 @@ __metadata: languageName: node linkType: hard -"@eslint-community/eslint-utils@npm:^4.2.0, @eslint-community/eslint-utils@npm:^4.4.0": +"@eslint-community/eslint-utils@npm:^4.2.0": version: 4.4.0 resolution: "@eslint-community/eslint-utils@npm:4.4.0" dependencies: @@ -3385,6 +3385,17 @@ __metadata: languageName: node linkType: hard +"@eslint-community/eslint-utils@npm:^4.4.0": + version: 4.9.0 + resolution: "@eslint-community/eslint-utils@npm:4.9.0" + dependencies: + eslint-visitor-keys: "npm:^3.4.3" + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + checksum: 10c0/8881e22d519326e7dba85ea915ac7a143367c805e6ba1374c987aa2fbdd09195cc51183d2da72c0e2ff388f84363e1b220fd0d19bef10c272c63455162176817 + languageName: node + linkType: hard + "@eslint-community/regexpp@npm:^4.10.0": version: 4.11.1 resolution: "@eslint-community/regexpp@npm:4.11.1" @@ -3704,7 +3715,7 @@ __metadata: languageName: node linkType: hard -"@expo/metro-config@npm:54.0.7, @expo/metro-config@npm:~54.0.7": +"@expo/metro-config@npm:54.0.7": version: 54.0.7 resolution: "@expo/metro-config@npm:54.0.7" dependencies: @@ -3738,6 +3749,40 @@ __metadata: languageName: node linkType: hard +"@expo/metro-config@npm:~54.0.7": + version: 54.0.9 + resolution: "@expo/metro-config@npm:54.0.9" + dependencies: + "@babel/code-frame": "npm:^7.20.0" + "@babel/core": "npm:^7.20.0" + "@babel/generator": "npm:^7.20.5" + "@expo/config": "npm:~12.0.10" + "@expo/env": "npm:~2.0.7" + "@expo/json-file": "npm:~10.0.7" + "@expo/metro": "npm:~54.1.0" + "@expo/spawn-async": "npm:^1.7.2" + browserslist: "npm:^4.25.0" + chalk: "npm:^4.1.0" + debug: "npm:^4.3.2" + dotenv: "npm:~16.4.5" + dotenv-expand: "npm:~11.0.6" + getenv: "npm:^2.0.0" + glob: "npm:^10.4.2" + hermes-parser: "npm:^0.29.1" + jsc-safe-url: "npm:^0.2.4" + lightningcss: "npm:^1.30.1" + minimatch: "npm:^9.0.0" + postcss: "npm:~8.4.32" + resolve-from: "npm:^5.0.0" + peerDependencies: + expo: "*" + peerDependenciesMeta: + expo: + optional: true + checksum: 10c0/6833c594082a347ba6df0ad6d107c6b8f21363a06b4f5e4ffbac91bbfc14cf1d62b2fbb335bb146dddcad8bd53d7a09920fe928cc7312f9e50bd9138b2d4aacc + languageName: node + linkType: hard + "@expo/metro@npm:~54.1.0": version: 54.1.0 resolution: "@expo/metro@npm:54.1.0" @@ -12566,7 +12611,7 @@ __metadata: dependencies: "@artsy/cohesion": "npm:4.336.0" "@artsy/icons": "npm:3.63.0" - "@artsy/palette-mobile": "npm:22.1.0--canary.424.5073.0" + "@artsy/palette-mobile": "npm:22.1.0--canary.425.5080.0" "@artsy/to-title-case": "npm:1.2.0" "@artsy/update-repo": "npm:0.7.0" "@babel/core": "npm:7.25.2" @@ -12742,7 +12787,7 @@ __metadata: react-native-pager-view: "npm:6.7.1" react-native-performance: "npm:5.1.4" react-native-permissions: "npm:3.8.4" - react-native-reanimated: "npm:3.19.4" + react-native-reanimated: "npm:4.1.5" react-native-reanimated-zoom: "npm:0.3.3" react-native-render-html: "npm:6.3.4" react-native-safe-area-context: "npm:5.6.1" @@ -12754,6 +12799,7 @@ __metadata: react-native-view-shot: "npm:4.0.3" react-native-vimeo-iframe: "npm:1.2.1" react-native-webview: "npm:13.15.0" + react-native-worklets: "npm:0.6.1" react-native-youtube-iframe: "npm:^2.4.1" react-relay: "npm:18.2.0" react-relay-network-modern: "npm:6.2.2" @@ -21588,16 +21634,6 @@ __metadata: languageName: node linkType: hard -"react-native-is-edge-to-edge@npm:1.1.7": - version: 1.1.7 - resolution: "react-native-is-edge-to-edge@npm:1.1.7" - peerDependencies: - react: "*" - react-native: "*" - checksum: 10c0/b7a37437f439b1e27a4d980de01994aa71b9091dc3ed00c21172d5505fb11978cd5ed3a43f97c89d502a3a08cf26e5cea6435b8d6e93d3557a92dd43563f7021 - languageName: node - linkType: hard - "react-native-is-edge-to-edge@npm:^1.2.1": version: 1.2.1 resolution: "react-native-is-edge-to-edge@npm:1.2.1" @@ -21726,27 +21762,18 @@ __metadata: languageName: node linkType: hard -"react-native-reanimated@npm:3.19.4": - version: 3.19.4 - resolution: "react-native-reanimated@npm:3.19.4" +"react-native-reanimated@npm:4.1.5": + version: 4.1.5 + resolution: "react-native-reanimated@npm:4.1.5" dependencies: - "@babel/plugin-transform-arrow-functions": "npm:^7.0.0-0" - "@babel/plugin-transform-class-properties": "npm:^7.0.0-0" - "@babel/plugin-transform-classes": "npm:^7.0.0-0" - "@babel/plugin-transform-nullish-coalescing-operator": "npm:^7.0.0-0" - "@babel/plugin-transform-optional-chaining": "npm:^7.0.0-0" - "@babel/plugin-transform-shorthand-properties": "npm:^7.0.0-0" - "@babel/plugin-transform-template-literals": "npm:^7.0.0-0" - "@babel/plugin-transform-unicode-regex": "npm:^7.0.0-0" - "@babel/preset-typescript": "npm:^7.16.7" - convert-source-map: "npm:^2.0.0" - invariant: "npm:^2.2.4" - react-native-is-edge-to-edge: "npm:1.1.7" + react-native-is-edge-to-edge: "npm:^1.2.1" + semver: "npm:7.7.2" peerDependencies: "@babel/core": ^7.0.0-0 react: "*" react-native: "*" - checksum: 10c0/265946c8056812685874cfd502e340ffc289128b90b897f274068608b624a757045686c987403f4557c9bf92753864b205e895dbc8111c7fc995b0943c7c5879 + react-native-worklets: ">=0.5.0" + checksum: 10c0/af4aeb17b23089819c8d1dbf7f06ac4e7116cf86c1350a44ee6b6b1d262ce4d93ee28b1e3ffc7ec12f2fd261a8d6436ecf4b771e47127ebdb2e5b509f177a2b5 languageName: node linkType: hard @@ -21885,6 +21912,29 @@ __metadata: languageName: node linkType: hard +"react-native-worklets@npm:0.6.1": + version: 0.6.1 + resolution: "react-native-worklets@npm:0.6.1" + dependencies: + "@babel/plugin-transform-arrow-functions": "npm:^7.0.0-0" + "@babel/plugin-transform-class-properties": "npm:^7.0.0-0" + "@babel/plugin-transform-classes": "npm:^7.0.0-0" + "@babel/plugin-transform-nullish-coalescing-operator": "npm:^7.0.0-0" + "@babel/plugin-transform-optional-chaining": "npm:^7.0.0-0" + "@babel/plugin-transform-shorthand-properties": "npm:^7.0.0-0" + "@babel/plugin-transform-template-literals": "npm:^7.0.0-0" + "@babel/plugin-transform-unicode-regex": "npm:^7.0.0-0" + "@babel/preset-typescript": "npm:^7.16.7" + convert-source-map: "npm:^2.0.0" + semver: "npm:7.7.2" + peerDependencies: + "@babel/core": ^7.0.0-0 + react: "*" + react-native: "*" + checksum: 10c0/bc3dcca00e287939aeb7ee7be501f15a0ac59c9351c60efafa89447d70e549e7f126705c154d92dd6e0cab924bf25f3c6ec1234a55a4daa9d3b3f26aa7871777 + languageName: node + linkType: hard + "react-native-youtube-iframe@npm:^2.4.1": version: 2.4.1 resolution: "react-native-youtube-iframe@npm:2.4.1" @@ -23036,6 +23086,15 @@ __metadata: languageName: node linkType: hard +"semver@npm:7.7.2, semver@npm:^7.7.2": + version: 7.7.2 + resolution: "semver@npm:7.7.2" + bin: + semver: bin/semver.js + checksum: 10c0/aca305edfbf2383c22571cb7714f48cadc7ac95371b4b52362fb8eeffdfbc0de0669368b82b2b15978f8848f01d7114da65697e56cd8c37b0dab8c58e543f9ea + languageName: node + linkType: hard + "semver@npm:^5.5.0": version: 5.7.2 resolution: "semver@npm:5.7.2" @@ -23074,15 +23133,6 @@ __metadata: languageName: node linkType: hard -"semver@npm:^7.7.2": - version: 7.7.2 - resolution: "semver@npm:7.7.2" - bin: - semver: bin/semver.js - checksum: 10c0/aca305edfbf2383c22571cb7714f48cadc7ac95371b4b52362fb8eeffdfbc0de0669368b82b2b15978f8848f01d7114da65697e56cd8c37b0dab8c58e543f9ea - languageName: node - linkType: hard - "send@npm:0.18.0": version: 0.18.0 resolution: "send@npm:0.18.0" From 50327a84ae7cd3ffa3fda3aede860f67e8c7e02c Mon Sep 17 00:00:00 2001 From: Mounir Dhahri Date: Fri, 14 Nov 2025 14:47:34 +0100 Subject: [PATCH 010/123] fix: artworks laayout on masonry --- src/app/Components/Artist/ArtistArtworks/ArtistArtworks.tsx | 2 ++ .../ArtworkGrids/MasonryInfiniteScrollArtworkGrid.tsx | 4 +++- src/app/Components/Gene/GeneArtworks.tsx | 2 ++ src/app/Scenes/ArtistSeries/ArtistSeriesArtworks.tsx | 2 ++ src/app/Scenes/Collection/Screens/CollectionArtworks.tsx | 2 ++ src/app/Scenes/Fair/Components/FairArtworks.tsx | 4 ++++ .../Components/InfiniteDiscoveryMoreWorksTab.tsx | 2 ++ src/app/Scenes/MyCollection/MyCollectionArtworks.tsx | 2 ++ src/app/Scenes/Partner/Components/PartnerArtwork.tsx | 2 ++ src/app/Scenes/Search/SearchArtworksGrid.tsx | 2 ++ src/app/Scenes/Tag/TagArtworks.tsx | 2 ++ 11 files changed, 25 insertions(+), 1 deletion(-) diff --git a/src/app/Components/Artist/ArtistArtworks/ArtistArtworks.tsx b/src/app/Components/Artist/ArtistArtworks/ArtistArtworks.tsx index ed01fe0e347..0cf466d4ca6 100644 --- a/src/app/Components/Artist/ArtistArtworks/ArtistArtworks.tsx +++ b/src/app/Components/Artist/ArtistArtworks/ArtistArtworks.tsx @@ -293,6 +293,8 @@ const ArtworksGrid: React.FC = ({ // need to pass zIndex: 1 here in order for the SubTabBar to // be visible above list content ListHeaderComponentStyle={{ zIndex: 1 }} + // This is needed to make sure we are getting the right column index for each item + optimizeItemArrangement={false} ListHeaderComponent={ <> diff --git a/src/app/Components/ArtworkGrids/MasonryInfiniteScrollArtworkGrid.tsx b/src/app/Components/ArtworkGrids/MasonryInfiniteScrollArtworkGrid.tsx index 9cce3315cfd..ead0d7d908c 100644 --- a/src/app/Components/ArtworkGrids/MasonryInfiniteScrollArtworkGrid.tsx +++ b/src/app/Components/ArtworkGrids/MasonryInfiniteScrollArtworkGrid.tsx @@ -160,7 +160,9 @@ export const MasonryInfiniteScrollArtworkGrid: React.FC, "numColumns" | "data" | "renderItem"> }, [shouldDisplayHeader, ListHeaderComponent, ListEmptyComponent, refreshControl, rest.onScroll]) diff --git a/src/app/Components/Gene/GeneArtworks.tsx b/src/app/Components/Gene/GeneArtworks.tsx index b364843db1c..36663781c91 100644 --- a/src/app/Components/Gene/GeneArtworks.tsx +++ b/src/app/Components/Gene/GeneArtworks.tsx @@ -128,6 +128,8 @@ export const GeneArtworksContainer: React.FC = ({ ge ) } + // This is needed to make sure we are getting the right column index for each item + optimizeItemArrangement={false} keyExtractor={(item) => item.id} renderItem={renderItem} onEndReached={loadMore} diff --git a/src/app/Scenes/ArtistSeries/ArtistSeriesArtworks.tsx b/src/app/Scenes/ArtistSeries/ArtistSeriesArtworks.tsx index 1b58dbb1abb..109f64254f8 100644 --- a/src/app/Scenes/ArtistSeries/ArtistSeriesArtworks.tsx +++ b/src/app/Scenes/ArtistSeries/ArtistSeriesArtworks.tsx @@ -125,6 +125,8 @@ export const ArtistSeriesArtworks: React.FC = ({ arti = ({ collecti numColumns={NUM_COLUMNS_MASONRY} keyboardShouldPersistTaps="handled" innerRef={gridRef} + // This is needed to make sure we are getting the right column index for each item + optimizeItemArrangement={false} ListEmptyComponent={ = ({ data={filteredArtworks} keyExtractor={(item) => item.id} numColumns={NUM_COLUMNS_MASONRY} + // This is needed to make sure we are getting the right column index for each item + optimizeItemArrangement={false} keyboardShouldPersistTaps="handled" ListEmptyComponent={ @@ -286,6 +288,8 @@ export const FairArtworksWithoutTabs: React.FC = ({ data={filteredArtworks} keyExtractor={(item) => item.id} numColumns={NUM_COLUMNS_MASONRY} + // This is needed to make sure we are getting the right column index for each item + optimizeItemArrangement={false} keyboardShouldPersistTaps="handled" ListEmptyComponent={ diff --git a/src/app/Scenes/InfiniteDiscovery/Components/InfiniteDiscoveryMoreWorksTab.tsx b/src/app/Scenes/InfiniteDiscovery/Components/InfiniteDiscoveryMoreWorksTab.tsx index d953c11448d..07aa5ecc7c4 100644 --- a/src/app/Scenes/InfiniteDiscovery/Components/InfiniteDiscoveryMoreWorksTab.tsx +++ b/src/app/Scenes/InfiniteDiscovery/Components/InfiniteDiscoveryMoreWorksTab.tsx @@ -72,6 +72,8 @@ export const MoreWorksTab: FC = ({ artworks: _artworks }) => data={artworks} numColumns={NUM_COLUMNS_MASONRY} keyboardShouldPersistTaps="handled" + // This is needed to make sure we are getting the right column index for each item + optimizeItemArrangement={false} keyExtractor={(item) => item?.internalID} ListEmptyComponent={} ListFooterComponent={() => ( diff --git a/src/app/Scenes/MyCollection/MyCollectionArtworks.tsx b/src/app/Scenes/MyCollection/MyCollectionArtworks.tsx index d47c5074bc8..7f7190f333b 100644 --- a/src/app/Scenes/MyCollection/MyCollectionArtworks.tsx +++ b/src/app/Scenes/MyCollection/MyCollectionArtworks.tsx @@ -119,6 +119,8 @@ export const MyCollectionArtworks: React.FC = ({ me } data={filteredArtworks} numColumns={NUM_COLUMNS_MASONRY} keyboardShouldPersistTaps="handled" + // This is needed to make sure we are getting the right column index for each item + optimizeItemArrangement={false} ListEmptyComponent={ diff --git a/src/app/Scenes/Partner/Components/PartnerArtwork.tsx b/src/app/Scenes/Partner/Components/PartnerArtwork.tsx index f61b2ffec2e..c50f8d3bf1b 100644 --- a/src/app/Scenes/Partner/Components/PartnerArtwork.tsx +++ b/src/app/Scenes/Partner/Components/PartnerArtwork.tsx @@ -92,6 +92,8 @@ export const PartnerArtwork: React.FC<{ data={artworks} numColumns={NUM_COLUMNS_MASONRY} keyboardShouldPersistTaps="handled" + // This is needed to make sure we are getting the right column index for each item + optimizeItemArrangement={false} ListEmptyComponent={ diff --git a/src/app/Scenes/Search/SearchArtworksGrid.tsx b/src/app/Scenes/Search/SearchArtworksGrid.tsx index c4fe5886576..f258cd6c445 100644 --- a/src/app/Scenes/Search/SearchArtworksGrid.tsx +++ b/src/app/Scenes/Search/SearchArtworksGrid.tsx @@ -114,6 +114,8 @@ const SearchArtworksGrid: React.FC = ({ viewer, relay, data={artworks} keyExtractor={(item) => item.id} numColumns={NUM_COLUMNS_MASONRY} + // This is needed to make sure we are getting the right column index for each item + optimizeItemArrangement={false} keyboardShouldPersistTaps="handled" keyboardDismissMode="on-drag" ListEmptyComponent={ diff --git a/src/app/Scenes/Tag/TagArtworks.tsx b/src/app/Scenes/Tag/TagArtworks.tsx index 1d9b86e529a..82c1dca5b88 100644 --- a/src/app/Scenes/Tag/TagArtworks.tsx +++ b/src/app/Scenes/Tag/TagArtworks.tsx @@ -121,6 +121,8 @@ const TagArtworks: React.FC = ({ tag, relay }) => { data={artworks} numColumns={NUM_COLUMNS_MASONRY} keyboardShouldPersistTaps="handled" + // This is needed to make sure we are getting the right column index for each item + optimizeItemArrangement={false} ListEmptyComponent={ initialArtworksTotal ? ( From 40679e4b3b44de9c362b2cf2be30997d48a93391 Mon Sep 17 00:00:00 2001 From: Mounir Dhahri Date: Fri, 14 Nov 2025 14:49:22 +0100 Subject: [PATCH 011/123] chore: upgrade gorhom --- package.json | 2 +- yarn.lock | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/package.json b/package.json index 372aa3adcff..8ae5ba23161 100644 --- a/package.json +++ b/package.json @@ -114,7 +114,7 @@ "@braze/react-native-sdk": "16.1.0", "@d11/react-native-fast-image": "8.12.0", "@expo/react-native-action-sheet": "4.1.1", - "@gorhom/bottom-sheet": "5.1.2", + "@gorhom/bottom-sheet": "5.2.6", "@gorhom/portal": "1.0.14", "@invertase/react-native-apple-authentication": "2.1.5", "@kesha-antonov/react-native-action-cable": "1.1.4", diff --git a/yarn.lock b/yarn.lock index 4f2c6bcd136..ae868bc4041 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4530,9 +4530,9 @@ __metadata: languageName: node linkType: hard -"@gorhom/bottom-sheet@npm:5.1.2": - version: 5.1.2 - resolution: "@gorhom/bottom-sheet@npm:5.1.2" +"@gorhom/bottom-sheet@npm:5.2.6": + version: 5.2.6 + resolution: "@gorhom/bottom-sheet@npm:5.2.6" dependencies: "@gorhom/portal": "npm:1.0.14" invariant: "npm:^2.2.4" @@ -4542,13 +4542,13 @@ __metadata: react: "*" react-native: "*" react-native-gesture-handler: ">=2.16.1" - react-native-reanimated: ">=3.16.0" + react-native-reanimated: "*" peerDependenciesMeta: "@types/react": optional: true "@types/react-native": optional: true - checksum: 10c0/3743cd8b8f6fde1f6460af045aea83dd6dff6a7b048165511d3b440a7b342b09c020d48fe8df7d35b61c03c670e4301bb3195381097253ad87a210df79759776 + checksum: 10c0/6caa4b963608bae84e4f8be17140e46b38d982c0c5531f98191d98185864dd1221e21cac464df3db6ce5e4733d03887ecb75bc0d044a25501e599604962aab80 languageName: node linkType: hard @@ -12625,7 +12625,7 @@ __metadata: "@braze/react-native-sdk": "npm:16.1.0" "@d11/react-native-fast-image": "npm:8.12.0" "@expo/react-native-action-sheet": "npm:4.1.1" - "@gorhom/bottom-sheet": "npm:5.1.2" + "@gorhom/bottom-sheet": "npm:5.2.6" "@gorhom/portal": "npm:1.0.14" "@invertase/react-native-apple-authentication": "npm:2.1.5" "@kesha-antonov/react-native-action-cable": "npm:1.1.4" From 1b11ad87fc8cb9dff7839061edc76ecbbc0b34d9 Mon Sep 17 00:00:00 2001 From: Mounir Dhahri Date: Fri, 14 Nov 2025 15:27:11 +0100 Subject: [PATCH 012/123] fix: infinite scroll issues --- package.json | 4 +- .../ArtworkCard/ArtworkCardBottomSheet.tsx | 40 ++++++++++++++----- .../ArtworkCardBottomSheetTabs.tsx | 2 +- .../Components/InfiniteDiscoveryHeader.tsx | 2 +- .../Components/Swiper/Swiper.tsx | 2 +- .../Components/ArtworkAutosuggestResults.tsx | 2 + yarn.lock | 20 +++++----- 7 files changed, 47 insertions(+), 25 deletions(-) diff --git a/package.json b/package.json index 8ae5ba23161..cd0b0c35570 100644 --- a/package.json +++ b/package.json @@ -109,12 +109,12 @@ "dependencies": { "@artsy/cohesion": "4.336.0", "@artsy/icons": "3.63.0", - "@artsy/palette-mobile": "22.1.0--canary.425.5080.0", + "@artsy/palette-mobile": "22.1.0--canary.425.5083.0", "@artsy/to-title-case": "1.2.0", "@braze/react-native-sdk": "16.1.0", "@d11/react-native-fast-image": "8.12.0", "@expo/react-native-action-sheet": "4.1.1", - "@gorhom/bottom-sheet": "5.2.6", + "@gorhom/bottom-sheet": "5.1.8", "@gorhom/portal": "1.0.14", "@invertase/react-native-apple-authentication": "2.1.5", "@kesha-antonov/react-native-action-cable": "1.1.4", diff --git a/src/app/Components/ArtworkCard/ArtworkCardBottomSheet.tsx b/src/app/Components/ArtworkCard/ArtworkCardBottomSheet.tsx index 6776805b21e..1305997d50a 100644 --- a/src/app/Components/ArtworkCard/ArtworkCardBottomSheet.tsx +++ b/src/app/Components/ArtworkCard/ArtworkCardBottomSheet.tsx @@ -1,10 +1,15 @@ import { ActionType, ContextModule, OwnerType } from "@artsy/cohesion" -import { useColor } from "@artsy/palette-mobile" -import BottomSheet from "@gorhom/bottom-sheet" +import { SkeletonText, Tabs, useColor } from "@artsy/palette-mobile" +import BottomSheet, { useBottomSheet } from "@gorhom/bottom-sheet" import { ArtworkCardBottomSheetBackdrop } from "app/Components/ArtworkCard/ArtworkCardBottomSheetBackdrop" import { ArtworkCardBottomSheetFooterQueryRenderer } from "app/Components/ArtworkCard/ArtworkCardBottomSheetFooter" import { ArtworkCardBottomSheetHandle } from "app/Components/ArtworkCard/ArtworkCardBottomSheetHandle" -import { ArtworkCardBottomSheetTabs } from "app/Components/ArtworkCard/ArtworkCardBottomSheetTabs" +import { + ArtworkCardBottomSheetTabs, + ArtworkCardBottomSheetTabsSkeleton, + TABS, +} from "app/Components/ArtworkCard/ArtworkCardBottomSheetTabs" +import { InfiniteDiscoveryAboutTheWorkTabSkeleton } from "app/Scenes/InfiniteDiscovery/Components/InfiniteDiscoveryAboutTheWorkTab" import { FC, useEffect, useState } from "react" import { Dimensions } from "react-native" import { useSafeAreaInsets } from "react-native-safe-area-context" @@ -24,6 +29,7 @@ export const ArtworkCardBottomSheet: FC = ({ artistIDs, contextModule, }) => { + const [isExpanded, setIsExpanded] = useState(false) const { bottom } = useSafeAreaInsets() const [footerVisible, setFooterVisible] = useState(true) const color = useColor() @@ -63,17 +69,31 @@ export const ArtworkCardBottomSheet: FC = ({ onChange={(index) => { const maxSnapPointIndex = 1 if (index === maxSnapPointIndex) { + setIsExpanded(true) trackEvent(tracks.swipedUp(artworkID, artworkSlug, contextModule)) + } else { + setIsExpanded(false) } }} > - + {!!isExpanded ? ( + + ) : ( + + + + + + {TABS[1].name} + + + )} ) diff --git a/src/app/Components/ArtworkCard/ArtworkCardBottomSheetTabs.tsx b/src/app/Components/ArtworkCard/ArtworkCardBottomSheetTabs.tsx index aacfa38eb0d..0db227e0146 100644 --- a/src/app/Components/ArtworkCard/ArtworkCardBottomSheetTabs.tsx +++ b/src/app/Components/ArtworkCard/ArtworkCardBottomSheetTabs.tsx @@ -16,7 +16,7 @@ interface ArtworkCardBottomSheetTabsProps { onTabChange: TabsContainerProps["onTabChange"] } -const TABS = [ +export const TABS = [ { name: "About the work", analyticsName: ContextModule.infiniteDiscoveryArtworkAboutTab, diff --git a/src/app/Scenes/InfiniteDiscovery/Components/InfiniteDiscoveryHeader.tsx b/src/app/Scenes/InfiniteDiscovery/Components/InfiniteDiscoveryHeader.tsx index fd8829c281f..cfaa5dd4a1a 100644 --- a/src/app/Scenes/InfiniteDiscovery/Components/InfiniteDiscoveryHeader.tsx +++ b/src/app/Scenes/InfiniteDiscovery/Components/InfiniteDiscoveryHeader.tsx @@ -63,7 +63,7 @@ export const InfiniteDiscoveryHeader: React.FC = ( } return ( - + ( const [cards, setCards] = useState(_cards) const swipedCardX = useSharedValue(-width) const _activeIndex = useSharedValue(0) - const [activeIndex, setActiveIndex] = useState(_activeIndex.value) + const [activeIndex, setActiveIndex] = useState(_activeIndex.get()) const swipedKeys = useSharedValue([]) // a list of cards that the user has seen diff --git a/src/app/Scenes/MyCollection/Screens/ArtworkForm/Components/ArtworkAutosuggestResults.tsx b/src/app/Scenes/MyCollection/Screens/ArtworkForm/Components/ArtworkAutosuggestResults.tsx index df2be14053d..db22e20eb9f 100644 --- a/src/app/Scenes/MyCollection/Screens/ArtworkForm/Components/ArtworkAutosuggestResults.tsx +++ b/src/app/Scenes/MyCollection/Screens/ArtworkForm/Components/ArtworkAutosuggestResults.tsx @@ -70,6 +70,8 @@ const ArtworkAutosuggestResults: React.FC = ({ showsVerticalScrollIndicator={false} data={artworks} numColumns={NUM_COLUMNS_MASONRY} + // This is needed to make sure we are getting the right column index for each item + optimizeItemArrangement={false} keyExtractor={(item) => item.id} keyboardShouldPersistTaps="handled" onEndReached={loadMore} diff --git a/yarn.lock b/yarn.lock index ae868bc4041..1636ef8d24d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -72,9 +72,9 @@ __metadata: languageName: node linkType: hard -"@artsy/palette-mobile@npm:22.1.0--canary.425.5080.0": - version: 22.1.0--canary.425.5080.0 - resolution: "@artsy/palette-mobile@npm:22.1.0--canary.425.5080.0" +"@artsy/palette-mobile@npm:22.1.0--canary.425.5083.0": + version: 22.1.0--canary.425.5083.0 + resolution: "@artsy/palette-mobile@npm:22.1.0--canary.425.5083.0" dependencies: "@artsy/icons": "npm:^3.49.0" "@artsy/palette-tokens": "npm:7.0.0" @@ -101,7 +101,7 @@ __metadata: react-native-reanimated: "*" react-native-svg: "*" styled-components: ">= 5" - checksum: 10c0/1a51c5286cf89f4d63d75dd22a9cf0dd24e82c9b8ffe81ada94d0b374c211360c8464398bc0721b5c91de35b099ccaa2c79ed0651242f1c809515abff65e1ae9 + checksum: 10c0/0a5b0980b6526372d340526b92cb8c60a83e365d9f5c781e5369af2ecb065a0a153fce935a7fcb37c3f23893d1a55853c38373eeef5715eb89c82530a1769acf languageName: node linkType: hard @@ -4530,9 +4530,9 @@ __metadata: languageName: node linkType: hard -"@gorhom/bottom-sheet@npm:5.2.6": - version: 5.2.6 - resolution: "@gorhom/bottom-sheet@npm:5.2.6" +"@gorhom/bottom-sheet@npm:5.1.8": + version: 5.1.8 + resolution: "@gorhom/bottom-sheet@npm:5.1.8" dependencies: "@gorhom/portal": "npm:1.0.14" invariant: "npm:^2.2.4" @@ -4548,7 +4548,7 @@ __metadata: optional: true "@types/react-native": optional: true - checksum: 10c0/6caa4b963608bae84e4f8be17140e46b38d982c0c5531f98191d98185864dd1221e21cac464df3db6ce5e4733d03887ecb75bc0d044a25501e599604962aab80 + checksum: 10c0/b1faa4bf495f2be814cc2477893fbe758282142b5e4a404eacabd0b76475975f17339fabce388719645a02c17ee999e86cffa26e847a40c9c38e98c5c342ee45 languageName: node linkType: hard @@ -12611,7 +12611,7 @@ __metadata: dependencies: "@artsy/cohesion": "npm:4.336.0" "@artsy/icons": "npm:3.63.0" - "@artsy/palette-mobile": "npm:22.1.0--canary.425.5080.0" + "@artsy/palette-mobile": "npm:22.1.0--canary.425.5083.0" "@artsy/to-title-case": "npm:1.2.0" "@artsy/update-repo": "npm:0.7.0" "@babel/core": "npm:7.25.2" @@ -12625,7 +12625,7 @@ __metadata: "@braze/react-native-sdk": "npm:16.1.0" "@d11/react-native-fast-image": "npm:8.12.0" "@expo/react-native-action-sheet": "npm:4.1.1" - "@gorhom/bottom-sheet": "npm:5.2.6" + "@gorhom/bottom-sheet": "npm:5.1.8" "@gorhom/portal": "npm:1.0.14" "@invertase/react-native-apple-authentication": "npm:2.1.5" "@kesha-antonov/react-native-action-cable": "npm:1.1.4" From 644b94abd8a333ecef6dc30906d8bc37473014b2 Mon Sep 17 00:00:00 2001 From: Mounir Dhahri Date: Fri, 14 Nov 2025 15:27:45 +0100 Subject: [PATCH 013/123] fix: temporarily disable launch-arguments --- src/app/App.tsx | 4 ++-- src/app/Components/ArtworkCard/ArtworkCardBottomSheet.tsx | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/app/App.tsx b/src/app/App.tsx index 5806535cc52..85499408261 100644 --- a/src/app/App.tsx +++ b/src/app/App.tsx @@ -5,7 +5,7 @@ import * as Sentry from "@sentry/react-native" import { Navigation } from "app/Navigation/Navigation" import { GlobalStore, unsafe__getEnvironment, unsafe_getDevToggle } from "app/store/GlobalStore" import { DevMenuWrapper } from "app/system/devTools/DevMenu/DevMenuWrapper" -import { useMaestroInitialization } from "app/system/devTools/useMaestroInitialization" +// import { useMaestroInitialization } from "app/system/devTools/useMaestroInitialization" import { useRageShakeDevMenu } from "app/system/devTools/useRageShakeDevMenu" import { setupSentry } from "app/system/errorReporting/setupSentry" import { usePushNotifications } from "app/system/notifications/usePushNotifications" @@ -73,7 +73,7 @@ const Main = () => { // Rozenite plugins end useRageShakeDevMenu() - useMaestroInitialization() + // useMaestroInitialization() useEffect(() => { const oss = Keys.OSS diff --git a/src/app/Components/ArtworkCard/ArtworkCardBottomSheet.tsx b/src/app/Components/ArtworkCard/ArtworkCardBottomSheet.tsx index 1305997d50a..66dfb954688 100644 --- a/src/app/Components/ArtworkCard/ArtworkCardBottomSheet.tsx +++ b/src/app/Components/ArtworkCard/ArtworkCardBottomSheet.tsx @@ -1,12 +1,11 @@ import { ActionType, ContextModule, OwnerType } from "@artsy/cohesion" import { SkeletonText, Tabs, useColor } from "@artsy/palette-mobile" -import BottomSheet, { useBottomSheet } from "@gorhom/bottom-sheet" +import BottomSheet from "@gorhom/bottom-sheet" import { ArtworkCardBottomSheetBackdrop } from "app/Components/ArtworkCard/ArtworkCardBottomSheetBackdrop" import { ArtworkCardBottomSheetFooterQueryRenderer } from "app/Components/ArtworkCard/ArtworkCardBottomSheetFooter" import { ArtworkCardBottomSheetHandle } from "app/Components/ArtworkCard/ArtworkCardBottomSheetHandle" import { ArtworkCardBottomSheetTabs, - ArtworkCardBottomSheetTabsSkeleton, TABS, } from "app/Components/ArtworkCard/ArtworkCardBottomSheetTabs" import { InfiniteDiscoveryAboutTheWorkTabSkeleton } from "app/Scenes/InfiniteDiscovery/Components/InfiniteDiscoveryAboutTheWorkTab" From f8f4438beb9d13d8907ef2789c9f190b30e351c6 Mon Sep 17 00:00:00 2001 From: Mounir Dhahri Date: Mon, 17 Nov 2025 12:11:23 +0100 Subject: [PATCH 014/123] Revert "chore: use date as android version code" This reverts commit 47a1f20739e795275549409a9c54173d752b6005. --- fastlane/Fastfile | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/fastlane/Fastfile b/fastlane/Fastfile index 4e9a0077d47..122a4c5e5b9 100644 --- a/fastlane/Fastfile +++ b/fastlane/Fastfile @@ -473,8 +473,7 @@ lane :get_next_android_build_version do file_dir = "#{Dir.pwd}/next_version_code.txt" puts "Writing next version code to: #{file_dir}" - puts "Generated date-based version code: #{next_version_code}" - File.write(file_dir, next_version_code) + File.write(file_dir, next_version_code.to_s) end desc 'Set some git properties on android for reading in builds' From a2f89a114f82fae73cde0e61000c38d0cb4e86c1 Mon Sep 17 00:00:00 2001 From: Mounir Dhahri Date: Wed, 19 Nov 2025 12:31:22 +0100 Subject: [PATCH 015/123] chore: use zeego menu instead of react-native-context-menu-view --- ios/Podfile.lock | 97 ++- package.json | 8 +- react-native.config.js | 10 + scripts/utils/flip-table | 65 ++ .../react-native-ios-context-menu/index.js | 8 + .../ArtworkGrids/ArtworkGridItem.tsx | 2 - .../ArtworkRail/ArtworkRailCard.tsx | 7 +- .../ContextMenu/ContextMenuArtwork.tsx | 61 +- .../ContextMenuArtworkPreviewCard.tsx | 8 +- yarn.lock | 721 +++++++++++++++++- 10 files changed, 920 insertions(+), 67 deletions(-) create mode 100644 react-native.config.js create mode 100755 scripts/utils/flip-table create mode 100644 src/__mocks__/react-native-ios-context-menu/index.js diff --git a/ios/Podfile.lock b/ios/Podfile.lock index e42efa39504..c6711fa7713 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -63,6 +63,10 @@ PODS: - CocoaLumberjack (3.9.0): - CocoaLumberjack/Core (= 3.9.0) - CocoaLumberjack/Core (3.9.0) + - ComputableLayout (0.7.0): + - DGSwiftUtilities (~> 0.11) + - ContextMenuAuxiliaryPreview (0.5.2): + - DGSwiftUtilities (~> 0.29) - CwlCatchException (2.2.1): - CwlCatchExceptionSupport (~> 2.2.1) - CwlCatchExceptionSupport (2.2.1) @@ -72,6 +76,7 @@ PODS: - CwlCatchException (~> 2.2.1) - CwlMachBadInstructionHandler (~> 2.2.2) - CwlPosixPreconditionTesting (~> 2.2.2) + - DGSwiftUtilities (0.47.0) - DoubleConversion (1.1.6) - EASClient (1.0.7): - ExpoModulesCore @@ -2135,7 +2140,7 @@ PODS: - ReactCommon/turbomodule/core - SocketRocket - Yoga - - react-native-blurhash (2.1.1): + - react-native-blurhash (2.1.2): - boost - DoubleConversion - fast_float @@ -2163,8 +2168,6 @@ PODS: - ReactCommon/turbomodule/core - SocketRocket - Yoga - - react-native-context-menu-view (1.11.0): - - React - react-native-cookies (6.0.11): - React-Core - react-native-document-picker (10.1.5): @@ -2242,6 +2245,74 @@ PODS: - React-Core - react-native-in-app-review (4.3.3): - React-Core + - react-native-ios-context-menu (3.2.0): + - boost + - ContextMenuAuxiliaryPreview (~> 0.5) + - DGSwiftUtilities + - DoubleConversion + - fast_float + - fmt + - glog + - hermes-engine + - RCT-Folly + - RCT-Folly/Fabric + - RCTRequired + - RCTTypeSafety + - React-Core + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-ImageManager + - React-jsi + - React-jsinspector + - React-jsinspectortracing + - react-native-ios-utilities + - React-NativeModulesApple + - React-RCTAppDelegate + - React-RCTFabric + - React-renderercss + - React-rendererdebug + - React-utils + - ReactCodegen + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - SocketRocket + - Yoga + - react-native-ios-utilities (5.2.0): + - boost + - ComputableLayout (~> 0.7) + - DGSwiftUtilities (~> 0.46) + - DoubleConversion + - fast_float + - fmt + - glog + - hermes-engine + - RCT-Folly + - RCT-Folly/Fabric + - RCTRequired + - RCTTypeSafety + - React-Core + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-ImageManager + - React-jsi + - React-jsinspector + - React-jsinspectortracing + - React-jsitooling + - React-NativeModulesApple + - React-RCTAppDelegate + - React-RCTFabric + - React-renderercss + - React-rendererdebug + - React-utils + - ReactCodegen + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - SocketRocket + - Yoga - react-native-keys (0.7.13): - boost - DoubleConversion @@ -3932,13 +4003,14 @@ DEPENDENCIES: - React-microtasksnativemodule (from `../node_modules/react-native/ReactCommon/react/nativemodule/microtasks`) - react-native-blob-util (from `../node_modules/react-native-blob-util`) - react-native-blurhash (from `../node_modules/react-native-blurhash`) - - react-native-context-menu-view (from `../node_modules/react-native-context-menu-view`) - "react-native-cookies (from `../node_modules/@react-native-cookies/cookies`)" - "react-native-document-picker (from `../node_modules/@react-native-documents/picker`)" - react-native-fbsdk-next (from `../node_modules/react-native-fbsdk-next`) - "react-native-geolocation (from `../node_modules/@react-native-community/geolocation`)" - react-native-get-random-values (from `../node_modules/react-native-get-random-values`) - react-native-in-app-review (from `../node_modules/react-native-in-app-review`) + - react-native-ios-context-menu (from `../node_modules/react-native-ios-context-menu`) + - react-native-ios-utilities (from `../node_modules/react-native-ios-utilities`) - react-native-keys (from `../node_modules/react-native-keys`) - react-native-launch-arguments (from `../node_modules/react-native-launch-arguments`) - "react-native-netinfo (from `../node_modules/@react-native-community/netinfo`)" @@ -4025,11 +4097,14 @@ SPEC REPOS: - AFNetworking - AppAuth - CocoaLumberjack + - ComputableLayout + - ContextMenuAuxiliaryPreview - CwlCatchException - CwlCatchExceptionSupport - CwlMachBadInstructionHandler - CwlPosixPreconditionTesting - CwlPreconditionTesting + - DGSwiftUtilities - Expecta - "Expecta+Snapshots" - FBAEMKit @@ -4233,8 +4308,6 @@ EXTERNAL SOURCES: :path: "../node_modules/react-native-blob-util" react-native-blurhash: :path: "../node_modules/react-native-blurhash" - react-native-context-menu-view: - :path: "../node_modules/react-native-context-menu-view" react-native-cookies: :path: "../node_modules/@react-native-cookies/cookies" react-native-document-picker: @@ -4247,6 +4320,10 @@ EXTERNAL SOURCES: :path: "../node_modules/react-native-get-random-values" react-native-in-app-review: :path: "../node_modules/react-native-in-app-review" + react-native-ios-context-menu: + :path: "../node_modules/react-native-ios-context-menu" + react-native-ios-utilities: + :path: "../node_modules/react-native-ios-utilities" react-native-keys: :path: "../node_modules/react-native-keys" react-native-launch-arguments: @@ -4413,11 +4490,14 @@ SPEC CHECKSUMS: BrazeUI: df3abdd46d2fe158cac147e9a8651d56be67a337 BVLinearGradient: cb006ba232a1f3e4f341bb62c42d1098c284da70 CocoaLumberjack: 5644158777912b7de7469fa881f8a3f259c2512a + ComputableLayout: c50faffac4ed9f8f05b0ce5e6f3a60df1f6042c8 + ContextMenuAuxiliaryPreview: 20be0be795b783b68f8792732eed4bed9f202c1c CwlCatchException: 7acc161b299a6de7f0a46a6ed741eae2c8b4d75a CwlCatchExceptionSupport: 54ccab8d8c78907b57f99717fb19d4cc3bce02dc CwlMachBadInstructionHandler: dae4fdd124d45c9910ac240287cc7b898f4502a1 CwlPosixPreconditionTesting: ecd095aa2129e740b44301c34571e8d85906fb88 CwlPreconditionTesting: 67a0047dd4de4382b93442c0e3f25207f984f35a + DGSwiftUtilities: 567f8d5ee618f0b7afb185b17aa45ff356315a0f DoubleConversion: cb417026b2400c8f53ae97020b2be961b59470cb EASClient: 68127f1248d2b25fdc82dbbfb17be95d1c4700be EXConstants: fd688cef4e401dcf798a021cfb5d87c890c30ba3 @@ -4522,14 +4602,15 @@ SPEC CHECKSUMS: React-Mapbuffer: 94f4264de2cb156960cd82b338a403f4653f2fd9 React-microtasksnativemodule: 6c4ee39a36958c39c97b074d28f360246a335e84 react-native-blob-util: 10c78778354e6c92b7a5afa4a1027cf0f18a9bb9 - react-native-blurhash: c1721deafe7a685088ea14ab4712a1c460be9fe4 - react-native-context-menu-view: dc362920c823ef1021e9a9ccd09d2e29c526852f + react-native-blurhash: 634dbcab9df4f325a67d4e8cff7388ef7b8b11ae react-native-cookies: b90327af903c8a7652100201d890c50a98697799 react-native-document-picker: f26f09a90cce65b5d682f21b511e8eb09a506fdc react-native-fbsdk-next: 52f81e60eb3e8e0e06cf9728b4572d3509ca9d01 react-native-geolocation: 95e48fe2687e5a8280103085372fa62c2297c5d6 react-native-get-random-values: d16467cf726c618e9c7a8c3c39c31faa2244bbba react-native-in-app-review: b3d1eed3d1596ebf6539804778272c4c65e4a400 + react-native-ios-context-menu: afeb0ca80a48e6d13a5d712928ca3b2fdbef037e + react-native-ios-utilities: d9ed1f5ea011650e9c7e9cb7c82272c1f0363e44 react-native-keys: 80dc5f204b236ff384be06a514294eb24c65bd1f react-native-launch-arguments: 165260aba9544f00c66fae3e136b11484d0cb49b react-native-netinfo: cec9c4e86083cb5b6aba0e0711f563e2fbbff187 diff --git a/package.json b/package.json index cd0b0c35570..fddce4d5141 100644 --- a/package.json +++ b/package.json @@ -165,10 +165,9 @@ "react-fps": "1.0.6", "react-native": "0.81.5", "react-native-blob-util": "0.19.11", - "react-native-blurhash": "2.1.1", + "react-native-blurhash": "^2.1.2", "react-native-bootsplash": "6.3.10", "react-native-collapsible-tab-view": "8.0.1", - "react-native-context-menu-view": "git+https://github.com/artsy/react-native-context-menu-view.git#brian/new-arch-woes", "react-native-device-info": "14.0.0", "react-native-fbsdk-next": "13.4.1", "react-native-gesture-handler": "2.28.0", @@ -176,6 +175,8 @@ "react-native-haptic-feedback": "1.13.0", "react-native-image-crop-picker": "0.51.0", "react-native-in-app-review": "4.3.3", + "react-native-ios-context-menu": "3.2.0", + "react-native-ios-utilities": "5.2.0", "react-native-keychain": "10.0.0", "react-native-keys": "0.7.13", "react-native-launch-arguments": "git+https://github.com/artsy/react-native-launch-arguments.git#v4.0.1-new-arch", @@ -212,7 +213,8 @@ "url": "0.11.3", "uuid": "10.0.0", "victory-native": "37.3.4", - "yup": "0.31.1" + "yup": "0.31.1", + "zeego": "^3.0.6" }, "devDependencies": { "@artsy/update-repo": "0.7.0", diff --git a/react-native.config.js b/react-native.config.js new file mode 100644 index 00000000000..72207d90c7c --- /dev/null +++ b/react-native.config.js @@ -0,0 +1,10 @@ +module.exports = { + dependencies: { + zeego: { + platforms: { + // Skip auto-linking here because we don't use it on android + android: null, + }, + }, + }, +} diff --git a/scripts/utils/flip-table b/scripts/utils/flip-table new file mode 100755 index 00000000000..1b38105f2c9 --- /dev/null +++ b/scripts/utils/flip-table @@ -0,0 +1,65 @@ +#!/usr/bin/env bash +set -euxo pipefail + + +# Clear local caches and build files + +echo 'Clear watchman (┛ಠ_ಠ)┛彡┻━┻' +watchman watch-del-all + +echo 'Clear gradle cache' +if [ -d node_modules ]; then + cd android + ./gradlew clean + cd - +fi + +echo 'Clear JS caches (┛ಠ_ಠ)┛彡┻━┻' +rm -rf .cache + +echo 'Clear gems (┛ಠ_ಠ)┛彡┻━┻' +rm -rf .vendor + +echo 'Clear node modules (┛ಠ_ಠ)┛彡┻━┻' +rm -rf node_modules + +echo 'Clear cocoapods directory (ノಠ益ಠ)ノ彡┻━┻' +rm -rf Pods + +echo 'Clear Xcode derived data (╯°□°)╯︵ ┻━┻' +# sometimes this fails on first try even with -rf +# but a second try takes it home +if ! rm -rf ~/Library/Developer/Xcode/DerivedData; then + rm -rf ~/Library/Developer/Xcode/DerivedData +fi + +echo 'Clear Xcode generated .env (╯°□°)╯︵ ┻━┻' +rm -rf ios/.xcode.env.local + +echo 'Reset yalc linked packages (ノಠдಠ)ノ︵┻━┻' +if command -v yalc &> /dev/null +then + yalc remove @artsy/palette-mobile +fi + +echo 'Clear relay, relay query map, jest, and metro caches (┛◉Д◉)┛彡┻━┻' +rm -rf "$TMPDIR"/RelayFindGraphQLTags-* +rm -rf data/complete.queryMap.json +rm -rf .cache +rm -rf "$TMPDIR"/metro* +rm -rf src/__generated__/*.graphql.ts + + + +echo 'Clear build artefacts (╯ರ ~ ರ)╯︵ ┻━┻' +find dist/ ! -name '.gitkeep' -type f -exec rm -f {} + + +echo 'Setup Assets' +# Required for yarn 4 +yarn install +yarn setup:artsy + +echo 'Reinstall dependencies ┬─┬ノ( º _ ºノ)' +yarn install:all + +./scripts/setup/update-echo diff --git a/src/__mocks__/react-native-ios-context-menu/index.js b/src/__mocks__/react-native-ios-context-menu/index.js new file mode 100644 index 00000000000..c0ac3490216 --- /dev/null +++ b/src/__mocks__/react-native-ios-context-menu/index.js @@ -0,0 +1,8 @@ +// Mock for Zeego's iOS dependency (react-native-ios-context-menu) +// This is a manual mock that Jest automatically uses when the module is imported +const { View } = require("react-native") + +module.exports = { + ContextMenuView: View, + ContextMenuButton: View, +} diff --git a/src/app/Components/ArtworkGrids/ArtworkGridItem.tsx b/src/app/Components/ArtworkGrids/ArtworkGridItem.tsx index 25f287fd4be..60ebf6c12b6 100644 --- a/src/app/Components/ArtworkGrids/ArtworkGridItem.tsx +++ b/src/app/Components/ArtworkGrids/ArtworkGridItem.tsx @@ -275,7 +275,6 @@ export const Artwork: React.FC = memo( haptic underlayColor={color("mono0")} onPress={handleTap} - // To prevent navigation when opening the long-press context menu, `onLongPress` & `delayLongPress` need to be set (https://github.com/mpiannucci/react-native-context-menu-view/issues/60) onLongPress={() => { // Adroid long press is tracked inside of the ContextMenuArtwork component if (contextScreenOwnerType && isIOS && enableContextMenuIOS) { @@ -288,7 +287,6 @@ export const Artwork: React.FC = memo( ) } }} - delayLongPress={400} navigationProps={navigationProps} to={artwork.href} testID={`artworkGridItem-${artwork.title}`} diff --git a/src/app/Components/ArtworkRail/ArtworkRailCard.tsx b/src/app/Components/ArtworkRail/ArtworkRailCard.tsx index 385d55045a1..56056ef772c 100644 --- a/src/app/Components/ArtworkRail/ArtworkRailCard.tsx +++ b/src/app/Components/ArtworkRail/ArtworkRailCard.tsx @@ -1,8 +1,7 @@ -import { Box, Flex, Spacer, useSpace } from "@artsy/palette-mobile" +import { Box, Flex, Spacer } from "@artsy/palette-mobile" import { ArtworkRailCard_artwork$key } from "__generated__/ArtworkRailCard_artwork.graphql" import { CreateArtworkAlertModal } from "app/Components/Artist/ArtistArtworks/CreateArtworkAlertModal" import { - ARTWORK_RAIL_CARD_IMAGE_HEIGHT, ARTWORK_RAIL_CARD_MAX_WIDTH, ARTWORK_RAIL_CARD_MIN_WIDTH, ArtworkRailCardImage, @@ -58,7 +57,6 @@ export const ArtworkRailCard: React.FC = memo( const isIOS = Platform.OS === "ios" const { trackEvent } = useTracking() - const space = useSpace() const [showCreateArtworkAlertModal, setShowCreateArtworkAlertModal] = useState(false) const disappearableRef = useRef(null) @@ -114,9 +112,6 @@ export const ArtworkRailCard: React.FC = memo( }} > { +interface ContextAction { + title: string + systemIcon: string onPress?: () => void } @@ -178,14 +189,11 @@ export const ContextMenuArtwork: React.FC { + const handleItemPress = (onPress?: () => void) => { if (haptic) { trigger?.(haptic === true ? "impactLight" : haptic) } - - const onPressToCall = contextActions[event.nativeEvent.index].onPress - - onPressToCall?.() + onPress?.() } const artworkPreviewComponent = ( @@ -197,20 +205,39 @@ export const ContextMenuArtwork: React.FC - {children} - + + {children} + + + + {() => artworkPreviewComponent(artwork, artworkDisplayProps)} + + + {contextActions.map((action, index) => ( + handleItemPress(action.onPress)} + > + + {action.title} + + ))} + + ) } diff --git a/src/app/Components/ContextMenu/ContextMenuArtworkPreviewCard.tsx b/src/app/Components/ContextMenu/ContextMenuArtworkPreviewCard.tsx index 6ca9173ab47..3b81393ce43 100644 --- a/src/app/Components/ContextMenu/ContextMenuArtworkPreviewCard.tsx +++ b/src/app/Components/ContextMenu/ContextMenuArtworkPreviewCard.tsx @@ -53,8 +53,14 @@ export const ContextMenuArtworkPreviewCard: React.FC + =16.8.0" + react-dom: ">=16.8.0" + checksum: 10c0/6654834a8e73ecbdbc6cad2ad8f7abc698ac7c1800ded4d61113525c591c03d2e3b59d3cf9205859221465ea38c87af4f9e6e204703c5b7a7e85332d1eef2e18 + languageName: node + linkType: hard + +"@floating-ui/utils@npm:^0.2.10": + version: 0.2.10 + resolution: "@floating-ui/utils@npm:0.2.10" + checksum: 10c0/e9bc2a1730ede1ee25843937e911ab6e846a733a4488623cd353f94721b05ec2c9ec6437613a2ac9379a94c2fd40c797a2ba6fa1df2716f5ce4aa6ddb1cf9ea4 + languageName: node + linkType: hard + "@gitbeaker/core@npm:^21.7.0": version: 21.7.0 resolution: "@gitbeaker/core@npm:21.7.0" @@ -5640,6 +5685,488 @@ __metadata: languageName: node linkType: hard +"@radix-ui/primitive@npm:1.1.3": + version: 1.1.3 + resolution: "@radix-ui/primitive@npm:1.1.3" + checksum: 10c0/88860165ee7066fa2c179f32ffcd3ee6d527d9dcdc0e8be85e9cb0e2c84834be8e3c1a976c74ba44b193f709544e12f54455d892b28e32f0708d89deda6b9f1d + languageName: node + linkType: hard + +"@radix-ui/react-arrow@npm:1.1.7": + version: 1.1.7 + resolution: "@radix-ui/react-arrow@npm:1.1.7" + dependencies: + "@radix-ui/react-primitive": "npm:2.1.3" + peerDependencies: + "@types/react": "*" + "@types/react-dom": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + "@types/react-dom": + optional: true + checksum: 10c0/c3b46766238b3ee2a394d8806a5141432361bf1425110c9f0dcf480bda4ebd304453a53f294b5399c6ee3ccfcae6fd544921fd01ddc379cf5942acdd7168664b + languageName: node + linkType: hard + +"@radix-ui/react-collection@npm:1.1.7": + version: 1.1.7 + resolution: "@radix-ui/react-collection@npm:1.1.7" + dependencies: + "@radix-ui/react-compose-refs": "npm:1.1.2" + "@radix-ui/react-context": "npm:1.1.2" + "@radix-ui/react-primitive": "npm:2.1.3" + "@radix-ui/react-slot": "npm:1.2.3" + peerDependencies: + "@types/react": "*" + "@types/react-dom": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + "@types/react-dom": + optional: true + checksum: 10c0/fa321a7300095508491f75414f02b243f0c3f179dc0728cfd115e2ea9f6f48f1516532b59f526d9ac81bbab63cd98a052074b4703ec0b9428fac945ebabec5fd + languageName: node + linkType: hard + +"@radix-ui/react-compose-refs@npm:1.1.2": + version: 1.1.2 + resolution: "@radix-ui/react-compose-refs@npm:1.1.2" + peerDependencies: + "@types/react": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 10c0/d36a9c589eb75d634b9b139c80f916aadaf8a68a7c1c4b8c6c6b88755af1a92f2e343457042089f04cc3f23073619d08bb65419ced1402e9d4e299576d970771 + languageName: node + linkType: hard + +"@radix-ui/react-context-menu@npm:^2.0.1": + version: 2.2.16 + resolution: "@radix-ui/react-context-menu@npm:2.2.16" + dependencies: + "@radix-ui/primitive": "npm:1.1.3" + "@radix-ui/react-context": "npm:1.1.2" + "@radix-ui/react-menu": "npm:2.1.16" + "@radix-ui/react-primitive": "npm:2.1.3" + "@radix-ui/react-use-callback-ref": "npm:1.1.1" + "@radix-ui/react-use-controllable-state": "npm:1.2.2" + peerDependencies: + "@types/react": "*" + "@types/react-dom": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + "@types/react-dom": + optional: true + checksum: 10c0/950f7559e65474a19145238cf44d744cb1e49be2221ff18436ba49b496b05ccf93bd3906aaa2c7ab76bc77daf694911a78442801e0053f57d2e57ebbfd281c49 + languageName: node + linkType: hard + +"@radix-ui/react-context@npm:1.1.2": + version: 1.1.2 + resolution: "@radix-ui/react-context@npm:1.1.2" + peerDependencies: + "@types/react": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 10c0/cece731f8cc25d494c6589cc681e5c01a93867d895c75889973afa1a255f163c286e390baa7bc028858eaabe9f6b57270d0ca6377356f652c5557c1c7a41ccce + languageName: node + linkType: hard + +"@radix-ui/react-direction@npm:1.1.1": + version: 1.1.1 + resolution: "@radix-ui/react-direction@npm:1.1.1" + peerDependencies: + "@types/react": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 10c0/7a89d9291f846a3105e45f4df98d6b7a08f8d7b30acdcd253005dc9db107ee83cbbebc9e47a9af1e400bcd47697f1511ceab23a399b0da854488fc7220482ac9 + languageName: node + linkType: hard + +"@radix-ui/react-dismissable-layer@npm:1.1.11": + version: 1.1.11 + resolution: "@radix-ui/react-dismissable-layer@npm:1.1.11" + dependencies: + "@radix-ui/primitive": "npm:1.1.3" + "@radix-ui/react-compose-refs": "npm:1.1.2" + "@radix-ui/react-primitive": "npm:2.1.3" + "@radix-ui/react-use-callback-ref": "npm:1.1.1" + "@radix-ui/react-use-escape-keydown": "npm:1.1.1" + peerDependencies: + "@types/react": "*" + "@types/react-dom": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + "@types/react-dom": + optional: true + checksum: 10c0/c825572a64073c4d3853702029979f6658770ffd6a98eabc4984e1dee1b226b4078a2a4dc7003f96475b438985e9b21a58e75f51db74dd06848dcae1f2d395dc + languageName: node + linkType: hard + +"@radix-ui/react-dropdown-menu@npm:^2.0.1": + version: 2.1.16 + resolution: "@radix-ui/react-dropdown-menu@npm:2.1.16" + dependencies: + "@radix-ui/primitive": "npm:1.1.3" + "@radix-ui/react-compose-refs": "npm:1.1.2" + "@radix-ui/react-context": "npm:1.1.2" + "@radix-ui/react-id": "npm:1.1.1" + "@radix-ui/react-menu": "npm:2.1.16" + "@radix-ui/react-primitive": "npm:2.1.3" + "@radix-ui/react-use-controllable-state": "npm:1.2.2" + peerDependencies: + "@types/react": "*" + "@types/react-dom": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + "@types/react-dom": + optional: true + checksum: 10c0/8caaa8dd791ccb284568720adafa59855e13860aa29eb20e10a04ba671cbbfa519a4c5d3a339a4d9fb08009eeb1065f4a8b5c3c8ef45e9753161cc560106b935 + languageName: node + linkType: hard + +"@radix-ui/react-focus-guards@npm:1.1.3": + version: 1.1.3 + resolution: "@radix-ui/react-focus-guards@npm:1.1.3" + peerDependencies: + "@types/react": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 10c0/0bab65eb8d7e4f72f685d63de7fbba2450e3cb15ad6a20a16b42195e9d335c576356f5a47cb58d1ffc115393e46d7b14b12c5d4b10029b0ec090861255866985 + languageName: node + linkType: hard + +"@radix-ui/react-focus-scope@npm:1.1.7": + version: 1.1.7 + resolution: "@radix-ui/react-focus-scope@npm:1.1.7" + dependencies: + "@radix-ui/react-compose-refs": "npm:1.1.2" + "@radix-ui/react-primitive": "npm:2.1.3" + "@radix-ui/react-use-callback-ref": "npm:1.1.1" + peerDependencies: + "@types/react": "*" + "@types/react-dom": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + "@types/react-dom": + optional: true + checksum: 10c0/8a6071331bdeeb79b223463de75caf759b8ad19339cab838e537b8dbb2db236891a1f4df252445c854d375d43d9d315dfcce0a6b01553a2984ec372bb8f1300e + languageName: node + linkType: hard + +"@radix-ui/react-id@npm:1.1.1": + version: 1.1.1 + resolution: "@radix-ui/react-id@npm:1.1.1" + dependencies: + "@radix-ui/react-use-layout-effect": "npm:1.1.1" + peerDependencies: + "@types/react": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 10c0/7d12e76818763d592c331277ef62b197e2e64945307e650bd058f0090e5ae48bbd07691b23b7e9e977901ef4eadcb3e2d5eaeb17a13859083384be83fc1292c7 + languageName: node + linkType: hard + +"@radix-ui/react-menu@npm:2.1.16": + version: 2.1.16 + resolution: "@radix-ui/react-menu@npm:2.1.16" + dependencies: + "@radix-ui/primitive": "npm:1.1.3" + "@radix-ui/react-collection": "npm:1.1.7" + "@radix-ui/react-compose-refs": "npm:1.1.2" + "@radix-ui/react-context": "npm:1.1.2" + "@radix-ui/react-direction": "npm:1.1.1" + "@radix-ui/react-dismissable-layer": "npm:1.1.11" + "@radix-ui/react-focus-guards": "npm:1.1.3" + "@radix-ui/react-focus-scope": "npm:1.1.7" + "@radix-ui/react-id": "npm:1.1.1" + "@radix-ui/react-popper": "npm:1.2.8" + "@radix-ui/react-portal": "npm:1.1.9" + "@radix-ui/react-presence": "npm:1.1.5" + "@radix-ui/react-primitive": "npm:2.1.3" + "@radix-ui/react-roving-focus": "npm:1.1.11" + "@radix-ui/react-slot": "npm:1.2.3" + "@radix-ui/react-use-callback-ref": "npm:1.1.1" + aria-hidden: "npm:^1.2.4" + react-remove-scroll: "npm:^2.6.3" + peerDependencies: + "@types/react": "*" + "@types/react-dom": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + "@types/react-dom": + optional: true + checksum: 10c0/27516b2b987fa9181c4da8645000af8f60691866a349d7a46b9505fa7d2e9d92b9e364db4f7305d08e9e57d0e1afc8df8354f8ee3c12aa05c0100c16b0e76c27 + languageName: node + linkType: hard + +"@radix-ui/react-popper@npm:1.2.8": + version: 1.2.8 + resolution: "@radix-ui/react-popper@npm:1.2.8" + dependencies: + "@floating-ui/react-dom": "npm:^2.0.0" + "@radix-ui/react-arrow": "npm:1.1.7" + "@radix-ui/react-compose-refs": "npm:1.1.2" + "@radix-ui/react-context": "npm:1.1.2" + "@radix-ui/react-primitive": "npm:2.1.3" + "@radix-ui/react-use-callback-ref": "npm:1.1.1" + "@radix-ui/react-use-layout-effect": "npm:1.1.1" + "@radix-ui/react-use-rect": "npm:1.1.1" + "@radix-ui/react-use-size": "npm:1.1.1" + "@radix-ui/rect": "npm:1.1.1" + peerDependencies: + "@types/react": "*" + "@types/react-dom": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + "@types/react-dom": + optional: true + checksum: 10c0/48e3f13eac3b8c13aca8ded37d74db17e1bb294da8d69f142ab6b8719a06c3f90051668bed64520bf9f3abdd77b382ce7ce209d056bb56137cecc949b69b421c + languageName: node + linkType: hard + +"@radix-ui/react-portal@npm:1.1.9": + version: 1.1.9 + resolution: "@radix-ui/react-portal@npm:1.1.9" + dependencies: + "@radix-ui/react-primitive": "npm:2.1.3" + "@radix-ui/react-use-layout-effect": "npm:1.1.1" + peerDependencies: + "@types/react": "*" + "@types/react-dom": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + "@types/react-dom": + optional: true + checksum: 10c0/45b432497c722720c72c493a29ef6085bc84b50eafe79d48b45c553121b63e94f9cdb77a3a74b9c49126f8feb3feee009fe400d48b7759d3552396356b192cd7 + languageName: node + linkType: hard + +"@radix-ui/react-presence@npm:1.1.5": + version: 1.1.5 + resolution: "@radix-ui/react-presence@npm:1.1.5" + dependencies: + "@radix-ui/react-compose-refs": "npm:1.1.2" + "@radix-ui/react-use-layout-effect": "npm:1.1.1" + peerDependencies: + "@types/react": "*" + "@types/react-dom": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + "@types/react-dom": + optional: true + checksum: 10c0/d0e61d314250eeaef5369983cb790701d667f51734bafd98cf759072755562018052c594e6cdc5389789f4543cb0a4d98f03ff4e8f37338d6b5bf51a1700c1d1 + languageName: node + linkType: hard + +"@radix-ui/react-primitive@npm:2.1.3": + version: 2.1.3 + resolution: "@radix-ui/react-primitive@npm:2.1.3" + dependencies: + "@radix-ui/react-slot": "npm:1.2.3" + peerDependencies: + "@types/react": "*" + "@types/react-dom": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + "@types/react-dom": + optional: true + checksum: 10c0/fdff9b84913bb4172ef6d3af7442fca5f9bba5f2709cba08950071f819d7057aec3a4a2d9ef44cf9cbfb8014d02573c6884a04cff175895823aaef809ebdb034 + languageName: node + linkType: hard + +"@radix-ui/react-roving-focus@npm:1.1.11": + version: 1.1.11 + resolution: "@radix-ui/react-roving-focus@npm:1.1.11" + dependencies: + "@radix-ui/primitive": "npm:1.1.3" + "@radix-ui/react-collection": "npm:1.1.7" + "@radix-ui/react-compose-refs": "npm:1.1.2" + "@radix-ui/react-context": "npm:1.1.2" + "@radix-ui/react-direction": "npm:1.1.1" + "@radix-ui/react-id": "npm:1.1.1" + "@radix-ui/react-primitive": "npm:2.1.3" + "@radix-ui/react-use-callback-ref": "npm:1.1.1" + "@radix-ui/react-use-controllable-state": "npm:1.2.2" + peerDependencies: + "@types/react": "*" + "@types/react-dom": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + "@types/react-dom": + optional: true + checksum: 10c0/2cd43339c36e89a3bf1db8aab34b939113dfbde56bf3a33df2d74757c78c9489b847b1962f1e2441c67e41817d120cb6177943e0f655f47bc1ff8e44fd55b1a2 + languageName: node + linkType: hard + +"@radix-ui/react-slot@npm:1.2.3": + version: 1.2.3 + resolution: "@radix-ui/react-slot@npm:1.2.3" + dependencies: + "@radix-ui/react-compose-refs": "npm:1.1.2" + peerDependencies: + "@types/react": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 10c0/5913aa0d760f505905779515e4b1f0f71a422350f077cc8d26d1aafe53c97f177fec0e6d7fbbb50d8b5e498aa9df9f707ca75ae3801540c283b26b0136138eef + languageName: node + linkType: hard + +"@radix-ui/react-use-callback-ref@npm:1.1.1": + version: 1.1.1 + resolution: "@radix-ui/react-use-callback-ref@npm:1.1.1" + peerDependencies: + "@types/react": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 10c0/5f6aff8592dea6a7e46589808912aba3fb3b626cf6edd2b14f01638b61dbbe49eeb9f67cd5601f4c15b2fb547b9a7e825f7c4961acd4dd70176c969ae405f8d8 + languageName: node + linkType: hard + +"@radix-ui/react-use-controllable-state@npm:1.2.2": + version: 1.2.2 + resolution: "@radix-ui/react-use-controllable-state@npm:1.2.2" + dependencies: + "@radix-ui/react-use-effect-event": "npm:0.0.2" + "@radix-ui/react-use-layout-effect": "npm:1.1.1" + peerDependencies: + "@types/react": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 10c0/f55c4b06e895293aed4b44c9ef26fb24432539f5346fcd6519c7745800535b571058685314e83486a45bf61dc83887e24826490d3068acc317fb0a9010516e63 + languageName: node + linkType: hard + +"@radix-ui/react-use-effect-event@npm:0.0.2": + version: 0.0.2 + resolution: "@radix-ui/react-use-effect-event@npm:0.0.2" + dependencies: + "@radix-ui/react-use-layout-effect": "npm:1.1.1" + peerDependencies: + "@types/react": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 10c0/e84ff72a3e76c5ae9c94941028bb4b6472f17d4104481b9eab773deab3da640ecea035e54da9d6f4df8d84c18ef6913baf92b7511bee06930dc58bd0c0add417 + languageName: node + linkType: hard + +"@radix-ui/react-use-escape-keydown@npm:1.1.1": + version: 1.1.1 + resolution: "@radix-ui/react-use-escape-keydown@npm:1.1.1" + dependencies: + "@radix-ui/react-use-callback-ref": "npm:1.1.1" + peerDependencies: + "@types/react": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 10c0/bff53be99e940fef1d3c4df7d560e1d9133182e5a98336255d3063327d1d3dd4ec54a95dc5afe15cca4fb6c184f0a956c70de2815578c318cf995a7f9beabaa1 + languageName: node + linkType: hard + +"@radix-ui/react-use-layout-effect@npm:1.1.1": + version: 1.1.1 + resolution: "@radix-ui/react-use-layout-effect@npm:1.1.1" + peerDependencies: + "@types/react": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 10c0/9f98fdaba008dfc58050de60a77670b885792df473cf82c1cef8daee919a5dd5a77d270209f5f0b0abfaac78cb1627396e3ff56c81b735be550409426fe8b040 + languageName: node + linkType: hard + +"@radix-ui/react-use-rect@npm:1.1.1": + version: 1.1.1 + resolution: "@radix-ui/react-use-rect@npm:1.1.1" + dependencies: + "@radix-ui/rect": "npm:1.1.1" + peerDependencies: + "@types/react": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 10c0/271711404c05c589c8dbdaa748749e7daf44bcc6bffc9ecd910821c3ebca0ee245616cf5b39653ce690f53f875c3836fd3f36f51ab1c628273b6db599eee4864 + languageName: node + linkType: hard + +"@radix-ui/react-use-size@npm:1.1.1": + version: 1.1.1 + resolution: "@radix-ui/react-use-size@npm:1.1.1" + dependencies: + "@radix-ui/react-use-layout-effect": "npm:1.1.1" + peerDependencies: + "@types/react": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 10c0/851d09a816f44282e0e9e2147b1b571410174cc048703a50c4fa54d672de994fd1dfff1da9d480ecfd12c77ae8f48d74f01adaf668f074156b8cd0043c6c21d8 + languageName: node + linkType: hard + +"@radix-ui/rect@npm:1.1.1": + version: 1.1.1 + resolution: "@radix-ui/rect@npm:1.1.1" + checksum: 10c0/0dac4f0f15691199abe6a0e067821ddd9d0349c0c05f39834e4eafc8403caf724106884035ae91bbc826e10367e6a5672e7bec4d4243860fa7649de246b1f60b + languageName: node + linkType: hard + "@react-native-async-storage/async-storage@npm:2.2.0": version: 2.2.0 resolution: "@react-native-async-storage/async-storage@npm:2.2.0" @@ -9811,6 +10338,15 @@ __metadata: languageName: node linkType: hard +"aria-hidden@npm:^1.2.4": + version: 1.2.6 + resolution: "aria-hidden@npm:1.2.6" + dependencies: + tslib: "npm:^2.0.0" + checksum: 10c0/7720cb539497a9f760f68f98a4b30f22c6767aa0e72fa7d58279f7c164e258fc38b2699828f8de881aab0fc8e9c56d1313a3f1a965046fc0381a554dbc72b54a + languageName: node + linkType: hard + "arr-diff@npm:^4.0.0": version: 4.0.0 resolution: "arr-diff@npm:4.0.0" @@ -12376,6 +12912,13 @@ __metadata: languageName: node linkType: hard +"detect-node-es@npm:^1.1.0": + version: 1.1.0 + resolution: "detect-node-es@npm:1.1.0" + checksum: 10c0/e562f00de23f10c27d7119e1af0e7388407eb4b06596a25f6d79a360094a109ff285de317f02b090faae093d314cf6e73ac3214f8a5bb3a0def5bece94557fbe + languageName: node + linkType: hard + "diff-sequences@npm:^29.6.3": version: 29.6.3 resolution: "diff-sequences@npm:29.6.3" @@ -12768,10 +13311,9 @@ __metadata: react-fps: "npm:1.0.6" react-native: "npm:0.81.5" react-native-blob-util: "npm:0.19.11" - react-native-blurhash: "npm:2.1.1" + react-native-blurhash: "npm:^2.1.2" react-native-bootsplash: "npm:6.3.10" react-native-collapsible-tab-view: "npm:8.0.1" - react-native-context-menu-view: "git+https://github.com/artsy/react-native-context-menu-view.git#brian/new-arch-woes" react-native-device-info: "npm:14.0.0" react-native-fbsdk-next: "npm:13.4.1" react-native-gesture-handler: "npm:2.28.0" @@ -12779,6 +13321,8 @@ __metadata: react-native-haptic-feedback: "npm:1.13.0" react-native-image-crop-picker: "npm:0.51.0" react-native-in-app-review: "npm:4.3.3" + react-native-ios-context-menu: "npm:3.2.0" + react-native-ios-utilities: "npm:5.2.0" react-native-keychain: "npm:10.0.0" react-native-keys: "npm:0.7.13" react-native-launch-arguments: "git+https://github.com/artsy/react-native-launch-arguments.git#v4.0.1-new-arch" @@ -12831,6 +13375,7 @@ __metadata: victory-native: "npm:37.3.4" yargs: "npm:17.7.2" yup: "npm:0.31.1" + zeego: "npm:^3.0.6" languageName: unknown linkType: soft @@ -15155,6 +15700,13 @@ __metadata: languageName: node linkType: hard +"get-nonce@npm:^1.0.0": + version: 1.0.1 + resolution: "get-nonce@npm:1.0.1" + checksum: 10c0/2d7df55279060bf0568549e1ffc9b84bc32a32b7541675ca092dce56317cdd1a59a98dcc4072c9f6a980779440139a3221d7486f52c488e69dc0fd27b1efb162 + languageName: node + linkType: hard + "get-proto@npm:^1.0.1": version: 1.0.1 resolution: "get-proto@npm:1.0.1" @@ -21486,17 +22038,7 @@ __metadata: languageName: node linkType: hard -"react-native-blurhash@npm:2.1.1": - version: 2.1.1 - resolution: "react-native-blurhash@npm:2.1.1" - peerDependencies: - react: ">=16.8.1" - react-native: ">=0.60.0-rc.0 <1.0.x" - checksum: 10c0/9ffefa93bb7f8578020b274112e9d5e40b152c94a7828c45e8f7ef71a20794e021accc6dd175857e334ae4727e5bc4d5cf7cf069c9b01e454478e8e31d912336 - languageName: node - linkType: hard - -"react-native-blurhash@npm:2.1.2": +"react-native-blurhash@npm:2.1.2, react-native-blurhash@npm:^2.1.2": version: 2.1.2 resolution: "react-native-blurhash@npm:2.1.2" peerDependencies: @@ -21551,16 +22093,6 @@ __metadata: languageName: node linkType: hard -"react-native-context-menu-view@git+https://github.com/artsy/react-native-context-menu-view.git#brian/new-arch-woes": - version: 1.11.0 - resolution: "react-native-context-menu-view@https://github.com/artsy/react-native-context-menu-view.git#commit=8332543bf6534660d0781fa6b0d085b8d42aefc9" - peerDependencies: - react: ^16.8.1 || ^17.0.0 || ^18.0.0 - react-native: ">=0.60.0-rc.0 <1.0.x" - checksum: 10c0/2acd060207d08bcf1e57aeb3639a85c507c97da4b1ee7f37d73b4a51124e314a13534819e1b693c9ea0b5a3bd0d468dd1702b80691a1632a91baf6689ac9c8b7 - languageName: node - linkType: hard - "react-native-device-info@npm:14.0.0": version: 14.0.0 resolution: "react-native-device-info@npm:14.0.0" @@ -21634,6 +22166,29 @@ __metadata: languageName: node linkType: hard +"react-native-ios-context-menu@npm:3.2.0": + version: 3.2.0 + resolution: "react-native-ios-context-menu@npm:3.2.0" + dependencies: + "@dominicstop/ts-event-emitter": "npm:^1.1.0" + peerDependencies: + react: "*" + react-native: "*" + react-native-ios-utilities: "*" + checksum: 10c0/1745b5b9722914a7c70cb1abf3111be89f9c67573a545a57c6d621d7ddb6e79e3371e7a1bf0dc1e9005e1013dd70f11f5e1d0ba980ae906af267e5a5755feae0 + languageName: node + linkType: hard + +"react-native-ios-utilities@npm:5.2.0": + version: 5.2.0 + resolution: "react-native-ios-utilities@npm:5.2.0" + peerDependencies: + react: "*" + react-native: "*" + checksum: 10c0/d5d7dadd0aa7bc66ab2cdf5cc39bd38e41f1f7011f34f3a6e7da25fb3e01a126848d415e0605859791ff0675e35a7aec0a3eb888389f25ab7508c72d2d9b8728 + languageName: node + linkType: hard + "react-native-is-edge-to-edge@npm:^1.2.1": version: 1.2.1 resolution: "react-native-is-edge-to-edge@npm:1.2.1" @@ -22039,6 +22594,57 @@ __metadata: languageName: node linkType: hard +"react-remove-scroll-bar@npm:^2.3.7": + version: 2.3.8 + resolution: "react-remove-scroll-bar@npm:2.3.8" + dependencies: + react-style-singleton: "npm:^2.2.2" + tslib: "npm:^2.0.0" + peerDependencies: + "@types/react": "*" + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 10c0/9a0675c66cbb52c325bdbfaed80987a829c4504cefd8ff2dd3b6b3afc9a1500b8ec57b212e92c1fb654396d07bbe18830a8146fe77677d2a29ce40b5e1f78654 + languageName: node + linkType: hard + +"react-remove-scroll@npm:^2.6.3": + version: 2.7.1 + resolution: "react-remove-scroll@npm:2.7.1" + dependencies: + react-remove-scroll-bar: "npm:^2.3.7" + react-style-singleton: "npm:^2.2.3" + tslib: "npm:^2.1.0" + use-callback-ref: "npm:^1.3.3" + use-sidecar: "npm:^1.1.3" + peerDependencies: + "@types/react": "*" + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 10c0/7ad8f6ffd3e2aedf9b3d79f0c9088a9a3d7c5332d80c923427a6d97fe0626fb4cb33a6d9174d19fad57d860be69c96f68497a0619c3a8af0e8a5332e49bdde31 + languageName: node + linkType: hard + +"react-style-singleton@npm:^2.2.2, react-style-singleton@npm:^2.2.3": + version: 2.2.3 + resolution: "react-style-singleton@npm:2.2.3" + dependencies: + get-nonce: "npm:^1.0.0" + tslib: "npm:^2.0.0" + peerDependencies: + "@types/react": "*" + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 10c0/841938ff16d16a6b76895f4cb2e1fea957e5fe3b30febbf03a54892dae1c9153f2383e231dea0b3ba41192ad2f2849448fa859caccd288943bce32639e971bee + languageName: node + linkType: hard + "react-test-renderer@npm:19.1.0": version: 19.1.0 resolution: "react-test-renderer@npm:19.1.0" @@ -23358,6 +23964,13 @@ __metadata: languageName: node linkType: hard +"sf-symbols-typescript@npm:^2.0.0": + version: 2.1.0 + resolution: "sf-symbols-typescript@npm:2.1.0" + checksum: 10c0/b6e2482c2b3ba785aa00770013e343a2175475b9cb7c8703c30a2ec1da8b41acd982db2d953877afb35af32a3dfba337d0b29e703c399cd2138c3cf68685c9c2 + languageName: node + linkType: hard + "shallowequal@npm:1.1.0": version: 1.1.0 resolution: "shallowequal@npm:1.1.0" @@ -24869,6 +25482,13 @@ __metadata: languageName: node linkType: hard +"tslib@npm:^2.0.0, tslib@npm:^2.1.0, tslib@npm:^2.3.0, tslib@npm:^2.3.1": + version: 2.8.1 + resolution: "tslib@npm:2.8.1" + checksum: 10c0/9c4759110a19c53f992d9aae23aac5ced636e99887b51b9e61def52611732872ff7668757d4e4c61f19691e36f4da981cd9485e869b4a7408d689f6bf1f14e62 + languageName: node + linkType: hard + "tslib@npm:^2.0.1": version: 2.3.1 resolution: "tslib@npm:2.3.1" @@ -24876,13 +25496,6 @@ __metadata: languageName: node linkType: hard -"tslib@npm:^2.1.0, tslib@npm:^2.3.0, tslib@npm:^2.3.1": - version: 2.8.1 - resolution: "tslib@npm:2.8.1" - checksum: 10c0/9c4759110a19c53f992d9aae23aac5ced636e99887b51b9e61def52611732872ff7668757d4e4c61f19691e36f4da981cd9485e869b4a7408d689f6bf1f14e62 - languageName: node - linkType: hard - "tslib@npm:^2.4.0": version: 2.4.1 resolution: "tslib@npm:2.4.1" @@ -25414,6 +26027,21 @@ __metadata: languageName: node linkType: hard +"use-callback-ref@npm:^1.3.3": + version: 1.3.3 + resolution: "use-callback-ref@npm:1.3.3" + dependencies: + tslib: "npm:^2.0.0" + peerDependencies: + "@types/react": "*" + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 10c0/f887488c6e6075cdad4962979da1714b217bcb1ee009a9e57ce9a844bcfc4c3a99e93983dfc2e5af9e0913824d24e730090ff255e902c516dcb58d2d3837e01c + languageName: node + linkType: hard + "use-deep-compare@npm:^1.1.0": version: 1.3.0 resolution: "use-deep-compare@npm:1.3.0" @@ -25434,6 +26062,22 @@ __metadata: languageName: node linkType: hard +"use-sidecar@npm:^1.1.3": + version: 1.1.3 + resolution: "use-sidecar@npm:1.1.3" + dependencies: + detect-node-es: "npm:^1.1.0" + tslib: "npm:^2.0.0" + peerDependencies: + "@types/react": "*" + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 10c0/161599bf921cfaa41c85d2b01c871975ee99260f3e874c2d41c05890d41170297bdcf314bc5185e7a700de2034ac5b888e3efc8e9f35724f4918f53538d717c9 + languageName: node + linkType: hard + "use-sync-external-store@npm:^1.4.0": version: 1.6.0 resolution: "use-sync-external-store@npm:1.6.0" @@ -26725,6 +27369,23 @@ __metadata: languageName: node linkType: hard +"zeego@npm:^3.0.6": + version: 3.0.6 + resolution: "zeego@npm:3.0.6" + dependencies: + "@radix-ui/react-context-menu": "npm:^2.0.1" + "@radix-ui/react-dropdown-menu": "npm:^2.0.1" + sf-symbols-typescript: "npm:^2.0.0" + peerDependencies: + "@react-native-menu/menu": 1.2.2 + react: "*" + react-native: "*" + react-native-ios-context-menu: 3.1.0 + react-native-ios-utilities: 5.1.2 + checksum: 10c0/76eec9ca0cee085da0bb50188ee08d6d67e3b2b2ea17b0a30e34fb3e39cd67a75d2650bdd4f5c593aec89cd778622d083dd20c61fd6adebe5ca01d694ac30fd5 + languageName: node + linkType: hard + "zod-to-json-schema@npm:^3.24.6": version: 3.24.6 resolution: "zod-to-json-schema@npm:3.24.6" From 696228b9adc10de9cb6435729cb8110cd8487620 Mon Sep 17 00:00:00 2001 From: Mounir Dhahri Date: Thu, 20 Nov 2025 17:35:29 +0100 Subject: [PATCH 016/123] fix: issues with flashlist performance --- src/app/App.tsx | 3 ++ .../Artist/ArtistArtworks/ArtistArtworks.tsx | 15 ++---- .../ArtworkGrids/MasonryArtworkGridItem.tsx | 6 +-- .../MasonryInfiniteScrollArtworkGrid.tsx | 9 +--- src/app/Components/Gene/GeneArtworks.tsx | 18 ++------ .../ArtQuizResultsEmptyTabs.tsx | 8 +--- .../ArtQuizResultsTabs/ArtQuizResultsTabs.tsx | 16 ++----- src/app/Scenes/Artist/Artist.tsx | 46 ++++++++----------- src/app/Scenes/ArtistSeries/ArtistSeries.tsx | 16 +++---- .../ArtistSeries/ArtistSeriesArtworks.tsx | 24 ++++------ src/app/Scenes/Collection/Collection.tsx | 8 +--- .../Collection/Screens/CollectionArtworks.tsx | 20 +++----- .../Scenes/Fair/Components/FairArtworks.tsx | 26 +++-------- src/app/Scenes/Fair/Fair.tsx | 8 +--- src/app/Scenes/Gene/Gene.tsx | 12 ++--- .../InfiniteDiscoveryMoreWorksTab.tsx | 17 ++----- .../MyCollection/MyCollectionArtworks.tsx | 32 ++++--------- .../Components/ArtworkAutosuggestResults.tsx | 17 ++----- .../Partner/Components/PartnerArtwork.tsx | 28 +++++------ src/app/Scenes/Partner/Partner.tsx | 16 ++----- src/app/Scenes/Search/SearchArtworksGrid.tsx | 21 +++------ src/app/Scenes/Tag/TagArtworks.tsx | 18 ++------ yarn.lock | 15 +++--- 23 files changed, 130 insertions(+), 269 deletions(-) diff --git a/src/app/App.tsx b/src/app/App.tsx index 85499408261..56d504f20e4 100644 --- a/src/app/App.tsx +++ b/src/app/App.tsx @@ -28,6 +28,7 @@ import { NativeModules, UIManager, View } from "react-native" import { Settings } from "react-native-fbsdk-next" import "react-native-get-random-values" import Keys from "react-native-keys" +import { enableFreeze } from "react-native-screens" import { useWebViewCookies } from "./Components/ArtsyWebView" import { Providers } from "./Providers" import { ForceUpdate } from "./Scenes/ForceUpdate/ForceUpdate" @@ -41,6 +42,8 @@ import useSyncNativeAuthState from "./utils/useSyncAuthState" require("./system/ignoreLogs") +enableFreeze(true) + if (__DEV__) { // Don't open RN dev menu with shake. We use it for our own Dev Menu. NativeModules.DevSettings.setIsShakeToShowDevMenuEnabled(false) diff --git a/src/app/Components/Artist/ArtistArtworks/ArtistArtworks.tsx b/src/app/Components/Artist/ArtistArtworks/ArtistArtworks.tsx index 0cf466d4ca6..4c2bef9b826 100644 --- a/src/app/Components/Artist/ArtistArtworks/ArtistArtworks.tsx +++ b/src/app/Components/Artist/ArtistArtworks/ArtistArtworks.tsx @@ -50,7 +50,6 @@ import { extractNodes } from "app/utils/extractNodes" import { useFeatureFlag } from "app/utils/hooks/useFeatureFlag" import { withSuspense } from "app/utils/hooks/withSuspense" import { - getColumnIndex, MASONRY_LIST_PAGE_SIZE, NUM_COLUMNS_MASONRY, ON_END_REACHED_THRESHOLD_MASONRY, @@ -182,17 +181,12 @@ const ArtworksGrid: React.FC = ({ } const renderItem: ListRenderItem = useCallback(({ item, index }) => { - const columnIndex = getColumnIndex(index) const imgAspectRatio = item.image?.aspectRatio ?? 1 const imgWidth = width / NUM_COLUMNS_MASONRY - space(2) - space(1) const imgHeight = imgWidth / imgAspectRatio return ( - + = ({ } keyExtractor={(item) => item.id} renderItem={renderItem} + contentContainerStyle={{ paddingHorizontal: space(1) }} onEndReached={loadMore} onEndReachedThreshold={ON_END_REACHED_THRESHOLD_MASONRY} // need to pass zIndex: 1 here in order for the SubTabBar to // be visible above list content ListHeaderComponentStyle={{ zIndex: 1 }} - // This is needed to make sure we are getting the right column index for each item - optimizeItemArrangement={false} ListHeaderComponent={ - <> + @@ -319,7 +312,7 @@ const ArtworksGrid: React.FC = ({ artworksCount > 1 ? "s" : "" }:`} - + } ListFooterComponent={listFooterComponent} /> diff --git a/src/app/Components/ArtworkGrids/MasonryArtworkGridItem.tsx b/src/app/Components/ArtworkGrids/MasonryArtworkGridItem.tsx index 2f98af3b124..b7854e90401 100644 --- a/src/app/Components/ArtworkGrids/MasonryArtworkGridItem.tsx +++ b/src/app/Components/ArtworkGrids/MasonryArtworkGridItem.tsx @@ -23,8 +23,8 @@ interface Artwork { } interface MasonryArtworkGridItemProps extends Omit { + fullWidth?: boolean artworkMetaStyle?: ViewProps["style"] - columnIndex: number contextModule?: ContextModule contextScreen?: ScreenOwnerType contextScreenOwnerId?: string @@ -41,8 +41,8 @@ interface MasonryArtworkGridItemProps extends Omit { } export const MasonryArtworkGridItem: React.FC = ({ + fullWidth = false, artworkMetaStyle = {}, - columnIndex, contextModule, contextScreen, contextScreenOwnerId, @@ -65,7 +65,7 @@ export const MasonryArtworkGridItem: React.FC = ({ const imgHeight = imgWidth / imgAspectRatio return ( - + = useCallback( ({ item, index }) => { - const columnIndex = getColumnIndex(index, rest.numColumns) - return ( , "numColumns" | "data" | "renderItem"> }, [shouldDisplayHeader, ListHeaderComponent, ListEmptyComponent, refreshControl, rest.onScroll]) @@ -196,7 +191,7 @@ export const MasonryInfiniteScrollArtworkGrid: React.FC = ({ ge } }, [relay.hasMore(), relay.isLoading()]) - const renderItem: ListRenderItem = useCallback(({ item, index }) => { - const columnIndex = getColumnIndex(index) - + const renderItem: ListRenderItem = useCallback(({ item }) => { const imgAspectRatio = item.image?.aspectRatio ?? 1 const imgWidth = width / NUM_COLUMNS_MASONRY - space(2) - space(1) const imgHeight = imgWidth / imgAspectRatio return ( - + = ({ ge ) } - // This is needed to make sure we are getting the right column index for each item - optimizeItemArrangement={false} keyExtractor={(item) => item.id} renderItem={renderItem} onEndReached={loadMore} @@ -140,8 +131,9 @@ export const GeneArtworksContainer: React.FC = ({ ge // need to pass zIndex: 1 here in order for the SubTabBar to // be visible above list content ListHeaderComponentStyle={{ zIndex: 1 }} + contentContainerStyle={{ paddingHorizontal: space(1) }} ListHeaderComponent={ - <> + @@ -150,7 +142,7 @@ export const GeneArtworksContainer: React.FC = ({ ge {`Showing ${artworksTotal} work${artworksTotal > 1 ? "s" : ""}`} - + } /> { )} > - - - + - - - + ) diff --git a/src/app/Scenes/ArtQuiz/ArtQuizResults/ArtQuizResultsTabs/ArtQuizResultsTabs.tsx b/src/app/Scenes/ArtQuiz/ArtQuizResults/ArtQuizResultsTabs/ArtQuizResultsTabs.tsx index d913c60f49b..abe24d2f560 100644 --- a/src/app/Scenes/ArtQuiz/ArtQuizResults/ArtQuizResultsTabs/ArtQuizResultsTabs.tsx +++ b/src/app/Scenes/ArtQuiz/ArtQuizResults/ArtQuizResultsTabs/ArtQuizResultsTabs.tsx @@ -16,8 +16,8 @@ export const ArtQuizResultsTabs = ({ me }: { me: ArtQuizResultsQuery$data["me"] const [activeTab, setActiveTab] = useState("worksYouLiked") - const savedArtworks = queryResult?.savedArtworks! - const recommendedArtworks = queryResult?.recommendedArtworks! + const savedArtworks = queryResult?.savedArtworks ?? [] + const recommendedArtworks = queryResult?.recommendedArtworks ?? [] const title = activeTab === "worksYouLiked" ? "Explore Your Quiz Results" : "Explore Art We Think You'll Love" @@ -34,19 +34,13 @@ export const ArtQuizResultsTabs = ({ me }: { me: ArtQuizResultsQuery$data["me"] BelowTitleHeaderComponent={() => } > - - - + - - - + - - - + ) diff --git a/src/app/Scenes/Artist/Artist.tsx b/src/app/Scenes/Artist/Artist.tsx index b0a15b00631..119e025c636 100644 --- a/src/app/Scenes/Artist/Artist.tsx +++ b/src/app/Scenes/Artist/Artist.tsx @@ -116,38 +116,32 @@ export const Artist: React.FC = ({ }} > - - - + - - {artistBelowTheFold ? ( - - ) : ( - - )} - + {artistBelowTheFold ? ( + + ) : ( + + )} - - {artistBelowTheFold ? ( - - ) : ( - - )} - + {artistBelowTheFold ? ( + + ) : ( + + )} diff --git a/src/app/Scenes/ArtistSeries/ArtistSeries.tsx b/src/app/Scenes/ArtistSeries/ArtistSeries.tsx index d9691c8cf7c..6d3a67a4711 100644 --- a/src/app/Scenes/ArtistSeries/ArtistSeries.tsx +++ b/src/app/Scenes/ArtistSeries/ArtistSeries.tsx @@ -53,18 +53,14 @@ export const ArtistSeries: React.FC = (props) => { }} > - - }> - - - + }> + + - - - - - + + + diff --git a/src/app/Scenes/ArtistSeries/ArtistSeriesArtworks.tsx b/src/app/Scenes/ArtistSeries/ArtistSeriesArtworks.tsx index 109f64254f8..d086e8bba42 100644 --- a/src/app/Scenes/ArtistSeries/ArtistSeriesArtworks.tsx +++ b/src/app/Scenes/ArtistSeries/ArtistSeriesArtworks.tsx @@ -12,11 +12,7 @@ import ArtworkGridItem from "app/Components/ArtworkGrids/ArtworkGridItem" import { FilteredArtworkGridZeroState } from "app/Components/ArtworkGrids/FilteredArtworkGridZeroState" import { HeaderArtworksFilterWithTotalArtworks } from "app/Components/HeaderArtworksFilter/HeaderArtworksFilterWithTotalArtworks" import { extractNodes } from "app/utils/extractNodes" -import { - getColumnIndex, - NUM_COLUMNS_MASONRY, - ON_END_REACHED_THRESHOLD_MASONRY, -} from "app/utils/masonryHelpers" +import { NUM_COLUMNS_MASONRY, ON_END_REACHED_THRESHOLD_MASONRY } from "app/utils/masonryHelpers" import { AnimatedMasonryListFooter } from "app/utils/masonryHelpers/AnimatedMasonryListFooter" import { ExtractNodeType } from "app/utils/relayHelpers" import { Schema } from "app/utils/track" @@ -97,17 +93,12 @@ export const ArtistSeriesArtworks: React.FC = ({ arti } const renderItem: ListRenderItem = useCallback(({ item, index }) => { - const columnIndex = getColumnIndex(index) const imgAspectRatio = item.image?.aspectRatio ?? 1 const imgWidth = width / NUM_COLUMNS_MASONRY - space(2) - space(1) const imgHeight = imgWidth / imgAspectRatio return ( - + = ({ arti = ({ arti // need to pass zIndex: 1 here in order for the SubTabBar to // be visible above list content ListHeaderComponentStyle={{ zIndex: 1 }} + contentContainerStyle={{ paddingHorizontal: space(1) }} ListHeaderComponent={ - - - + + + + + } ListFooterComponent={() => ( diff --git a/src/app/Scenes/Collection/Collection.tsx b/src/app/Scenes/Collection/Collection.tsx index 92d7e4a5762..060b859d81a 100644 --- a/src/app/Scenes/Collection/Collection.tsx +++ b/src/app/Scenes/Collection/Collection.tsx @@ -103,15 +103,11 @@ export const CollectionContent: React.FC = ({ collection }) => }} > - - - + {!!shouldRenderOverviewTab ? ( - - - + ) : null} diff --git a/src/app/Scenes/Collection/Screens/CollectionArtworks.tsx b/src/app/Scenes/Collection/Screens/CollectionArtworks.tsx index 58cdf72c08b..41a3c82b8cd 100644 --- a/src/app/Scenes/Collection/Screens/CollectionArtworks.tsx +++ b/src/app/Scenes/Collection/Screens/CollectionArtworks.tsx @@ -11,7 +11,6 @@ import { HeaderArtworksFilterWithTotalArtworks } from "app/Components/HeaderArtw import { extractNodes } from "app/utils/extractNodes" import { get } from "app/utils/get" import { - getColumnIndex, MASONRY_LIST_PAGE_SIZE, NUM_COLUMNS_MASONRY, ON_END_REACHED_THRESHOLD_MASONRY, @@ -107,8 +106,6 @@ export const CollectionArtworks: React.FC = ({ collecti } const renderItem: ListRenderItem = useCallback(({ item, index }) => { - const columnIndex = getColumnIndex(index) - const imgAspectRatio = item.image?.aspectRatio ?? 1 const imgWidth = width / NUM_COLUMNS_MASONRY - space(2) - space(1) const imgHeight = imgWidth / imgAspectRatio @@ -116,11 +113,7 @@ export const CollectionArtworks: React.FC = ({ collecti const hideSignals = CURATORS_PICKS_SLUGS.includes(collection.slug) return ( - + = ({ collecti numColumns={NUM_COLUMNS_MASONRY} keyboardShouldPersistTaps="handled" innerRef={gridRef} - // This is needed to make sure we are getting the right column index for each item - optimizeItemArrangement={false} ListEmptyComponent={ = ({ collecti // need to pass zIndex: 1 here in order for the SubTabBar to // be visible above list content ListHeaderComponentStyle={{ zIndex: 1 }} + contentContainerStyle={{ paddingHorizontal: space(1) }} ListHeaderComponent={ - - - + + + + + } ListFooterComponent={() => ( diff --git a/src/app/Scenes/Fair/Components/FairArtworks.tsx b/src/app/Scenes/Fair/Components/FairArtworks.tsx index cacb1e1592c..1615566df50 100644 --- a/src/app/Scenes/Fair/Components/FairArtworks.tsx +++ b/src/app/Scenes/Fair/Components/FairArtworks.tsx @@ -23,7 +23,6 @@ import { extractNodes } from "app/utils/extractNodes" import { useScreenDimensions } from "app/utils/hooks" import { withSuspense } from "app/utils/hooks/withSuspense" import { - getColumnIndex, MASONRY_LIST_PAGE_SIZE, NUM_COLUMNS_MASONRY, ON_END_REACHED_THRESHOLD_MASONRY, @@ -95,17 +94,12 @@ export const FairArtworks: React.FC = ({ }, [artworksTotal]) const renderItem: ListRenderItem = useCallback(({ item, index }) => { - const columnIndex = getColumnIndex(index) const imgAspectRatio = item.image?.aspectRatio ?? 1 const imgWidth = width / NUM_COLUMNS_MASONRY - space(2) - space(1) const imgHeight = imgWidth / imgAspectRatio return ( - + = ({ data={filteredArtworks} keyExtractor={(item) => item.id} numColumns={NUM_COLUMNS_MASONRY} - // This is needed to make sure we are getting the right column index for each item - optimizeItemArrangement={false} keyboardShouldPersistTaps="handled" + contentContainerStyle={{ paddingHorizontal: space(1) }} ListEmptyComponent={ = ({ // be visible above list content ListHeaderComponentStyle={{ zIndex: 1 }} ListHeaderComponent={ - <> + - + } ListFooterComponent={() => ( @@ -288,9 +281,8 @@ export const FairArtworksWithoutTabs: React.FC = ({ data={filteredArtworks} keyExtractor={(item) => item.id} numColumns={NUM_COLUMNS_MASONRY} - // This is needed to make sure we are getting the right column index for each item - optimizeItemArrangement={false} keyboardShouldPersistTaps="handled" + contentContainerStyle={{ paddingHorizontal: space(1) }} ListEmptyComponent={ = ({ onEndReached={handleOnEndReached} onEndReachedThreshold={ON_END_REACHED_THRESHOLD_MASONRY} renderItem={({ item, index }) => { - const columnIndex = getColumnIndex(index) - const imgAspectRatio = item.image?.aspectRatio ?? 1 const imgWidth = width / NUM_COLUMNS_MASONRY - space(2) - space(1) const imgHeight = imgWidth / imgAspectRatio return ( - + = ({ fair }) => { }} > - - - + {!!hasExhibitors ? ( - - - + ) : null} diff --git a/src/app/Scenes/Gene/Gene.tsx b/src/app/Scenes/Gene/Gene.tsx index 306f8d7c4ec..ecfa326ae77 100644 --- a/src/app/Scenes/Gene/Gene.tsx +++ b/src/app/Scenes/Gene/Gene.tsx @@ -67,16 +67,12 @@ export const Gene: React.FC = (props) => { headerProps={{ onBack: goBack }} > - - - - - + + + - - - + diff --git a/src/app/Scenes/InfiniteDiscovery/Components/InfiniteDiscoveryMoreWorksTab.tsx b/src/app/Scenes/InfiniteDiscovery/Components/InfiniteDiscoveryMoreWorksTab.tsx index 07aa5ecc7c4..21902ed5c1f 100644 --- a/src/app/Scenes/InfiniteDiscovery/Components/InfiniteDiscoveryMoreWorksTab.tsx +++ b/src/app/Scenes/InfiniteDiscovery/Components/InfiniteDiscoveryMoreWorksTab.tsx @@ -9,11 +9,7 @@ import { FilteredArtworkGridZeroState } from "app/Components/ArtworkGrids/Filter import { PAGE_SIZE } from "app/Components/constants" import { extractNodes } from "app/utils/extractNodes" import { withSuspense } from "app/utils/hooks/withSuspense" -import { - getColumnIndex, - NUM_COLUMNS_MASONRY, - ON_END_REACHED_THRESHOLD_MASONRY, -} from "app/utils/masonryHelpers" +import { NUM_COLUMNS_MASONRY, ON_END_REACHED_THRESHOLD_MASONRY } from "app/utils/masonryHelpers" import { AnimatedMasonryListFooter } from "app/utils/masonryHelpers/AnimatedMasonryListFooter" import { PlaceholderGrid } from "app/utils/placeholderGrid" import { ExtractNodeType } from "app/utils/relayHelpers" @@ -40,18 +36,12 @@ export const MoreWorksTab: FC = ({ artworks: _artworks }) => const renderItem: ListRenderItem> = useCallback( ({ item, index }) => { - const columnIndex = getColumnIndex(index) - const imgAspectRatio = item.image?.aspectRatio ?? 1 const imgWidth = width / NUM_COLUMNS_MASONRY - space(2) - space(1) const imgHeight = imgWidth / imgAspectRatio return ( - + = ({ artworks: _artworks }) => data={artworks} numColumns={NUM_COLUMNS_MASONRY} keyboardShouldPersistTaps="handled" - // This is needed to make sure we are getting the right column index for each item - optimizeItemArrangement={false} + contentContainerStyle={{ paddingHorizontal: space(1) }} keyExtractor={(item) => item?.internalID} ListEmptyComponent={} ListFooterComponent={() => ( diff --git a/src/app/Scenes/MyCollection/MyCollectionArtworks.tsx b/src/app/Scenes/MyCollection/MyCollectionArtworks.tsx index 7f7190f333b..975d1988069 100644 --- a/src/app/Scenes/MyCollection/MyCollectionArtworks.tsx +++ b/src/app/Scenes/MyCollection/MyCollectionArtworks.tsx @@ -19,11 +19,7 @@ import { MyCollectionTabsStore } from "app/Scenes/MyCollection/State/MyCollectio import { cleanLocalImages } from "app/utils/LocalImageStore" import { extractNodes } from "app/utils/extractNodes" import { withSuspense } from "app/utils/hooks/withSuspense" -import { - getColumnIndex, - NUM_COLUMNS_MASONRY, - ON_END_REACHED_THRESHOLD_MASONRY, -} from "app/utils/masonryHelpers" +import { NUM_COLUMNS_MASONRY, ON_END_REACHED_THRESHOLD_MASONRY } from "app/utils/masonryHelpers" import { AnimatedMasonryListFooter } from "app/utils/masonryHelpers/AnimatedMasonryListFooter" import { MY_COLLECTION_REFRESH_KEY, @@ -42,6 +38,7 @@ interface MyCollectionArtworksProps { } export const MyCollectionArtworks: React.FC = ({ me }) => { + const space = useSpace() const { setIsFilterModalVisible, setFiltersCount } = MyCollectionTabsStore.useStoreActions( (actions) => actions ) @@ -75,21 +72,13 @@ export const MyCollectionArtworks: React.FC = ({ me } cleanLocalImages() }, []) - const renderItem: ListRenderItem<(typeof filteredArtworks)[0]> = useCallback( - ({ item, index }) => { - const columnIndex = getColumnIndex(index) - return ( - - - - ) - }, - [] - ) + const renderItem: ListRenderItem<(typeof filteredArtworks)[0]> = useCallback(({ item }) => { + return ( + + + + ) + }, []) const RefreshControl = useRefreshControl(refetch) @@ -119,8 +108,7 @@ export const MyCollectionArtworks: React.FC = ({ me } data={filteredArtworks} numColumns={NUM_COLUMNS_MASONRY} keyboardShouldPersistTaps="handled" - // This is needed to make sure we are getting the right column index for each item - optimizeItemArrangement={false} + contentContainerStyle={{ paddingHorizontal: space(1) }} ListEmptyComponent={ diff --git a/src/app/Scenes/MyCollection/Screens/ArtworkForm/Components/ArtworkAutosuggestResults.tsx b/src/app/Scenes/MyCollection/Screens/ArtworkForm/Components/ArtworkAutosuggestResults.tsx index db22e20eb9f..a76e089f6e2 100644 --- a/src/app/Scenes/MyCollection/Screens/ArtworkForm/Components/ArtworkAutosuggestResults.tsx +++ b/src/app/Scenes/MyCollection/Screens/ArtworkForm/Components/ArtworkAutosuggestResults.tsx @@ -18,11 +18,7 @@ import { PAGE_SIZE } from "app/Components/constants" import { getRelayEnvironment } from "app/system/relay/defaultEnvironment" import { extractNodes } from "app/utils/extractNodes" import { useScreenDimensions } from "app/utils/hooks" -import { - getColumnIndex, - NUM_COLUMNS_MASONRY, - ON_END_REACHED_THRESHOLD_MASONRY, -} from "app/utils/masonryHelpers" +import { NUM_COLUMNS_MASONRY, ON_END_REACHED_THRESHOLD_MASONRY } from "app/utils/masonryHelpers" import { renderWithPlaceholder } from "app/utils/renderWithPlaceholder" import React, { useCallback, useEffect } from "react" import { createPaginationContainer, graphql, QueryRenderer, RelayPaginationProp } from "react-relay" @@ -66,12 +62,10 @@ const ArtworkAutosuggestResults: React.FC = ({ return ( item.id} keyboardShouldPersistTaps="handled" onEndReached={loadMore} @@ -99,18 +93,13 @@ const ArtworkAutosuggestResults: React.FC = ({ } renderItem={({ item, index }) => { - const columnIndex = getColumnIndex(index) const imgAspectRatio = item.image?.aspectRatio ?? 1 const imgWidth = width / NUM_COLUMNS_MASONRY - space(2) - space(1) const imgHeight = imgWidth / imgAspectRatio return ( - + = useCallback(({ item, index }) => { - const columnIndex = getColumnIndex(index) - + const renderItem: ListRenderItem = useCallback(({ item }) => { const imgAspectRatio = item.image?.aspectRatio ?? 1 const imgWidth = width / NUM_COLUMNS_MASONRY - space(2) - space(1) const imgHeight = imgWidth / imgAspectRatio return ( - + @@ -110,12 +102,14 @@ export const PartnerArtwork: React.FC<{ // be visible above list content ListHeaderComponentStyle={{ zIndex: 1 }} ListHeaderComponent={ - - setIsFilterArtworksModalVisible(true)} - /> - + + + setIsFilterArtworksModalVisible(true)} + /> + + } /> diff --git a/src/app/Scenes/Partner/Partner.tsx b/src/app/Scenes/Partner/Partner.tsx index a05dbf61646..9cc378fec2a 100644 --- a/src/app/Scenes/Partner/Partner.tsx +++ b/src/app/Scenes/Partner/Partner.tsx @@ -85,21 +85,15 @@ const Partner: React.FC = (props) => { headerProps={{ onBack: goBack }} > - - - + - - - - - + + + - - - + diff --git a/src/app/Scenes/Search/SearchArtworksGrid.tsx b/src/app/Scenes/Search/SearchArtworksGrid.tsx index f258cd6c445..1393506f2a3 100644 --- a/src/app/Scenes/Search/SearchArtworksGrid.tsx +++ b/src/app/Scenes/Search/SearchArtworksGrid.tsx @@ -20,11 +20,7 @@ import ArtworkGridItem from "app/Components/ArtworkGrids/ArtworkGridItem" import { ArtworksFilterHeader } from "app/Components/ArtworkGrids/ArtworksFilterHeader" import { SCROLLVIEW_SEARCH_RESULTS_PADDING_BOTTOM_OFFSET } from "app/Components/constants" import { extractNodes } from "app/utils/extractNodes" -import { - getColumnIndex, - NUM_COLUMNS_MASONRY, - ON_END_REACHED_THRESHOLD_MASONRY, -} from "app/utils/masonryHelpers" +import { NUM_COLUMNS_MASONRY, ON_END_REACHED_THRESHOLD_MASONRY } from "app/utils/masonryHelpers" import { AnimatedMasonryListFooter } from "app/utils/masonryHelpers/AnimatedMasonryListFooter" import { Schema } from "app/utils/track" @@ -114,8 +110,6 @@ const SearchArtworksGrid: React.FC = ({ viewer, relay, data={artworks} keyExtractor={(item) => item.id} numColumns={NUM_COLUMNS_MASONRY} - // This is needed to make sure we are getting the right column index for each item - optimizeItemArrangement={false} keyboardShouldPersistTaps="handled" keyboardDismissMode="on-drag" ListEmptyComponent={ @@ -137,19 +131,13 @@ const SearchArtworksGrid: React.FC = ({ viewer, relay, )} renderItem={({ item, index }) => { - const columnIndex = getColumnIndex(index) - const imgAspectRatio = item.image?.aspectRatio ?? 1 const imgWidth = width / NUM_COLUMNS_MASONRY - space(2) - space(1) const imgHeight = imgWidth / imgAspectRatio return ( - + = ({ viewer, relay, ) }} - contentContainerStyle={{ paddingBottom: SCROLLVIEW_SEARCH_RESULTS_PADDING_BOTTOM_OFFSET }} + contentContainerStyle={{ + paddingBottom: SCROLLVIEW_SEARCH_RESULTS_PADDING_BOTTOM_OFFSET, + paddingHorizontal: space(1), + }} /> diff --git a/src/app/Scenes/Tag/TagArtworks.tsx b/src/app/Scenes/Tag/TagArtworks.tsx index 82c1dca5b88..3c35c62336a 100644 --- a/src/app/Scenes/Tag/TagArtworks.tsx +++ b/src/app/Scenes/Tag/TagArtworks.tsx @@ -18,7 +18,6 @@ import { FilteredArtworkGridZeroState } from "app/Components/ArtworkGrids/Filter import { TagArtworksFilterHeader } from "app/Scenes/Tag/TagArtworksFilterHeader" import { extractNodes } from "app/utils/extractNodes" import { - getColumnIndex, MASONRY_LIST_PAGE_SIZE, NUM_COLUMNS_MASONRY, ON_END_REACHED_THRESHOLD_MASONRY, @@ -91,19 +90,13 @@ const TagArtworks: React.FC = ({ tag, relay }) => { } }, [relay.hasMore(), relay.isLoading()]) - const renderItem: ListRenderItem = useCallback(({ item, index }) => { - const columnIndex = getColumnIndex(index) - + const renderItem: ListRenderItem = useCallback(({ item }) => { const imgAspectRatio = item.image?.aspectRatio ?? 1 const imgWidth = width / NUM_COLUMNS_MASONRY - space(2) - space(1) const imgHeight = imgWidth / imgAspectRatio return ( - + = ({ tag, relay }) => { data={artworks} numColumns={NUM_COLUMNS_MASONRY} keyboardShouldPersistTaps="handled" - // This is needed to make sure we are getting the right column index for each item - optimizeItemArrangement={false} + contentContainerStyle={{ paddingHorizontal: space(1) }} ListEmptyComponent={ initialArtworksTotal ? ( @@ -147,7 +139,7 @@ const TagArtworks: React.FC = ({ tag, relay }) => { // be visible above list content ListHeaderComponentStyle={{ zIndex: 1 }} ListHeaderComponent={ - <> + @@ -156,7 +148,7 @@ const TagArtworks: React.FC = ({ tag, relay }) => { Showing {artworksTotal} works - + } /> = 18.2.0" - checksum: 10c0/0e8231ced4f196c84db859760b9704b85eca156ba0d8d9802a89d46d96116fa10fa481dc482be6a807b33971682bce176a997391543d2404754e43af510201b8 + checksum: 10c0/d70a61dbd2e7898193cedcebf6d0759494eff676cf8c2977ffc005211cf0134e041787e3e8fffd16ed39fe740389504fa27e62e7fdbe1856a978df7e4c1bdbd5 languageName: node linkType: hard @@ -6891,22 +6892,22 @@ __metadata: linkType: hard "@react-navigation/elements@npm:^2.6.5": - version: 2.7.0 - resolution: "@react-navigation/elements@npm:2.7.0" + version: 2.8.2 + resolution: "@react-navigation/elements@npm:2.8.2" dependencies: color: "npm:^4.2.3" use-latest-callback: "npm:^0.2.4" use-sync-external-store: "npm:^1.5.0" peerDependencies: "@react-native-masked-view/masked-view": ">= 0.2.0" - "@react-navigation/native": ^7.1.18 + "@react-navigation/native": ^7.1.20 react: ">= 18.2.0" react-native: "*" react-native-safe-area-context: ">= 4.0.0" peerDependenciesMeta: "@react-native-masked-view/masked-view": optional: true - checksum: 10c0/4128146e14d812681deb885b4505745b2dc47596d4b15cc713fafcb95632efda61e5d1fc75dd9e4bbd503099a866fb1591e08356ebd47bde0405c7a30dc144cf + checksum: 10c0/0e5282f92f2946fd635c2a1c9b444d6d158663ad57669cb87e372587d2313df90cd092737305f999e6223aace75cb7829ef709b1198a8a6bc22aa40821a792e6 languageName: node linkType: hard From dde82aec75472072ce03667bf75a40220e1ae923 Mon Sep 17 00:00:00 2001 From: Mounir Dhahri Date: Fri, 21 Nov 2025 10:11:33 +0100 Subject: [PATCH 017/123] fix: issues with menu item --- src/app/Components/ArtworkGrids/ArtworkGridItem.tsx | 2 ++ .../Components/ArtworkGrids/MasonryArtworkGridItem.tsx | 10 +++++++++- src/app/Components/ArtworkRail/ArtworkRail.tsx | 2 +- src/app/Components/ArtworkRail/ArtworkRailCard.tsx | 2 +- src/app/Components/ContextMenu/ContextMenuArtwork.tsx | 2 +- 5 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/app/Components/ArtworkGrids/ArtworkGridItem.tsx b/src/app/Components/ArtworkGrids/ArtworkGridItem.tsx index 60ebf6c12b6..25f287fd4be 100644 --- a/src/app/Components/ArtworkGrids/ArtworkGridItem.tsx +++ b/src/app/Components/ArtworkGrids/ArtworkGridItem.tsx @@ -275,6 +275,7 @@ export const Artwork: React.FC = memo( haptic underlayColor={color("mono0")} onPress={handleTap} + // To prevent navigation when opening the long-press context menu, `onLongPress` & `delayLongPress` need to be set (https://github.com/mpiannucci/react-native-context-menu-view/issues/60) onLongPress={() => { // Adroid long press is tracked inside of the ContextMenuArtwork component if (contextScreenOwnerType && isIOS && enableContextMenuIOS) { @@ -287,6 +288,7 @@ export const Artwork: React.FC = memo( ) } }} + delayLongPress={400} navigationProps={navigationProps} to={artwork.href} testID={`artworkGridItem-${artwork.title}`} diff --git a/src/app/Components/ArtworkGrids/MasonryArtworkGridItem.tsx b/src/app/Components/ArtworkGrids/MasonryArtworkGridItem.tsx index b7854e90401..7313b68e66e 100644 --- a/src/app/Components/ArtworkGrids/MasonryArtworkGridItem.tsx +++ b/src/app/Components/ArtworkGrids/MasonryArtworkGridItem.tsx @@ -65,7 +65,15 @@ export const MasonryArtworkGridItem: React.FC = ({ const imgHeight = imgWidth / imgAspectRatio return ( - + = memo( onPress, onEndReached, onEndReachedThreshold, - ListHeaderComponent = , + ListHeaderComponent = , ListFooterComponent = , hideArtistName = false, listRef, diff --git a/src/app/Components/ArtworkRail/ArtworkRailCard.tsx b/src/app/Components/ArtworkRail/ArtworkRailCard.tsx index 56056ef772c..079713432bd 100644 --- a/src/app/Components/ArtworkRail/ArtworkRailCard.tsx +++ b/src/app/Components/ArtworkRail/ArtworkRailCard.tsx @@ -76,7 +76,7 @@ export const ArtworkRailCard: React.FC = memo( contextScreenOwnerSlug={contextScreenOwnerSlug} contextScreenOwnerType={contextScreenOwnerType} > - + - {children} + {children} Date: Fri, 21 Nov 2025 10:50:42 +0100 Subject: [PATCH 018/123] fix: issues with animations transform --- ios/Podfile.lock | 2 +- package.json | 4 +- .../Artist/ArtistArtworks/ArtistArtworks.tsx | 20 +++---- .../Artist/ArtistHeaderNavRight.tsx | 35 ++++-------- .../ArtworkCardBottomSheetHandle.tsx | 19 +------ .../ArtworkGrids/ArtworkSaveIconWrapper.tsx | 56 +++++++++++-------- src/app/Components/FadeIn.tsx | 51 +++++++++-------- src/app/Components/Gene/GeneArtworks.tsx | 16 +++--- .../ArtistSeries/ArtistSeriesArtworks.tsx | 18 +++--- src/app/Scenes/ArtworkList/ArtworkList.tsx | 2 +- .../Collection/Screens/CollectionArtworks.tsx | 22 ++++---- .../Scenes/Fair/Components/FairArtworks.tsx | 36 ++++++------ .../InfiniteDiscoveryMoreWorksTab.tsx | 22 ++++---- .../Components/ArtworkAutosuggestResults.tsx | 18 +++--- .../Partner/Components/PartnerArtwork.tsx | 16 +++--- src/app/Scenes/Search/SearchArtworksGrid.tsx | 18 +++--- src/app/Scenes/Tag/TagArtworks.tsx | 16 +++--- 17 files changed, 170 insertions(+), 201 deletions(-) diff --git a/ios/Podfile.lock b/ios/Podfile.lock index c6711fa7713..a8946bdd763 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -4668,7 +4668,7 @@ SPEC CHECKSUMS: RNNotifee: 5e3b271e8ea7456a36eec994085543c9adca9168 RNPermissions: 663a639fdc5aa46b853f514ae8a86dd4deb160cb RNReactNativeHapticFeedback: 7601768ee65ffc86fc93d7c30dd917031144ed3d - RNReanimated: b1f6ab0ddbe94e003e1e60fdbc03da9ffa103730 + RNReanimated: ceb81fcfe01e98bff4193366893e4e341de500a5 RNScreens: 0bbf16c074ae6bb1058a7bf2d1ae017f4306797c RNSentry: ab7ba8bd678713c94762d2d3f2087d47105b6cf3 RNShare: 1dba46787d6e5543e05655efaefa0e4bb98380d9 diff --git a/package.json b/package.json index fddce4d5141..c8b10e826bb 100644 --- a/package.json +++ b/package.json @@ -361,7 +361,9 @@ "reanimated": { "staticFeatureFlags": { "USE_COMMIT_HOOK_ONLY_FOR_REACT_COMMITS": true, - "DISABLE_COMMIT_PAUSING_MECHANISM": true + "DISABLE_COMMIT_PAUSING_MECHANISM": true, + "IOS_SYNCHRONOUSLY_UPDATE_UI_PROPS": true, + "ANDROID_SYNCHRONOUSLY_UPDATE_UI_PROPS": true } }, "packageManager": "yarn@4.10.3" diff --git a/src/app/Components/Artist/ArtistArtworks/ArtistArtworks.tsx b/src/app/Components/Artist/ArtistArtworks/ArtistArtworks.tsx index 4c2bef9b826..c900968e09d 100644 --- a/src/app/Components/Artist/ArtistArtworks/ArtistArtworks.tsx +++ b/src/app/Components/Artist/ArtistArtworks/ArtistArtworks.tsx @@ -186,17 +186,15 @@ const ArtworksGrid: React.FC = ({ const imgHeight = imgWidth / imgAspectRatio return ( - - - + ) }, []) diff --git a/src/app/Components/Artist/ArtistHeaderNavRight.tsx b/src/app/Components/Artist/ArtistHeaderNavRight.tsx index 7011325c501..e46049e1ff6 100644 --- a/src/app/Components/Artist/ArtistHeaderNavRight.tsx +++ b/src/app/Components/Artist/ArtistHeaderNavRight.tsx @@ -59,27 +59,16 @@ export const ArtistHeaderNavRight: React.FC = ({ const followButtonTranslateX = useDerivedValue(() => displayFollowButton.value ? 0 : followAreaDeltaX ) - const followButtonOpacity = useDerivedValue(() => (displayFollowButton.value ? 1 : 0)) const viewStyle = useAnimatedStyle( () => ({ - transform: [ - { - translateX: withTiming(followButtonTranslateX.value, { - duration: 200, - easing: Easing.sin, - }), - }, - ], + left: withTiming(followButtonTranslateX.value, { duration: 200, easing: Easing.sin }), }), [followAreaDeltaX] ) const spacerStyle = useAnimatedStyle(() => ({ width: withTiming(spacerWidth.value, { duration: 200 }), })) - const followButtonStyle = useAnimatedStyle(() => ({ - opacity: withTiming(followButtonOpacity.value, { duration: 200 }), - })) const handleSharePress = useCallback(() => { if (artist?.name && artist?.name && artist?.slug && artist?.href) { @@ -114,18 +103,16 @@ export const ArtistHeaderNavRight: React.FC = ({ - - setIsFollowed(!isFollowed)} - // Using maxWidth and minWidth to prevent the button from changing width when the text changes - maxWidth={followButtonWidth} - minWidth={followButtonWidth} - /> - + setIsFollowed(!isFollowed)} + // Using maxWidth and minWidth to prevent the button from changing width when the text changes + maxWidth={followButtonWidth} + minWidth={followButtonWidth} + /> ) diff --git a/src/app/Components/ArtworkCard/ArtworkCardBottomSheetHandle.tsx b/src/app/Components/ArtworkCard/ArtworkCardBottomSheetHandle.tsx index e49c24d7aea..eefedd7775f 100644 --- a/src/app/Components/ArtworkCard/ArtworkCardBottomSheetHandle.tsx +++ b/src/app/Components/ArtworkCard/ArtworkCardBottomSheetHandle.tsx @@ -1,26 +1,13 @@ import { ChevronUpIcon } from "@artsy/icons/native" import { Flex, Text } from "@artsy/palette-mobile" -import { useBottomSheet } from "@gorhom/bottom-sheet" import { BottomSheetDefaultHandleProps } from "@gorhom/bottom-sheet/lib/typescript/components/bottomSheetHandle/types" import { useBottomSheetAnimatedStyles } from "app/Components/ArtworkCard/useBottomSheetAnimatedStyles" import { FC } from "react" -import Animated, { Extrapolation, interpolate, useAnimatedStyle } from "react-native-reanimated" +import Animated from "react-native-reanimated" export const ArtworkCardBottomSheetHandle: FC = () => { const { opacityStyle, heightTextStyle } = useBottomSheetAnimatedStyles() - const { animatedIndex } = useBottomSheet() - const animatedHandle = useAnimatedStyle(() => { - return { - transform: [ - { - rotateX: - interpolate(animatedIndex.value, [0, 0.2, 1], [0, 20, 180], Extrapolation.CLAMP) + - "deg", - }, - ], - } - }) return ( = ( pt={0.5} backgroundColor="mono0" > - + - + diff --git a/src/app/Components/ArtworkGrids/ArtworkSaveIconWrapper.tsx b/src/app/Components/ArtworkGrids/ArtworkSaveIconWrapper.tsx index d5fd3621ccf..ff34ca0d722 100644 --- a/src/app/Components/ArtworkGrids/ArtworkSaveIconWrapper.tsx +++ b/src/app/Components/ArtworkGrids/ArtworkSaveIconWrapper.tsx @@ -1,26 +1,23 @@ import { HeartFillIcon, HeartStrokeIcon } from "@artsy/icons/native" import { HEART_ICON_SIZE } from "app/Components/constants" import { useEffect, useRef } from "react" -import Animated, { - useAnimatedStyle, - useSharedValue, - withSequence, - withSpring, - withTiming, -} from "react-native-reanimated" +import { Animated, useAnimatedValue } from "react-native" -export const ArtworkSaveIconWrapper: React.FC<{ +interface ArtworkSaveIconWrapperProps { isSaved: boolean testID?: string accessibilityLabel?: string fill?: string -}> = ({ isSaved, testID, accessibilityLabel, fill }) => { - const scaleAnimation = useSharedValue(1) - const didMount = useRef(false) +} - const animatedStyles = useAnimatedStyle(() => ({ - transform: [{ scale: scaleAnimation.value }], - })) +export const ArtworkSaveIconWrapper: React.FC = ({ + isSaved, + testID, + accessibilityLabel, + fill, +}) => { + const scaleAnimation = useAnimatedValue(1) + const didMount = useRef(false) useEffect(() => { if (!didMount.current) { @@ -29,23 +26,36 @@ export const ArtworkSaveIconWrapper: React.FC<{ } if (isSaved) { - scaleAnimation.value = withSequence( - withSpring(isSaved ? 0.7 : 1, { - mass: 1, + Animated.sequence([ + Animated.spring(scaleAnimation, { + toValue: 0.7, + mass: 0.01, stiffness: 300, - damping: 20, + useNativeDriver: true, + }), + Animated.timing(scaleAnimation, { + toValue: 1.1, + duration: 300, + useNativeDriver: true, + }), + Animated.timing(scaleAnimation, { + toValue: 1, + duration: 200, + useNativeDriver: true, }), - withTiming(1.1, { duration: 300 }), - withTiming(1, { duration: 200 }) - ) + ]).start() } else { // We don't want to animation the dislike - scaleAnimation.value = 1 + scaleAnimation.setValue(1) } }, [isSaved, scaleAnimation]) return ( - + {!!isSaved ? ( { - const showing = useSharedValue(0) + const animatedValue = useRef(new Animated.Value(0)).current useEffect(() => { - showing.value = withDelay( + Animated.timing(animatedValue, { + toValue: 1, + duration, delay, - withTiming(1, { - duration, - }) - ) - }, []) + useNativeDriver: true, + }).start() + }, [animatedValue, delay, duration]) - const animatedStyle = useAnimatedStyle(() => { - return { - transform: [{ translateY: slide ? interpolate(showing.get(), [0, 1], [10, 0]) : 0 }], - opacity: showing.get(), - } - }) + const translateY = slide + ? animatedValue.interpolate({ + inputRange: [0, 1], + outputRange: [10, 0], + }) + : 0 - return {children} + return ( + + {children} + + ) } diff --git a/src/app/Components/Gene/GeneArtworks.tsx b/src/app/Components/Gene/GeneArtworks.tsx index 342be98e777..d3db79b3845 100644 --- a/src/app/Components/Gene/GeneArtworks.tsx +++ b/src/app/Components/Gene/GeneArtworks.tsx @@ -90,15 +90,13 @@ export const GeneArtworksContainer: React.FC = ({ ge const imgHeight = imgWidth / imgAspectRatio return ( - - - + ) }, []) diff --git a/src/app/Scenes/ArtistSeries/ArtistSeriesArtworks.tsx b/src/app/Scenes/ArtistSeries/ArtistSeriesArtworks.tsx index d086e8bba42..ddeb8bcbf97 100644 --- a/src/app/Scenes/ArtistSeries/ArtistSeriesArtworks.tsx +++ b/src/app/Scenes/ArtistSeries/ArtistSeriesArtworks.tsx @@ -98,16 +98,14 @@ export const ArtistSeriesArtworks: React.FC = ({ arti const imgHeight = imgWidth / imgAspectRatio return ( - - - + ) }, []) diff --git a/src/app/Scenes/ArtworkList/ArtworkList.tsx b/src/app/Scenes/ArtworkList/ArtworkList.tsx index 8f64870e2dd..259d57920a4 100644 --- a/src/app/Scenes/ArtworkList/ArtworkList.tsx +++ b/src/app/Scenes/ArtworkList/ArtworkList.tsx @@ -107,7 +107,7 @@ export const ArtworkList: FC = ({ listID }) => { hasMore={hasNext} isLoading={isLoadingNext} ListHeaderComponent={ - + = ({ collecti const hideSignals = CURATORS_PICKS_SLUGS.includes(collection.slug) return ( - - - + ) }, []) diff --git a/src/app/Scenes/Fair/Components/FairArtworks.tsx b/src/app/Scenes/Fair/Components/FairArtworks.tsx index 1615566df50..6a5c906d60b 100644 --- a/src/app/Scenes/Fair/Components/FairArtworks.tsx +++ b/src/app/Scenes/Fair/Components/FairArtworks.tsx @@ -99,16 +99,14 @@ export const FairArtworks: React.FC = ({ const imgHeight = imgWidth / imgAspectRatio return ( - - - + ) }, []) @@ -308,16 +306,14 @@ export const FairArtworksWithoutTabs: React.FC = ({ const imgHeight = imgWidth / imgAspectRatio return ( - - - + ) }} /> diff --git a/src/app/Scenes/InfiniteDiscovery/Components/InfiniteDiscoveryMoreWorksTab.tsx b/src/app/Scenes/InfiniteDiscovery/Components/InfiniteDiscoveryMoreWorksTab.tsx index 21902ed5c1f..d5f471dd06f 100644 --- a/src/app/Scenes/InfiniteDiscovery/Components/InfiniteDiscoveryMoreWorksTab.tsx +++ b/src/app/Scenes/InfiniteDiscovery/Components/InfiniteDiscoveryMoreWorksTab.tsx @@ -1,5 +1,5 @@ import { ContextModule, OwnerType } from "@artsy/cohesion" -import { Flex, SimpleMessage, Tabs, useScreenDimensions, useSpace } from "@artsy/palette-mobile" +import { SimpleMessage, Tabs, useScreenDimensions, useSpace } from "@artsy/palette-mobile" import { BottomSheetScrollView } from "@gorhom/bottom-sheet" import { ListRenderItem } from "@shopify/flash-list" import { InfiniteDiscoveryMoreWorksTabQuery } from "__generated__/InfiniteDiscoveryMoreWorksTabQuery.graphql" @@ -41,17 +41,15 @@ export const MoreWorksTab: FC = ({ artworks: _artworks }) => const imgHeight = imgWidth / imgAspectRatio return ( - - - + ) }, [] diff --git a/src/app/Scenes/MyCollection/Screens/ArtworkForm/Components/ArtworkAutosuggestResults.tsx b/src/app/Scenes/MyCollection/Screens/ArtworkForm/Components/ArtworkAutosuggestResults.tsx index a76e089f6e2..873d27facc3 100644 --- a/src/app/Scenes/MyCollection/Screens/ArtworkForm/Components/ArtworkAutosuggestResults.tsx +++ b/src/app/Scenes/MyCollection/Screens/ArtworkForm/Components/ArtworkAutosuggestResults.tsx @@ -99,16 +99,14 @@ const ArtworkAutosuggestResults: React.FC = ({ const imgHeight = imgWidth / imgAspectRatio return ( - - - + ) }} /> diff --git a/src/app/Scenes/Partner/Components/PartnerArtwork.tsx b/src/app/Scenes/Partner/Components/PartnerArtwork.tsx index e14e1ec99d1..a89558f4534 100644 --- a/src/app/Scenes/Partner/Components/PartnerArtwork.tsx +++ b/src/app/Scenes/Partner/Components/PartnerArtwork.tsx @@ -67,15 +67,13 @@ export const PartnerArtwork: React.FC<{ const imgHeight = imgWidth / imgAspectRatio return ( - - - + ) }, []) diff --git a/src/app/Scenes/Search/SearchArtworksGrid.tsx b/src/app/Scenes/Search/SearchArtworksGrid.tsx index 1393506f2a3..70f2b832453 100644 --- a/src/app/Scenes/Search/SearchArtworksGrid.tsx +++ b/src/app/Scenes/Search/SearchArtworksGrid.tsx @@ -137,16 +137,14 @@ const SearchArtworksGrid: React.FC = ({ viewer, relay, const imgHeight = imgWidth / imgAspectRatio return ( - - - + ) }} contentContainerStyle={{ diff --git a/src/app/Scenes/Tag/TagArtworks.tsx b/src/app/Scenes/Tag/TagArtworks.tsx index 3c35c62336a..03557153019 100644 --- a/src/app/Scenes/Tag/TagArtworks.tsx +++ b/src/app/Scenes/Tag/TagArtworks.tsx @@ -96,15 +96,13 @@ const TagArtworks: React.FC = ({ tag, relay }) => { const imgHeight = imgWidth / imgAspectRatio return ( - - - + ) }, []) From 3e31393302b4e9960057ec6d37ea0e8bb69d155e Mon Sep 17 00:00:00 2001 From: Mounir Dhahri Date: Fri, 21 Nov 2025 10:54:40 +0100 Subject: [PATCH 019/123] chore: remove unnecessary blurhash from setupjest --- src/setupJest.tsx | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/src/setupJest.tsx b/src/setupJest.tsx index 3f9bafb2541..4ab18c5cf74 100644 --- a/src/setupJest.tsx +++ b/src/setupJest.tsx @@ -98,13 +98,6 @@ jest.mock("react-native-permissions", () => ({ requestNotifications: jest.fn(), })) -jest.mock("react-native-blurhash", () => { - const ReactNative = require("react-native") - return { - Blurhash: ReactNative.View as any, - } -}) - require("jest-fetch-mock").enableMocks() jest.mock("react-tracking") @@ -693,12 +686,6 @@ jest.mock("app/utils/Sentinel", () => { Sentinel: View, } }) -jest.mock("react-native-blurhash", () => { - const ReactNative = require("react-native") - return { - Blurhash: ReactNative.View as any, - } -}) jest.mock("app/system/notifications/getNotificationsPermissions", () => ({ getNotificationPermissionsStatus: mockFetchNotificationPermissions, From a811fe4f4f330013343fc87495f922fefbf70266 Mon Sep 17 00:00:00 2001 From: Mounir Dhahri Date: Fri, 21 Nov 2025 10:57:18 +0100 Subject: [PATCH 020/123] chore: add missing package --- package.json | 1 + yarn.lock | 11 +++++++++++ 2 files changed, 12 insertions(+) diff --git a/package.json b/package.json index c8b10e826bb..0b96e919630 100644 --- a/package.json +++ b/package.json @@ -129,6 +129,7 @@ "@react-native-firebase/app": "23.1.0", "@react-native-firebase/messaging": "23.1.0", "@react-native-google-signin/google-signin": "11.0.1", + "@react-native-menu/menu": "^2.0.0", "@react-navigation/bottom-tabs": "7.4.8", "@react-navigation/elements": "2.6.5", "@react-navigation/material-top-tabs": "7.3.8", diff --git a/yarn.lock b/yarn.lock index 295fb4580e6..2b492d2219e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6498,6 +6498,16 @@ __metadata: languageName: node linkType: hard +"@react-native-menu/menu@npm:^2.0.0": + version: 2.0.0 + resolution: "@react-native-menu/menu@npm:2.0.0" + peerDependencies: + react: "*" + react-native: "*" + checksum: 10c0/1e88e1892730c70e28a654a8df6427f80f1b88880eaa62f2744072b9cebead4e834490d15ef7f0b91eadf9cb1ec9241b29f116ce7e94661685b41faf10af3fa3 + languageName: node + linkType: hard + "@react-native/assets-registry@npm:0.81.5": version: 0.81.5 resolution: "@react-native/assets-registry@npm:0.81.5" @@ -13188,6 +13198,7 @@ __metadata: "@react-native-firebase/app": "npm:23.1.0" "@react-native-firebase/messaging": "npm:23.1.0" "@react-native-google-signin/google-signin": "npm:11.0.1" + "@react-native-menu/menu": "npm:^2.0.0" "@react-native/babel-preset": "npm:0.81.5" "@react-native/eslint-config": "npm:0.81.5" "@react-native/metro-config": "npm:0.81.5" From 2cef231870f90b1db24bb23f7eba64665e4e38a8 Mon Sep 17 00:00:00 2001 From: Mounir Dhahri Date: Fri, 21 Nov 2025 11:01:36 +0100 Subject: [PATCH 021/123] chore: run yarn install again --- ios/Podfile.lock | 32 ++++++++++++++++++++++++++++++++ package.json | 2 +- yarn.lock | 4 ++-- 3 files changed, 35 insertions(+), 3 deletions(-) diff --git a/ios/Podfile.lock b/ios/Podfile.lock index a8946bdd763..623d684c5b6 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -2344,6 +2344,34 @@ PODS: - Yoga - react-native-launch-arguments (4.1.0): - React + - react-native-menu (2.0.0): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - hermes-engine + - RCT-Folly + - RCT-Folly/Fabric + - RCTRequired + - RCTTypeSafety + - React-Core + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-ImageManager + - React-jsi + - React-NativeModulesApple + - React-RCTFabric + - React-renderercss + - React-rendererdebug + - React-utils + - ReactCodegen + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - SocketRocket + - Yoga - react-native-netinfo (11.4.1): - React-Core - react-native-pager-view (6.7.1): @@ -4013,6 +4041,7 @@ DEPENDENCIES: - react-native-ios-utilities (from `../node_modules/react-native-ios-utilities`) - react-native-keys (from `../node_modules/react-native-keys`) - react-native-launch-arguments (from `../node_modules/react-native-launch-arguments`) + - "react-native-menu (from `../node_modules/@react-native-menu/menu`)" - "react-native-netinfo (from `../node_modules/@react-native-community/netinfo`)" - react-native-pager-view (from `../node_modules/react-native-pager-view`) - react-native-performance (from `../node_modules/react-native-performance`) @@ -4328,6 +4357,8 @@ EXTERNAL SOURCES: :path: "../node_modules/react-native-keys" react-native-launch-arguments: :path: "../node_modules/react-native-launch-arguments" + react-native-menu: + :path: "../node_modules/@react-native-menu/menu" react-native-netinfo: :path: "../node_modules/@react-native-community/netinfo" react-native-pager-view: @@ -4613,6 +4644,7 @@ SPEC CHECKSUMS: react-native-ios-utilities: d9ed1f5ea011650e9c7e9cb7c82272c1f0363e44 react-native-keys: 80dc5f204b236ff384be06a514294eb24c65bd1f react-native-launch-arguments: 165260aba9544f00c66fae3e136b11484d0cb49b + react-native-menu: 8d2c831a735c9e6528c28b26ca14e57591d87e14 react-native-netinfo: cec9c4e86083cb5b6aba0e0711f563e2fbbff187 react-native-pager-view: 4669cb3244c99fec52997f8906dd92f44b6ae17e react-native-performance: 1cff1830de6c7b64d56b5c0c92b6dbece74acc03 diff --git a/package.json b/package.json index 0b96e919630..ad595308d1a 100644 --- a/package.json +++ b/package.json @@ -166,7 +166,7 @@ "react-fps": "1.0.6", "react-native": "0.81.5", "react-native-blob-util": "0.19.11", - "react-native-blurhash": "^2.1.2", + "react-native-blurhash": "2.1.2", "react-native-bootsplash": "6.3.10", "react-native-collapsible-tab-view": "8.0.1", "react-native-device-info": "14.0.0", diff --git a/yarn.lock b/yarn.lock index 2b492d2219e..ffa94698d84 100644 --- a/yarn.lock +++ b/yarn.lock @@ -13323,7 +13323,7 @@ __metadata: react-fps: "npm:1.0.6" react-native: "npm:0.81.5" react-native-blob-util: "npm:0.19.11" - react-native-blurhash: "npm:^2.1.2" + react-native-blurhash: "npm:2.1.2" react-native-bootsplash: "npm:6.3.10" react-native-collapsible-tab-view: "npm:8.0.1" react-native-device-info: "npm:14.0.0" @@ -22050,7 +22050,7 @@ __metadata: languageName: node linkType: hard -"react-native-blurhash@npm:2.1.2, react-native-blurhash@npm:^2.1.2": +"react-native-blurhash@npm:2.1.2": version: 2.1.2 resolution: "react-native-blurhash@npm:2.1.2" peerDependencies: From 5af97db9564003c1ddec064148581285f725d8a6 Mon Sep 17 00:00:00 2001 From: Mounir Dhahri Date: Fri, 21 Nov 2025 11:06:56 +0100 Subject: [PATCH 022/123] fix: broken test --- package.json | 2 +- src/__mocks__/react-native-blurhash/index.js | 3 +++ yarn.lock | 10 +++++----- 3 files changed, 9 insertions(+), 6 deletions(-) create mode 100644 src/__mocks__/react-native-blurhash/index.js diff --git a/package.json b/package.json index ad595308d1a..4f3fba5ec03 100644 --- a/package.json +++ b/package.json @@ -129,7 +129,7 @@ "@react-native-firebase/app": "23.1.0", "@react-native-firebase/messaging": "23.1.0", "@react-native-google-signin/google-signin": "11.0.1", - "@react-native-menu/menu": "^2.0.0", + "@react-native-menu/menu": "1.2.2", "@react-navigation/bottom-tabs": "7.4.8", "@react-navigation/elements": "2.6.5", "@react-navigation/material-top-tabs": "7.3.8", diff --git a/src/__mocks__/react-native-blurhash/index.js b/src/__mocks__/react-native-blurhash/index.js new file mode 100644 index 00000000000..a356abeee5b --- /dev/null +++ b/src/__mocks__/react-native-blurhash/index.js @@ -0,0 +1,3 @@ +module.exports = { + Blurhash: () => null, +} diff --git a/yarn.lock b/yarn.lock index ffa94698d84..9714349cac8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6498,13 +6498,13 @@ __metadata: languageName: node linkType: hard -"@react-native-menu/menu@npm:^2.0.0": - version: 2.0.0 - resolution: "@react-native-menu/menu@npm:2.0.0" +"@react-native-menu/menu@npm:1.2.2": + version: 1.2.2 + resolution: "@react-native-menu/menu@npm:1.2.2" peerDependencies: react: "*" react-native: "*" - checksum: 10c0/1e88e1892730c70e28a654a8df6427f80f1b88880eaa62f2744072b9cebead4e834490d15ef7f0b91eadf9cb1ec9241b29f116ce7e94661685b41faf10af3fa3 + checksum: 10c0/947e882524e7ee7c0ac77d81119c6eb0cb0c1f66156d61c1e1b50c46960a768f1b4e2149610a7a30a1f2a921c0694ecbbb401b5758785a0120f993006259d099 languageName: node linkType: hard @@ -13198,7 +13198,7 @@ __metadata: "@react-native-firebase/app": "npm:23.1.0" "@react-native-firebase/messaging": "npm:23.1.0" "@react-native-google-signin/google-signin": "npm:11.0.1" - "@react-native-menu/menu": "npm:^2.0.0" + "@react-native-menu/menu": "npm:1.2.2" "@react-native/babel-preset": "npm:0.81.5" "@react-native/eslint-config": "npm:0.81.5" "@react-native/metro-config": "npm:0.81.5" From 9528a92f60cfeb3ab9f0f97dce821662a83498b6 Mon Sep 17 00:00:00 2001 From: Mounir Dhahri Date: Fri, 21 Nov 2025 11:08:19 +0100 Subject: [PATCH 023/123] fix: silence temporarily --- fastlane/utility_fastlane.rb | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/fastlane/utility_fastlane.rb b/fastlane/utility_fastlane.rb index 4fe5af79c3e..d697b3b3770 100644 --- a/fastlane/utility_fastlane.rb +++ b/fastlane/utility_fastlane.rb @@ -95,15 +95,16 @@ run_id = ENV['GITHUB_RUN_ID'] github_url = "https://github.com/#{github_repo}/actions/runs/#{run_id}" - slack( - message: message, - success: false, - payload: { - 'GitHub Actions' => github_url, - 'Exception' => exception.message - }, - default_payloads: [] - ) + # TODO: Enable again + # slack( + # message: message, + # success: false, + # payload: { + # 'GitHub Actions' => github_url, + # 'Exception' => exception.message + # }, + # default_payloads: [] + # ) end desc "Notifies in slack if a new beta is needed" From 1fea9b629900a63c525a71df7d52d4b623da98ac Mon Sep 17 00:00:00 2001 From: Mounir Dhahri Date: Fri, 21 Nov 2025 11:21:04 +0100 Subject: [PATCH 024/123] fix: infinite discovery issues --- scripts/utils/flip-table | 65 ------------------ .../Components/InfiniteDiscoveryHeader.tsx | 2 +- .../Components/Swiper/Swiper.tsx | 68 ++++++++++--------- .../InfiniteDiscovery/InfiniteDiscovery.tsx | 9 +-- 4 files changed, 41 insertions(+), 103 deletions(-) delete mode 100755 scripts/utils/flip-table diff --git a/scripts/utils/flip-table b/scripts/utils/flip-table deleted file mode 100755 index 1b38105f2c9..00000000000 --- a/scripts/utils/flip-table +++ /dev/null @@ -1,65 +0,0 @@ -#!/usr/bin/env bash -set -euxo pipefail - - -# Clear local caches and build files - -echo 'Clear watchman (┛ಠ_ಠ)┛彡┻━┻' -watchman watch-del-all - -echo 'Clear gradle cache' -if [ -d node_modules ]; then - cd android - ./gradlew clean - cd - -fi - -echo 'Clear JS caches (┛ಠ_ಠ)┛彡┻━┻' -rm -rf .cache - -echo 'Clear gems (┛ಠ_ಠ)┛彡┻━┻' -rm -rf .vendor - -echo 'Clear node modules (┛ಠ_ಠ)┛彡┻━┻' -rm -rf node_modules - -echo 'Clear cocoapods directory (ノಠ益ಠ)ノ彡┻━┻' -rm -rf Pods - -echo 'Clear Xcode derived data (╯°□°)╯︵ ┻━┻' -# sometimes this fails on first try even with -rf -# but a second try takes it home -if ! rm -rf ~/Library/Developer/Xcode/DerivedData; then - rm -rf ~/Library/Developer/Xcode/DerivedData -fi - -echo 'Clear Xcode generated .env (╯°□°)╯︵ ┻━┻' -rm -rf ios/.xcode.env.local - -echo 'Reset yalc linked packages (ノಠдಠ)ノ︵┻━┻' -if command -v yalc &> /dev/null -then - yalc remove @artsy/palette-mobile -fi - -echo 'Clear relay, relay query map, jest, and metro caches (┛◉Д◉)┛彡┻━┻' -rm -rf "$TMPDIR"/RelayFindGraphQLTags-* -rm -rf data/complete.queryMap.json -rm -rf .cache -rm -rf "$TMPDIR"/metro* -rm -rf src/__generated__/*.graphql.ts - - - -echo 'Clear build artefacts (╯ರ ~ ರ)╯︵ ┻━┻' -find dist/ ! -name '.gitkeep' -type f -exec rm -f {} + - -echo 'Setup Assets' -# Required for yarn 4 -yarn install -yarn setup:artsy - -echo 'Reinstall dependencies ┬─┬ノ( º _ ºノ)' -yarn install:all - -./scripts/setup/update-echo diff --git a/src/app/Scenes/InfiniteDiscovery/Components/InfiniteDiscoveryHeader.tsx b/src/app/Scenes/InfiniteDiscovery/Components/InfiniteDiscoveryHeader.tsx index cfaa5dd4a1a..b21d158bfaf 100644 --- a/src/app/Scenes/InfiniteDiscovery/Components/InfiniteDiscoveryHeader.tsx +++ b/src/app/Scenes/InfiniteDiscovery/Components/InfiniteDiscoveryHeader.tsx @@ -63,7 +63,7 @@ export const InfiniteDiscoveryHeader: React.FC = ( } return ( - + React.ReactNode + isArtworkSaved?: (index: number) => boolean onNewCardReached?: (key: Key) => void onRewind: (key: Key) => void onSwipe: (swipedKey: Key, nextKey: Key) => void - containerStyle?: ViewStyle - cardStyle?: ViewStyle - isArtworkSaved?: (index: number) => boolean } & ( | { onReachTriggerIndex?: never; triggerIndex?: never } | { onReachTriggerIndex: (activeIndex: number) => void; triggerIndex: number } @@ -38,14 +40,15 @@ export const Swiper = forwardRef( ( { cards: _cards, + cardStyle, + containerStyle, + HeaderComponent, + isArtworkSaved, onNewCardReached, + onReachTriggerIndex, onRewind, onSwipe, - onReachTriggerIndex, triggerIndex, - containerStyle, - cardStyle, - isArtworkSaved, }, ref ) => { @@ -202,32 +205,35 @@ export const Swiper = forwardRef( return ( - {cards.map((c, i) => { - if (i < initialSliceIndex) { - return null - } + {!!HeaderComponent && } + + {cards.map((c, i) => { + if (i < initialSliceIndex) { + return null + } - return ( - - - - ) - })} + activeCardX={activeCardX} + activeIndex={_activeIndex} + swipedKeys={swipedKeys} + swipedCardX={swipedCardX} + key={c.internalID} + internalID={c.internalID} + > + + + ) + })} + ) diff --git a/src/app/Scenes/InfiniteDiscovery/InfiniteDiscovery.tsx b/src/app/Scenes/InfiniteDiscovery/InfiniteDiscovery.tsx index 04d542f4304..93e3c738bb4 100644 --- a/src/app/Scenes/InfiniteDiscovery/InfiniteDiscovery.tsx +++ b/src/app/Scenes/InfiniteDiscovery/InfiniteDiscovery.tsx @@ -1,5 +1,5 @@ import { ContextModule } from "@artsy/cohesion" -import { Screen, Spacer } from "@artsy/palette-mobile" +import { Screen } from "@artsy/palette-mobile" import { captureMessage } from "@sentry/react-native" import { InfiniteDiscoveryNegativeSignalsBottomSheetQuery$variables } from "__generated__/InfiniteDiscoveryNegativeSignalsBottomSheetQuery.graphql" import { InfiniteDiscoveryQueryRendererQuery$data } from "__generated__/InfiniteDiscoveryQueryRendererQuery.graphql" @@ -180,12 +180,9 @@ export const InfiniteDiscovery: React.FC = ({ - https://github.com/facebook/react-native/issues/47140 */} - - - - } + cards={[artworks[0]]} onReachTriggerIndex={handleFetchMore} triggerIndex={2} onNewCardReached={handleNewCardReached} From 932cf11f482468519767b17cb635b10a05397fb0 Mon Sep 17 00:00:00 2001 From: Mounir Dhahri Date: Fri, 21 Nov 2025 11:24:16 +0100 Subject: [PATCH 025/123] fix: cleanup --- ios/Podfile.lock | 4 ++-- package.json | 2 +- patches/react-native+0.81.5.patch | 7 ------- ...h+2.1.1.patch => react-native-blurhash+2.1.2.patch} | 0 yarn.lock | 10 +++++----- 5 files changed, 8 insertions(+), 15 deletions(-) rename patches/{react-native-blurhash+2.1.1.patch => react-native-blurhash+2.1.2.patch} (100%) diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 623d684c5b6..39289afa801 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -2344,7 +2344,7 @@ PODS: - Yoga - react-native-launch-arguments (4.1.0): - React - - react-native-menu (2.0.0): + - react-native-menu (1.2.2): - boost - DoubleConversion - fast_float @@ -4644,7 +4644,7 @@ SPEC CHECKSUMS: react-native-ios-utilities: d9ed1f5ea011650e9c7e9cb7c82272c1f0363e44 react-native-keys: 80dc5f204b236ff384be06a514294eb24c65bd1f react-native-launch-arguments: 165260aba9544f00c66fae3e136b11484d0cb49b - react-native-menu: 8d2c831a735c9e6528c28b26ca14e57591d87e14 + react-native-menu: 5962c8b2413669b5013c3579554df4d8b856c887 react-native-netinfo: cec9c4e86083cb5b6aba0e0711f563e2fbbff187 react-native-pager-view: 4669cb3244c99fec52997f8906dd92f44b6ae17e react-native-performance: 1cff1830de6c7b64d56b5c0c92b6dbece74acc03 diff --git a/package.json b/package.json index 4f3fba5ec03..21fd5c9e218 100644 --- a/package.json +++ b/package.json @@ -109,7 +109,7 @@ "dependencies": { "@artsy/cohesion": "4.336.0", "@artsy/icons": "3.63.0", - "@artsy/palette-mobile": "22.1.0--canary.425.5083.0", + "@artsy/palette-mobile": "22.1.0--canary.425.5095.0", "@artsy/to-title-case": "1.2.0", "@braze/react-native-sdk": "16.1.0", "@d11/react-native-fast-image": "8.12.0", diff --git a/patches/react-native+0.81.5.patch b/patches/react-native+0.81.5.patch index ea99383bc5e..935253e9afe 100644 --- a/patches/react-native+0.81.5.patch +++ b/patches/react-native+0.81.5.patch @@ -34,10 +34,3 @@ index e0742c9..77fab8b 100644 } bool traceTurboModulePromiseRejectionsOnAndroid() override { -diff --git a/node_modules/react-native/scripts/.packager.env b/node_modules/react-native/scripts/.packager.env -new file mode 100644 -index 0000000..361f5fb ---- /dev/null -+++ b/node_modules/react-native/scripts/.packager.env -@@ -0,0 +1 @@ -+export RCT_METRO_PORT=8081 diff --git a/patches/react-native-blurhash+2.1.1.patch b/patches/react-native-blurhash+2.1.2.patch similarity index 100% rename from patches/react-native-blurhash+2.1.1.patch rename to patches/react-native-blurhash+2.1.2.patch diff --git a/yarn.lock b/yarn.lock index 9714349cac8..675a4460cda 100644 --- a/yarn.lock +++ b/yarn.lock @@ -72,9 +72,9 @@ __metadata: languageName: node linkType: hard -"@artsy/palette-mobile@npm:22.1.0--canary.425.5083.0": - version: 22.1.0--canary.425.5083.0 - resolution: "@artsy/palette-mobile@npm:22.1.0--canary.425.5083.0" +"@artsy/palette-mobile@npm:22.1.0--canary.425.5095.0": + version: 22.1.0--canary.425.5095.0 + resolution: "@artsy/palette-mobile@npm:22.1.0--canary.425.5095.0" dependencies: "@artsy/icons": "npm:^3.49.0" "@artsy/palette-tokens": "npm:7.0.0" @@ -101,7 +101,7 @@ __metadata: react-native-reanimated: "*" react-native-svg: "*" styled-components: ">= 5" - checksum: 10c0/0a5b0980b6526372d340526b92cb8c60a83e365d9f5c781e5369af2ecb065a0a153fce935a7fcb37c3f23893d1a55853c38373eeef5715eb89c82530a1769acf + checksum: 10c0/031e17e39d4609b92233a98f856993081dd1914c944b08fe4a1b3e9a40c66fa6296bdc4d079972b88c00e6c9e1e41eb569f5fd45dacad4ce62f20461da62e522 languageName: node linkType: hard @@ -13165,7 +13165,7 @@ __metadata: dependencies: "@artsy/cohesion": "npm:4.336.0" "@artsy/icons": "npm:3.63.0" - "@artsy/palette-mobile": "npm:22.1.0--canary.425.5083.0" + "@artsy/palette-mobile": "npm:22.1.0--canary.425.5095.0" "@artsy/to-title-case": "npm:1.2.0" "@artsy/update-repo": "npm:0.7.0" "@babel/core": "npm:7.25.2" From 9cb2799f45271e46358e1328fd872b4f4a67a539 Mon Sep 17 00:00:00 2001 From: Mounir Dhahri Date: Fri, 21 Nov 2025 11:52:27 +0100 Subject: [PATCH 026/123] fix: skip building react-native-context --- ios/Podfile.lock | 4 ++-- package.json | 2 +- react-native.config.js | 6 ++++++ yarn.lock | 23 ++++++----------------- 4 files changed, 15 insertions(+), 20 deletions(-) diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 39289afa801..5c89de36252 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -3950,7 +3950,7 @@ DEPENDENCIES: - CocoaLumberjack (= 3.9.0) - DoubleConversion (from `../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec`) - EASClient (from `../node_modules/expo-eas-client/ios`) - - EXConstants (from `../node_modules/expo-constants/ios`) + - EXConstants (from `../node_modules/expo/node_modules/expo-constants/ios`) - EXJSONUtils (from `../node_modules/expo-json-utils/ios`) - EXManifests (from `../node_modules/expo-manifests/ios`) - Expecta (= 1.0.6) @@ -4221,7 +4221,7 @@ EXTERNAL SOURCES: EASClient: :path: "../node_modules/expo-eas-client/ios" EXConstants: - :path: "../node_modules/expo-constants/ios" + :path: "../node_modules/expo/node_modules/expo-constants/ios" EXJSONUtils: :path: "../node_modules/expo-json-utils/ios" EXManifests: diff --git a/package.json b/package.json index 21fd5c9e218..f87c69a133f 100644 --- a/package.json +++ b/package.json @@ -109,7 +109,7 @@ "dependencies": { "@artsy/cohesion": "4.336.0", "@artsy/icons": "3.63.0", - "@artsy/palette-mobile": "22.1.0--canary.425.5095.0", + "@artsy/palette-mobile": "22.2.0--canary.425.5115.0", "@artsy/to-title-case": "1.2.0", "@braze/react-native-sdk": "16.1.0", "@d11/react-native-fast-image": "8.12.0", diff --git a/react-native.config.js b/react-native.config.js index 72207d90c7c..87acebf6d5d 100644 --- a/react-native.config.js +++ b/react-native.config.js @@ -6,5 +6,11 @@ module.exports = { android: null, }, }, + "@react-native-menu/menu": { + platforms: { + // Skip auto-linking here because we don't use it on android + android: null, + }, + }, }, } diff --git a/yarn.lock b/yarn.lock index 675a4460cda..416f1ff60f8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -72,9 +72,9 @@ __metadata: languageName: node linkType: hard -"@artsy/palette-mobile@npm:22.1.0--canary.425.5095.0": - version: 22.1.0--canary.425.5095.0 - resolution: "@artsy/palette-mobile@npm:22.1.0--canary.425.5095.0" +"@artsy/palette-mobile@npm:22.2.0--canary.425.5115.0": + version: 22.2.0--canary.425.5115.0 + resolution: "@artsy/palette-mobile@npm:22.2.0--canary.425.5115.0" dependencies: "@artsy/icons": "npm:^3.49.0" "@artsy/palette-tokens": "npm:7.0.0" @@ -84,7 +84,7 @@ __metadata: "@styled-system/theme-get": "npm:^5.1.2" events: "npm:^3.3.0" lodash: "npm:^4.17.21" - moti: "npm:^0.25.3" + moti: "npm:0.30.0" react-nanny: "npm:^2.15.0" react-native-blurhash: "npm:2.1.2" react-native-collapsible-tab-view: "npm:^8.0.1" @@ -101,7 +101,7 @@ __metadata: react-native-reanimated: "*" react-native-svg: "*" styled-components: ">= 5" - checksum: 10c0/031e17e39d4609b92233a98f856993081dd1914c944b08fe4a1b3e9a40c66fa6296bdc4d079972b88c00e6c9e1e41eb569f5fd45dacad4ce62f20461da62e522 + checksum: 10c0/ab890f705d528b02ea314a6c0e8358ad9e3eff39c4560eb0f53e1a846de03da19a55f557b6a8ab53fe71200555608e6b4d317bcbaa5e9f9d676885eba65cb9d2 languageName: node linkType: hard @@ -13165,7 +13165,7 @@ __metadata: dependencies: "@artsy/cohesion": "npm:4.336.0" "@artsy/icons": "npm:3.63.0" - "@artsy/palette-mobile": "npm:22.1.0--canary.425.5095.0" + "@artsy/palette-mobile": "npm:22.2.0--canary.425.5115.0" "@artsy/to-title-case": "npm:1.2.0" "@artsy/update-repo": "npm:0.7.0" "@babel/core": "npm:7.25.2" @@ -20233,17 +20233,6 @@ __metadata: languageName: node linkType: hard -"moti@npm:^0.25.3": - version: 0.25.4 - resolution: "moti@npm:0.25.4" - dependencies: - framer-motion: "npm:^6.5.1" - peerDependencies: - react-native-reanimated: "*" - checksum: 10c0/622b8fb2ef48af06a22854e23dbe73acc16bf48e2d9f79f4061139123044ef8227a14a5ae3dbc617110763eaffd74ad99dd55aa4c0da8a5200c7069981ef06ef - languageName: node - linkType: hard - "ms@npm:2.0.0": version: 2.0.0 resolution: "ms@npm:2.0.0" From 4058e9a9446c0443ef366de3a413c3c87dca1818 Mon Sep 17 00:00:00 2001 From: Mounir Dhahri Date: Wed, 3 Dec 2025 10:32:30 +0100 Subject: [PATCH 027/123] chore: address pairing review comments Co-authored-by: George --- src/app/App.tsx | 3 -- .../Artist/ArtistHeaderNavRight.tsx | 49 +++++++++++-------- .../InfiniteDiscovery/InfiniteDiscovery.tsx | 2 +- 3 files changed, 30 insertions(+), 24 deletions(-) diff --git a/src/app/App.tsx b/src/app/App.tsx index 56d504f20e4..85499408261 100644 --- a/src/app/App.tsx +++ b/src/app/App.tsx @@ -28,7 +28,6 @@ import { NativeModules, UIManager, View } from "react-native" import { Settings } from "react-native-fbsdk-next" import "react-native-get-random-values" import Keys from "react-native-keys" -import { enableFreeze } from "react-native-screens" import { useWebViewCookies } from "./Components/ArtsyWebView" import { Providers } from "./Providers" import { ForceUpdate } from "./Scenes/ForceUpdate/ForceUpdate" @@ -42,8 +41,6 @@ import useSyncNativeAuthState from "./utils/useSyncAuthState" require("./system/ignoreLogs") -enableFreeze(true) - if (__DEV__) { // Don't open RN dev menu with shake. We use it for our own Dev Menu. NativeModules.DevSettings.setIsShakeToShowDevMenuEnabled(false) diff --git a/src/app/Components/Artist/ArtistHeaderNavRight.tsx b/src/app/Components/Artist/ArtistHeaderNavRight.tsx index e46049e1ff6..547171a0d5d 100644 --- a/src/app/Components/Artist/ArtistHeaderNavRight.tsx +++ b/src/app/Components/Artist/ArtistHeaderNavRight.tsx @@ -50,24 +50,33 @@ export const ArtistHeaderNavRight: React.FC = ({ }) // convert the space into primitive types to be user on the UI thread - const space1 = space(1) const space2 = space(2) - const spacerWidth = useDerivedValue( - () => (displayFollowButton.value ? space1 : space2), - [space1, space2] - ) + const followButtonTranslateX = useDerivedValue(() => displayFollowButton.value ? 0 : followAreaDeltaX ) + const followButtonOpacity = useDerivedValue(() => (displayFollowButton.value ? 1 : 0)) + const viewStyle = useAnimatedStyle( () => ({ - left: withTiming(followButtonTranslateX.value, { duration: 200, easing: Easing.sin }), + transform: [ + { + translateX: withTiming( + followButtonTranslateX.value - (displayFollowButton.value ? 0 : space2), + { + duration: 200, + easing: Easing.sin, + } + ), + }, + ], }), [followAreaDeltaX] ) - const spacerStyle = useAnimatedStyle(() => ({ - width: withTiming(spacerWidth.value, { duration: 200 }), + + const followButtonStyle = useAnimatedStyle(() => ({ + opacity: withTiming(followButtonOpacity.value, { duration: 200 }), })) const handleSharePress = useCallback(() => { @@ -101,18 +110,18 @@ export const ArtistHeaderNavRight: React.FC = ({ - - - setIsFollowed(!isFollowed)} - // Using maxWidth and minWidth to prevent the button from changing width when the text changes - maxWidth={followButtonWidth} - minWidth={followButtonWidth} - /> + + setIsFollowed(!isFollowed)} + // Using maxWidth and minWidth to prevent the button from changing width when the text changes + maxWidth={followButtonWidth} + minWidth={followButtonWidth} + /> + ) diff --git a/src/app/Scenes/InfiniteDiscovery/InfiniteDiscovery.tsx b/src/app/Scenes/InfiniteDiscovery/InfiniteDiscovery.tsx index 93e3c738bb4..eb7a7bf7553 100644 --- a/src/app/Scenes/InfiniteDiscovery/InfiniteDiscovery.tsx +++ b/src/app/Scenes/InfiniteDiscovery/InfiniteDiscovery.tsx @@ -182,7 +182,7 @@ export const InfiniteDiscovery: React.FC = ({ } - cards={[artworks[0]]} + cards={artworks} onReachTriggerIndex={handleFetchMore} triggerIndex={2} onNewCardReached={handleNewCardReached} From e20b553bf8e3bb8f05a54962a7a16266cd274aa9 Mon Sep 17 00:00:00 2001 From: Mounir Dhahri Date: Wed, 3 Dec 2025 11:25:36 +0100 Subject: [PATCH 028/123] fix: share modal broken snap points --- package.json | 2 +- src/app/Components/ShareSheet/ShareSheet.tsx | 2 +- yarn.lock | 10 +++++----- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/package.json b/package.json index f87c69a133f..58e0dbeac02 100644 --- a/package.json +++ b/package.json @@ -114,7 +114,7 @@ "@braze/react-native-sdk": "16.1.0", "@d11/react-native-fast-image": "8.12.0", "@expo/react-native-action-sheet": "4.1.1", - "@gorhom/bottom-sheet": "5.1.8", + "@gorhom/bottom-sheet": "5.2.6", "@gorhom/portal": "1.0.14", "@invertase/react-native-apple-authentication": "2.1.5", "@kesha-antonov/react-native-action-cable": "1.1.4", diff --git a/src/app/Components/ShareSheet/ShareSheet.tsx b/src/app/Components/ShareSheet/ShareSheet.tsx index 68595fd8dc8..2aa5760f403 100644 --- a/src/app/Components/ShareSheet/ShareSheet.tsx +++ b/src/app/Components/ShareSheet/ShareSheet.tsx @@ -189,7 +189,7 @@ export const ShareSheet = () => { diff --git a/yarn.lock b/yarn.lock index 416f1ff60f8..5f751982666 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4575,9 +4575,9 @@ __metadata: languageName: node linkType: hard -"@gorhom/bottom-sheet@npm:5.1.8": - version: 5.1.8 - resolution: "@gorhom/bottom-sheet@npm:5.1.8" +"@gorhom/bottom-sheet@npm:5.2.6": + version: 5.2.6 + resolution: "@gorhom/bottom-sheet@npm:5.2.6" dependencies: "@gorhom/portal": "npm:1.0.14" invariant: "npm:^2.2.4" @@ -4593,7 +4593,7 @@ __metadata: optional: true "@types/react-native": optional: true - checksum: 10c0/b1faa4bf495f2be814cc2477893fbe758282142b5e4a404eacabd0b76475975f17339fabce388719645a02c17ee999e86cffa26e847a40c9c38e98c5c342ee45 + checksum: 10c0/6caa4b963608bae84e4f8be17140e46b38d982c0c5531f98191d98185864dd1221e21cac464df3db6ce5e4733d03887ecb75bc0d044a25501e599604962aab80 languageName: node linkType: hard @@ -13179,7 +13179,7 @@ __metadata: "@braze/react-native-sdk": "npm:16.1.0" "@d11/react-native-fast-image": "npm:8.12.0" "@expo/react-native-action-sheet": "npm:4.1.1" - "@gorhom/bottom-sheet": "npm:5.1.8" + "@gorhom/bottom-sheet": "npm:5.2.6" "@gorhom/portal": "npm:1.0.14" "@invertase/react-native-apple-authentication": "npm:2.1.5" "@kesha-antonov/react-native-action-cable": "npm:1.1.4" From ae5480a047ebe3bfe529dcdab0c03a82b41dd8c6 Mon Sep 17 00:00:00 2001 From: Mounir Dhahri Date: Wed, 3 Dec 2025 11:49:14 +0100 Subject: [PATCH 029/123] fix: broken centering on create alert inside artwork screen --- .../Artwork/Components/ArtworkScreenHeaderCreateAlert.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/app/Scenes/Artwork/Components/ArtworkScreenHeaderCreateAlert.tsx b/src/app/Scenes/Artwork/Components/ArtworkScreenHeaderCreateAlert.tsx index d5031b2be58..4f7bec9645f 100644 --- a/src/app/Scenes/Artwork/Components/ArtworkScreenHeaderCreateAlert.tsx +++ b/src/app/Scenes/Artwork/Components/ArtworkScreenHeaderCreateAlert.tsx @@ -1,6 +1,6 @@ import { ContextModule, OwnerType } from "@artsy/cohesion" import { BellStrokeIcon } from "@artsy/icons/native" -import { Button } from "@artsy/palette-mobile" +import { Button, Flex } from "@artsy/palette-mobile" import { ArtworkScreenHeaderCreateAlert_artwork$key } from "__generated__/ArtworkScreenHeaderCreateAlert_artwork.graphql" import { CreateArtworkAlertModal } from "app/Components/Artist/ArtistArtworks/CreateArtworkAlertModal" import { hasBiddingEnded } from "app/Scenes/Artwork/utils/hasBiddingEnded" @@ -44,7 +44,7 @@ export const ArtworkScreenHeaderCreateAlert: React.FC + )} @@ -291,7 +292,7 @@ const SocialLoginButtons: React.FC = () => { accessibilityLabel="Google" > - + From 3f7bb528f769b62be89f91f2fbc3a71a8c3258c5 Mon Sep 17 00:00:00 2001 From: Mounir Dhahri Date: Mon, 15 Dec 2025 15:46:53 +0100 Subject: [PATCH 056/123] chore: disable tab switch animation --- src/app/Navigation/AuthenticatedRoutes/Tabs.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/Navigation/AuthenticatedRoutes/Tabs.tsx b/src/app/Navigation/AuthenticatedRoutes/Tabs.tsx index 2af8aa28727..1fddfcc9fdd 100644 --- a/src/app/Navigation/AuthenticatedRoutes/Tabs.tsx +++ b/src/app/Navigation/AuthenticatedRoutes/Tabs.tsx @@ -98,7 +98,7 @@ const AppTabs: React.FC = () => { currentRoute && modules[currentRoute as AppModule]?.options?.hidesBottomTabs return { - animation: "fade", + animation: "none", headerShown: false, tabBarStyle: { animate: true, From 8faff58ed5b55083bb9fa4ba4bbca8745e3f5cf8 Mon Sep 17 00:00:00 2001 From: Mounir Dhahri Date: Mon, 15 Dec 2025 16:05:01 +0100 Subject: [PATCH 057/123] fix: broken padding inside artist modals --- src/app/Components/ArtworkFilter/ArtworkFilterNavigator.tsx | 6 +++--- src/app/Scenes/SavedSearchAlert/CreateSavedSearchAlert.tsx | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/app/Components/ArtworkFilter/ArtworkFilterNavigator.tsx b/src/app/Components/ArtworkFilter/ArtworkFilterNavigator.tsx index 138453390e1..4fb8c84c4f6 100644 --- a/src/app/Components/ArtworkFilter/ArtworkFilterNavigator.tsx +++ b/src/app/Components/ArtworkFilter/ArtworkFilterNavigator.tsx @@ -1,5 +1,5 @@ import { ActionType, ContextModule, OwnerType, TappedCreateAlert } from "@artsy/cohesion" -import { useColor } from "@artsy/palette-mobile" +import { Flex, useColor } from "@artsy/palette-mobile" import { NavigationContainer, NavigationIndependentTree } from "@react-navigation/native" import { TransitionPresets, createStackNavigator } from "@react-navigation/stack" import { @@ -344,7 +344,7 @@ export const ArtworkFilterNavigator: React.FC = (props) => { testID="artwork-filter-navigator" presentationStyle="overFullScreen" > - + = (props) => { attributes={attributes} sizeMetric={filterState.sizeMetric} /> - + diff --git a/src/app/Scenes/SavedSearchAlert/CreateSavedSearchAlert.tsx b/src/app/Scenes/SavedSearchAlert/CreateSavedSearchAlert.tsx index 2e453ebcb27..9e1576070eb 100644 --- a/src/app/Scenes/SavedSearchAlert/CreateSavedSearchAlert.tsx +++ b/src/app/Scenes/SavedSearchAlert/CreateSavedSearchAlert.tsx @@ -1,4 +1,4 @@ -import { useColor } from "@artsy/palette-mobile" +import { Flex, useColor } from "@artsy/palette-mobile" import { NavigationContainer, NavigationIndependentTree } from "@react-navigation/native" import { TransitionPresets, createStackNavigator } from "@react-navigation/stack" import { useNavigationTheme } from "app/Navigation/useNavigationTheme" @@ -53,7 +53,7 @@ export const CreateSavedSearchAlert: React.FC = (pr statusBarTranslucent animationType="slide" > - = (pr /> - + From 21bb5f53d31b42902de2784751cf529393fb233d Mon Sep 17 00:00:00 2001 From: Mounir Dhahri Date: Mon, 15 Dec 2025 16:05:25 +0100 Subject: [PATCH 058/123] fix: broken padding inside artist modals --- src/app/Components/ArtworkFilter/ArtworkFilterNavigator.tsx | 2 +- src/app/Scenes/SavedSearchAlert/CreateSavedSearchAlert.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app/Components/ArtworkFilter/ArtworkFilterNavigator.tsx b/src/app/Components/ArtworkFilter/ArtworkFilterNavigator.tsx index 4fb8c84c4f6..5540dc798f9 100644 --- a/src/app/Components/ArtworkFilter/ArtworkFilterNavigator.tsx +++ b/src/app/Components/ArtworkFilter/ArtworkFilterNavigator.tsx @@ -39,7 +39,7 @@ import { OwnerEntityTypes, PageNames } from "app/utils/track/schema" import { useLocalizedUnit } from "app/utils/useLocalizedUnit" import { useEffect, useState } from "react" import { Keyboard, Modal, Platform, ViewProps } from "react-native" -import { SafeAreaView, useSafeAreaInsets } from "react-native-safe-area-context" +import { useSafeAreaInsets } from "react-native-safe-area-context" import { useTracking } from "react-tracking" import { FilterModalMode as ArtworkFilterMode, diff --git a/src/app/Scenes/SavedSearchAlert/CreateSavedSearchAlert.tsx b/src/app/Scenes/SavedSearchAlert/CreateSavedSearchAlert.tsx index 9e1576070eb..cfd33f2b473 100644 --- a/src/app/Scenes/SavedSearchAlert/CreateSavedSearchAlert.tsx +++ b/src/app/Scenes/SavedSearchAlert/CreateSavedSearchAlert.tsx @@ -13,7 +13,7 @@ import { ConfirmationScreen } from "app/Scenes/SavedSearchAlert/screens/Confirma import { SavedSearchFilterScreen } from "app/Scenes/SavedSearchAlert/screens/SavedSearchFilterScreen" import { useLocalizedUnit } from "app/utils/useLocalizedUnit" import { KeyboardAvoidingView, Modal, Platform } from "react-native" -import { SafeAreaView, useSafeAreaInsets } from "react-native-safe-area-context" +import { useSafeAreaInsets } from "react-native-safe-area-context" import { CreateSavedSearchAlertNavigationStack, CreateSavedSearchAlertProps, From 408565aaaa2ae329d4eafbb0bb9acad493a2cabe Mon Sep 17 00:00:00 2001 From: Mounir Dhahri Date: Mon, 15 Dec 2025 16:12:57 +0100 Subject: [PATCH 059/123] fix: broken padding inside create alert modal --- src/app/Scenes/SavedSearchAlert/CreateSavedSearchAlert.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/Scenes/SavedSearchAlert/CreateSavedSearchAlert.tsx b/src/app/Scenes/SavedSearchAlert/CreateSavedSearchAlert.tsx index cfd33f2b473..e9fece1f213 100644 --- a/src/app/Scenes/SavedSearchAlert/CreateSavedSearchAlert.tsx +++ b/src/app/Scenes/SavedSearchAlert/CreateSavedSearchAlert.tsx @@ -57,7 +57,7 @@ export const CreateSavedSearchAlert: React.FC = (pr style={{ flex: 1, backgroundColor: color("background"), - paddingTop: Platform.OS === "ios" ? topInset : 0, + paddingTop: topInset, }} > Date: Mon, 15 Dec 2025 16:13:42 +0100 Subject: [PATCH 060/123] fix: berghain mode create alert button --- .../SavedSearchAlert/Components/Form.tsx | 76 +++++++++---------- 1 file changed, 37 insertions(+), 39 deletions(-) diff --git a/src/app/Scenes/SavedSearchAlert/Components/Form.tsx b/src/app/Scenes/SavedSearchAlert/Components/Form.tsx index 6d3ac57f0d4..49769cab97e 100644 --- a/src/app/Scenes/SavedSearchAlert/Components/Form.tsx +++ b/src/app/Scenes/SavedSearchAlert/Components/Form.tsx @@ -18,9 +18,9 @@ import { SavedSearchAlertFormValues, SavedSearchPill, } from "app/Scenes/SavedSearchAlert/SavedSearchAlertModel" +// eslint-disable-next-line no-restricted-imports import { navigate } from "app/system/navigation/navigate" import { useFormikContext } from "formik" -import { MotiView } from "moti" import { Platform, ScrollView, StyleProp, ViewStyle } from "react-native" import { useTracking } from "react-tracking" import { SavedSearchAlertSwitch } from "./SavedSearchAlertSwitch" @@ -206,47 +206,45 @@ export const Form: React.FC = ({ - - + + {isEditMode ? "Save Alert" : "Create Alert"} + - {!!isEditMode && ( - <> - - - - )} + {!!isEditMode && ( + <> + + + + )} - {!isEditMode && ( - - Access all your alerts in your profile. - - )} - - + {!isEditMode && ( + + Access all your alerts in your profile. + + )} + ) } From 346688abee6db395d1b6ee5169e6249e9ac2b20a Mon Sep 17 00:00:00 2001 From: Mounir Dhahri Date: Mon, 15 Dec 2025 16:53:32 +0100 Subject: [PATCH 061/123] fix: fair artworks grid paddings --- .../Scenes/Fair/FairAllFollowedArtists.tsx | 32 ++++++++----------- 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/src/app/Scenes/Fair/FairAllFollowedArtists.tsx b/src/app/Scenes/Fair/FairAllFollowedArtists.tsx index 53a485585b7..3a02fea8c30 100644 --- a/src/app/Scenes/Fair/FairAllFollowedArtists.tsx +++ b/src/app/Scenes/Fair/FairAllFollowedArtists.tsx @@ -46,24 +46,20 @@ export const FairAllFollowedArtists: React.FC = ({ return ( - - - - - - + + ) From a7b1f7d304b7f82c8eeb24d59df96ac6bc100c83 Mon Sep 17 00:00:00 2001 From: Mounir Dhahri Date: Tue, 16 Dec 2025 12:07:14 +0100 Subject: [PATCH 062/123] fix(PBRW-1413): infinite discovery onboarding issues (#13095) fix: infinite discovery broken padding on iOS --- .../Components/InfiniteDiscoveryOnboarding.tsx | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/app/Scenes/InfiniteDiscovery/Components/InfiniteDiscoveryOnboarding.tsx b/src/app/Scenes/InfiniteDiscovery/Components/InfiniteDiscoveryOnboarding.tsx index 37ca40b98c6..ce4369be572 100644 --- a/src/app/Scenes/InfiniteDiscovery/Components/InfiniteDiscoveryOnboarding.tsx +++ b/src/app/Scenes/InfiniteDiscovery/Components/InfiniteDiscoveryOnboarding.tsx @@ -7,7 +7,7 @@ import { MotiView } from "moti" import { useEffect, useRef, useState } from "react" import { LayoutAnimation, Modal, TouchableWithoutFeedback } from "react-native" import LinearGradient from "react-native-linear-gradient" -import { SafeAreaView } from "react-native-safe-area-context" +import { useSafeAreaInsets } from "react-native-safe-area-context" interface InfiniteDiscoveryOnboardingProps { artworks: InfiniteDiscoveryArtwork[] @@ -26,6 +26,7 @@ export const InfiniteDiscoveryOnboarding: React.FC(null) @@ -144,8 +145,11 @@ export const InfiniteDiscoveryOnboarding: React.FC - - + From d350ebea322035742e1a3f556f1f129142bd1cf6 Mon Sep 17 00:00:00 2001 From: Mounir Dhahri Date: Tue, 16 Dec 2025 12:15:02 +0100 Subject: [PATCH 063/123] fix: artwork grid issues (#13096) * fix: broken padding on heart icon * fix: partner cut title on android --- .../ArtworkGrids/ArtworkGridItem.tsx | 20 ++++++++++--------- .../MasonryInfiniteScrollArtworkGrid.tsx | 2 +- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/app/Components/ArtworkGrids/ArtworkGridItem.tsx b/src/app/Components/ArtworkGrids/ArtworkGridItem.tsx index 25f287fd4be..1082f4f7575 100644 --- a/src/app/Components/ArtworkGrids/ArtworkGridItem.tsx +++ b/src/app/Components/ArtworkGrids/ArtworkGridItem.tsx @@ -372,15 +372,17 @@ export const Artwork: React.FC = memo( )} {!hidePartner && !!artwork.partner?.name && ( - - {artwork.partner.name} - + + + {artwork.partner.name} + + )} {!!displayPriceOfferMessage && ( diff --git a/src/app/Components/ArtworkGrids/MasonryInfiniteScrollArtworkGrid.tsx b/src/app/Components/ArtworkGrids/MasonryInfiniteScrollArtworkGrid.tsx index 3a469fe130e..ee358b8b44f 100644 --- a/src/app/Components/ArtworkGrids/MasonryInfiniteScrollArtworkGrid.tsx +++ b/src/app/Components/ArtworkGrids/MasonryInfiniteScrollArtworkGrid.tsx @@ -104,7 +104,7 @@ export const MasonryInfiniteScrollArtworkGrid: React.FC Date: Tue, 16 Dec 2025 12:16:14 +0100 Subject: [PATCH 064/123] fix(PBRW-1411): create alert modal info button (#13094) fix: info button modal issues --- src/app/Components/Buttons/InfoButton.tsx | 24 ++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/src/app/Components/Buttons/InfoButton.tsx b/src/app/Components/Buttons/InfoButton.tsx index 0a53a42c187..5a128719267 100644 --- a/src/app/Components/Buttons/InfoButton.tsx +++ b/src/app/Components/Buttons/InfoButton.tsx @@ -13,6 +13,7 @@ import { AutoHeightBottomSheet } from "app/Components/BottomSheet/AutoHeightBott import { forwardRef, useImperativeHandle, useMemo, useState } from "react" import { Modal, Platform, ScrollView } from "react-native" import { SafeAreaView } from "react-native-safe-area-context" +import { FullWindowOverlay } from "react-native-screens" interface InfoButtonProps { isPresentedModally?: boolean @@ -107,11 +108,19 @@ export const AutoHeightInfoModal: React.FC<{ const { height: screenHeight, safeAreaInsets } = useScreenDimensions() const containerComponent = useMemo(() => { - return ({ children }: { children?: React.ReactNode }) => ( - - {children} - - ) + if (Platform.OS === "ios") { + return ({ children }: { children?: React.ReactNode }) => ( + {children} + ) + } + + if (Platform.OS === "android" && isPresentedModally) { + return ({ children }: { children?: React.ReactNode }) => ( + + {children} + + ) + } return undefined }, [visible, isPresentedModally]) @@ -134,10 +143,7 @@ export const AutoHeightInfoModal: React.FC<{ : undefined } > - + {modalTitle ?? title} From 6827833eb6520762d156a2480d7fc3a2a36fca76 Mon Sep 17 00:00:00 2001 From: Brian Beckerle <49686530+brainbicycle@users.noreply.github.com> Date: Tue, 16 Dec 2025 06:21:45 -0500 Subject: [PATCH 065/123] fix: webview bugs on new arch (#13097) pass double to workaround decelerationRate prop issue --- HACKS.md | 11 +++++++++++ src/app/Components/ArtsyWebView.tsx | 3 ++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/HACKS.md b/HACKS.md index e6095364863..dada013673e 100644 --- a/HACKS.md +++ b/HACKS.md @@ -295,3 +295,14 @@ This feature flag was added to fix performance issues with scrolling. See https: #### When can we remove this: When reanimated adopts this by default. + +## react-native-webview passing constant for decelerationRate prop + +#### Explanation/Context: + +This is a bug on the new architecture on Android with this prop and react-native-webview. + +#### When can we remove this: + +When this is merged and we update react-native-webview to a version that contains it: +https://github.com/react-native-webview/react-native-webview/pull/3885 diff --git a/src/app/Components/ArtsyWebView.tsx b/src/app/Components/ArtsyWebView.tsx index 733f7526802..75b90a499b2 100644 --- a/src/app/Components/ArtsyWebView.tsx +++ b/src/app/Components/ArtsyWebView.tsx @@ -294,7 +294,8 @@ export const ArtsyWebView = forwardRef< // sharedCookiesEnabled is required on iOS for the user to be implicitly logged into force/prediction // on android it works without it sharedCookiesEnabled - decelerationRate="normal" + // See HACKS.md for more details + decelerationRate={Platform.OS === "android" ? 0.985 : "normal"} source={{ uri, headers: { From 19feaa28ca2a8f12f86decc242dbbc320c85c2df Mon Sep 17 00:00:00 2001 From: Mounir Dhahri Date: Tue, 16 Dec 2025 14:31:09 +0100 Subject: [PATCH 066/123] fix: broken generic grid padding (#13102) * fix: broken padding inside create alert modal * fix: berghain mode create alert button * fix: fair artworks grid paddings * fix: generic grid broken paddings * fix: broken test * fix: broken test * chore: address review comment --- .../ArtworkGrids/ArtworkGridItem.tsx | 1 - .../Components/ArtworkGrids/GenericGrid.tsx | 237 ++++-------------- .../MasonryInfiniteScrollArtworkGrid.tsx | 89 ++++--- .../__tests__/GenericGrid.tests.tsx | 104 ++++---- .../Components/WorksForYou/Notification.tsx | 31 +-- .../__tests__/Notification.tests.tsx | 64 +++-- .../ArtQuizExploreArtworks.tsx | 14 +- .../ArtQuizLikedArtworks.tsx | 5 - .../BrowseSimilarWorksContent.tsx | 7 +- .../Components/OtherWorks/OtherWorks.tsx | 18 +- .../Scenes/Fair/FairAllFollowedArtists.tsx | 32 +-- src/app/Scenes/Feature/Feature.tsx | 4 +- .../SavedSearchAlert/AlertArtworksGrid.tsx | 11 +- .../screens/ConfirmationScreen.tsx | 21 +- 14 files changed, 263 insertions(+), 375 deletions(-) diff --git a/src/app/Components/ArtworkGrids/ArtworkGridItem.tsx b/src/app/Components/ArtworkGrids/ArtworkGridItem.tsx index 1082f4f7575..67c28c0eba9 100644 --- a/src/app/Components/ArtworkGrids/ArtworkGridItem.tsx +++ b/src/app/Components/ArtworkGrids/ArtworkGridItem.tsx @@ -76,7 +76,6 @@ export interface ArtworkProps extends ArtworkActionTrackingProps { showLotLabel?: boolean titleTextStyle?: TextProps trackTap?: (artworkSlug: string, index?: number) => void - trackingFlow?: string /** allows for artwork to be added to recent searches */ updateRecentSearchesOnTap?: boolean hideCreateAlertOnArtworkPreview?: boolean diff --git a/src/app/Components/ArtworkGrids/GenericGrid.tsx b/src/app/Components/ArtworkGrids/GenericGrid.tsx index ce9a4ed8d6d..34b005563ba 100644 --- a/src/app/Components/ArtworkGrids/GenericGrid.tsx +++ b/src/app/Components/ArtworkGrids/GenericGrid.tsx @@ -1,203 +1,65 @@ import { ContextModule } from "@artsy/cohesion" import { Flex, TextProps, useScreenDimensions } from "@artsy/palette-mobile" -import { GenericGrid_artworks$data } from "__generated__/GenericGrid_artworks.graphql" +import { GenericGrid_artworks$key } from "__generated__/GenericGrid_artworks.graphql" +import { MasonryInfiniteScrollArtworkGrid } from "app/Components/ArtworkGrids/MasonryInfiniteScrollArtworkGrid" import Spinner from "app/Components/Spinner" import { Stack } from "app/Components/Stack" import { AnalyticsContextProvider } from "app/system/analytics/AnalyticsContext" +import { MasonryArtworkItem } from "app/utils/masonryHelpers" import { RandomNumberGenerator } from "app/utils/placeholders" import { times } from "lodash" import React from "react" -import { LayoutChangeEvent, StyleSheet, View, ViewStyle } from "react-native" +import { StyleSheet, View, ViewStyle } from "react-native" import { isTablet } from "react-native-device-info" -import { createFragmentContainer, graphql } from "react-relay" -import Artwork, { ArtworkGridItemPlaceholder, ArtworkProps } from "./ArtworkGridItem" +import { graphql, useFragment } from "react-relay" +import { ArtworkGridItemPlaceholder, ArtworkProps } from "./ArtworkGridItem" interface Props { artistNamesTextStyle?: TextProps - saleInfoTextStyle?: TextProps - artworks: GenericGrid_artworks$data - sectionMargin?: number + artworks: GenericGrid_artworks$key + contextModule?: ContextModule hidePartner?: boolean - itemMargin?: number isLoading?: boolean - trackingFlow?: string - contextModule?: ContextModule + itemMargin?: number + onPress?: (artworkID: string) => void + saleInfoTextStyle?: TextProps trackTap?: (artworkSlug: string, itemIndex?: number) => void - // Give explicit width to avoid resizing after mount - width?: number -} - -interface State { - sectionDimension: number - sectionCount: number } type PropsForArtwork = Omit -type GenericArtworkType = GenericGrid_artworks$data extends ReadonlyArray - ? GenericArtwork - : never - -export class GenericArtworksGrid extends React.Component { - state = this.props.width - ? this.layoutState(this.props.width) - : { - sectionDimension: 0, - sectionCount: 0, - } +export const GenericGrid: React.FC = ({ + artworks: artworksProp, + contextScreenOwnerId, + contextScreenOwnerSlug, + contextScreenOwnerType, + hidePartner = false, + isLoading, + onPress, + trackTap, +}) => { + const artworks = useFragment(genericGridFragment, artworksProp) - width = 0 - - layoutState(width: number): State { - const sectionCount = isTablet() ? 3 : 2 - const sectionMargin = this.props.sectionMargin ?? 20 - const sectionMargins = sectionMargin * (sectionCount - 1) - const artworkPadding = 20 - const sectionDimension = (width - sectionMargins - artworkPadding) / sectionCount - - return { - sectionCount, - sectionDimension, - } - } - - onLayout = (event: LayoutChangeEvent) => { - if (this.props.width) { - // noop because we were given an explicit width - return - } - const layout = event.nativeEvent.layout - if (layout.width !== this.width) { - // this means we've rotated or are on our initial load - this.width = layout.width - - this.setState(this.layoutState(layout.width)) - } - } - - shouldComponentUpdate(nextProps: Props, nextState: State) { - // if there's a change in columns, we'll need to re-render - if ( - this.props.artworks === nextProps.artworks && - this.state.sectionCount === nextState.sectionCount && - this.props.isLoading === nextProps.isLoading - ) { - return false - } - return true - } - - sectionedArtworks() { - const sectionedArtworks: GenericArtworkType[][] = [] - const sectionRatioSums: number[] = [] - for (let i = 0; i < this.state.sectionCount; i++) { - sectionedArtworks.push([]) - sectionRatioSums.push(0) - } - - this.props.artworks.forEach((artwork) => { - if (artwork.image) { - let lowestRatioSum = Number.MAX_VALUE - let sectionIndex: number | null = null - - for (let j = 0; j < sectionRatioSums.length; j++) { - const ratioSum = sectionRatioSums[j] - if (ratioSum < lowestRatioSum) { - sectionIndex = j - lowestRatioSum = ratioSum - } - } - - if (sectionIndex != null) { - const section = sectionedArtworks[sectionIndex] - section.push(artwork) - - // total section aspect ratio - const aspectRatio = artwork.image.aspectRatio || 1 - sectionRatioSums[sectionIndex] += 1 / aspectRatio - } - } - }) - - return sectionedArtworks - } - - renderSections() { - const itemMargin = this.props.itemMargin ?? 20 - const spacerStyle = { - height: itemMargin, - } - const sectionedArtworks = this.sectionedArtworks() - const sections = [] - const { contextModule, trackingFlow, trackTap } = this.props - - for (let column = 0; column < this.state.sectionCount; column++) { - const artworkComponents = [] - const artworks = sectionedArtworks[column] - for (let row = 0; row < artworks.length; row++) { - const artwork = artworks[row] - const itemIndex = row * this.state.sectionCount + column - - const aspectRatio = artwork.image?.aspectRatio ?? 1 - const imgWidth = this.state.sectionDimension - const imgHeight = imgWidth / aspectRatio - - artworkComponents.push( - + + + - ) - if (row < artworks.length - 1) { - artworkComponents.push( - - ) - } - } - - const sectionMargin = this.props.sectionMargin ?? 20 - const sectionSpecificStyle = { - width: this.state.sectionDimension, - marginRight: column === this.state.sectionCount - 1 ? 0 : sectionMargin, - } - sections.push( - - {artworkComponents} - ) - } - return sections - } - - render() { - const artworks = this.state.sectionDimension ? this.renderSections() : null - - return ( - - - - {artworks} - - {this.props.isLoading ? : null} - - - ) - } + {isLoading ? : null} + + + ) } interface Styles { @@ -218,18 +80,17 @@ const styles = StyleSheet.create({ }, }) -const GenericGrid = createFragmentContainer(GenericArtworksGrid, { - artworks: graphql` - fragment GenericGrid_artworks on Artwork @relay(plural: true) { - id - slug - image(includeAll: false) { - aspectRatio - } - ...ArtworkGridItem_artwork +const genericGridFragment = graphql` + fragment GenericGrid_artworks on Artwork @relay(plural: true) { + id + slug + image(includeAll: false) { + aspectRatio + blurhash } - `, -}) + ...ArtworkGridItem_artwork @arguments(includeAllImages: false) + } +` export default GenericGrid diff --git a/src/app/Components/ArtworkGrids/MasonryInfiniteScrollArtworkGrid.tsx b/src/app/Components/ArtworkGrids/MasonryInfiniteScrollArtworkGrid.tsx index ee358b8b44f..ad883144f7e 100644 --- a/src/app/Components/ArtworkGrids/MasonryInfiniteScrollArtworkGrid.tsx +++ b/src/app/Components/ArtworkGrids/MasonryInfiniteScrollArtworkGrid.tsx @@ -1,5 +1,5 @@ import { ContextModule, ScreenOwnerType } from "@artsy/cohesion" -import { useSpace } from "@artsy/palette-mobile" +import { TextProps, useSpace } from "@artsy/palette-mobile" import { FlashList, FlashListProps, ListRenderItem } from "@shopify/flash-list" import { PriceOfferMessage } from "app/Components/ArtworkGrids/ArtworkGridItem" import { MasonryArtworkGridItem } from "app/Components/ArtworkGrids/MasonryArtworkGridItem" @@ -17,6 +17,7 @@ type MasonryFlashListOmittedProps = Omit, "re interface MasonryInfiniteScrollArtworkGridProps extends MasonryFlashListOmittedProps { animated?: boolean + artistNamesTextStyle?: TextProps artworks: MasonryArtworkItem[] contextModule?: ContextModule contextScreen?: ScreenOwnerType @@ -30,15 +31,18 @@ interface MasonryInfiniteScrollArtworkGridProps extends MasonryFlashListOmittedP hideCreateAlertOnArtworkPreview?: boolean hideCuratorsPick?: boolean hideIncreasedInterest?: boolean - hideViewFollowsLink?: boolean + hidePartner?: boolean hideSaleInfo?: boolean hideSaveIcon?: boolean + hideViewFollowsLink?: boolean isLoading?: boolean loadMore?: (pageSize: number) => void onPress?: (artworkID: string) => void pageSize?: number partnerOffer?: PartnerOffer | null priceOfferMessage?: PriceOfferMessage + saleInfoTextStyle?: TextProps + trackTap?: (artworkSlug: string, itemIndex?: number) => void } /** @@ -50,6 +54,7 @@ interface MasonryInfiniteScrollArtworkGridProps extends MasonryFlashListOmittedP export const MasonryInfiniteScrollArtworkGrid: React.FC = ({ animated = false, + artistNamesTextStyle, artworks, contextModule, contextScreen, @@ -62,19 +67,23 @@ export const MasonryInfiniteScrollArtworkGrid: React.FC { @@ -92,15 +101,7 @@ export const MasonryInfiniteScrollArtworkGrid: React.FC { return ( ) }, [ + artistNamesTextStyle, + artworks.length, contextModule, - contextScreenOwnerType, contextScreen, contextScreenOwnerId, contextScreenOwnerSlug, - rest.numColumns, - space, - artworks.length, - partnerOffer, - priceOfferMessage, - onPress, - hideSaleInfo, - hideSaveIcon, + contextScreenOwnerType, disableArtworksListPrompt, disableProgressiveOnboarding, - hideIncreasedInterest, - hideCuratorsPick, hideCreateAlertOnArtworkPreview, + hideCuratorsPick, + hideIncreasedInterest, + hidePartner, + hideSaleInfo, + hideSaveIcon, + onPress, + partnerOffer, + priceOfferMessage, + rest.numColumns, + saleInfoTextStyle, + space, + trackTap, ] ) @@ -155,11 +172,19 @@ export const MasonryInfiniteScrollArtworkGrid: React.FC, "numColumns" | "data" | "renderItem"> - }, [shouldDisplayHeader, ListHeaderComponent, ListEmptyComponent, refreshControl, rest.onScroll]) + }, [ + shouldDisplayHeader, + ListHeaderComponent, + ListEmptyComponent, + refreshControl, + scrollEnabled, + rest.onScroll, + ]) if (artworks.length === 0) { return ( diff --git a/src/app/Components/ArtworkGrids/__tests__/GenericGrid.tests.tsx b/src/app/Components/ArtworkGrids/__tests__/GenericGrid.tests.tsx index 42db5cbc6fb..ae3714492d8 100644 --- a/src/app/Components/ArtworkGrids/__tests__/GenericGrid.tests.tsx +++ b/src/app/Components/ArtworkGrids/__tests__/GenericGrid.tests.tsx @@ -1,51 +1,67 @@ -import { renderWithHookWrappersTL } from "app/utils/tests/renderWithWrappers" -import "react-native" +import { screen } from "@testing-library/react-native" +import { GenericGridTestsQuery } from "__generated__/GenericGridTestsQuery.graphql" +import { GenericGrid } from "app/Components/ArtworkGrids/GenericGrid" +import { extractNodes } from "app/utils/extractNodes" +import { setupTestWrapper } from "app/utils/tests/setupTestWrapper" +import { graphql } from "react-relay" -import RelayGenericArtworksGrid, { - GenericArtworksGrid, -} from "app/Components/ArtworkGrids/GenericGrid" - -it("renders without throwing an error", () => { - const artworks = [artwork(), artwork(), artwork()] - - renderWithHookWrappersTL() -}) - -it("handles showing an update when there are new artworks", () => { - const artworks = [artwork(), artwork()] as any - const newArtworks = [artwork(), artwork(), artwork()] as any +describe("GenericGrid", () => { + const { renderWithRelay } = setupTestWrapper({ + Component: ({ viewer, isLoading }) => { + const artworks = extractNodes(viewer?.artworksConnection) + return + }, + query: graphql` + query GenericGridTestsQuery @relay_test_operation { + viewer { + artworksConnection(first: 3) { + edges { + node { + ...GenericGrid_artworks + } + } + } + } + } + `, + }) - const grid = new GenericArtworksGrid({ artworks }) - const shouldUpdate = grid.shouldComponentUpdate({ artworks: newArtworks }, {} as any) + it("renders without throwing an error", () => { + renderWithRelay({ + Artwork: () => ({ + id: "artwork-long-title", + slug: "long-title", + title: "DO WOMEN STILL HAVE TO BE NAKED TO GET INTO THE MET. MUSEUM", + date: "2012", + image: { + aspectRatio: 2.18, + blurhash: "test-blurhash", + }, + }), + }) - expect(shouldUpdate).toBeTruthy() -}) + expect(screen.getByLabelText("Artworks Content View")).toBeOnTheScreen() + expect( + screen.getByTestId( + "artworkGridItem-DO WOMEN STILL HAVE TO BE NAKED TO GET INTO THE MET. MUSEUM" + ) + ).toBeOnTheScreen() + }) -it("handles showing an update when data loading was stopped", () => { - const artworks = [artwork(), artwork()] as any + it("renders spinner when loading", () => { + renderWithRelay( + { + Artwork: () => ({ + id: "artwork-1", + slug: "test-artwork", + image: { + aspectRatio: 1.5, + }, + }), + }, + { isLoading: true } + ) - const grid = new GenericArtworksGrid({ - artworks, - isLoading: true, + expect(screen.getByTestId("spinner")).toBeOnTheScreen() }) - const shouldUpdate = grid.shouldComponentUpdate({ artworks, isLoading: false }, {} as any) - - expect(shouldUpdate).toBeTruthy() }) - -const artwork = () => { - return { - id: "artwork-long-title", - gravityID: "long-title", - title: "DO WOMEN STILL HAVE TO BE NAKED TO GET INTO THE MET. MUSEUM", - date: "2012", - saleMessage: null, - isInAuction: false, - image: { - url: "artsy.net/image-url", - aspectRatio: 2.18, - }, - artistsNames: "Guerrilla Girls", - href: "/artwork/guerrilla-girls-do-women-still-have-to-be-naked-to-get-into-the-met-museum", - } -} diff --git a/src/app/Components/WorksForYou/Notification.tsx b/src/app/Components/WorksForYou/Notification.tsx index bcc24288875..71e8cd5a1ac 100644 --- a/src/app/Components/WorksForYou/Notification.tsx +++ b/src/app/Components/WorksForYou/Notification.tsx @@ -1,18 +1,11 @@ -import { Text } from "@artsy/palette-mobile" +import { Flex, Text } from "@artsy/palette-mobile" import { Notification_notification$data } from "__generated__/Notification_notification.graphql" import GenericGrid from "app/Components/ArtworkGrids/GenericGrid" import { ThemeAwareClassTheme } from "app/Components/DarkModeClassTheme" import { navigate } from "app/system/navigation/navigate" import { extractNodes } from "app/utils/extractNodes" import React from "react" -import { - Image, - ImageStyle, - StyleSheet, - TouchableWithoutFeedback, - View, - ViewStyle, -} from "react-native" +import { Image, StyleSheet, TouchableWithoutFeedback, View } from "react-native" import { createFragmentContainer, graphql } from "react-relay" interface Props { @@ -65,9 +58,9 @@ export class Notification extends React.Component { - - - + + + )} @@ -75,15 +68,7 @@ export class Notification extends React.Component { } } -interface Styles { - container: ViewStyle - header: ViewStyle - artistAvatar: ImageStyle - metadataContainer: ViewStyle - gridContainer: ViewStyle -} - -const styles = StyleSheet.create({ +const styles = StyleSheet.create({ container: { marginTop: 20, marginHorizontal: HORIZONTAL_PADDING, @@ -102,10 +87,6 @@ const styles = StyleSheet.create({ alignSelf: "center", flex: 1, }, - gridContainer: { - marginTop: 20, - marginBottom: 20, - }, }) export default createFragmentContainer(Notification, { diff --git a/src/app/Components/WorksForYou/__tests__/Notification.tests.tsx b/src/app/Components/WorksForYou/__tests__/Notification.tests.tsx index bc04b4cd971..d5341872b63 100644 --- a/src/app/Components/WorksForYou/__tests__/Notification.tests.tsx +++ b/src/app/Components/WorksForYou/__tests__/Notification.tests.tsx @@ -1,30 +1,50 @@ -import { renderWithLayout } from "app/utils/tests/renderWithLayout" +import { screen } from "@testing-library/react-native" +import { NotificationTestsQuery } from "__generated__/NotificationTestsQuery.graphql" +import NotificationFragmentContainer from "app/Components/WorksForYou/Notification" +import { setupTestWrapper } from "app/utils/tests/setupTestWrapper" import "react-native" -import { Notification } from "app/Components/WorksForYou/Notification" +import { graphql } from "relay-runtime" -it("renders without throwing an error for unread notification", () => { - const props = notification() - renderWithLayout(, { width: 768 }) -}) +describe("Notification", () => { + const { renderWithRelay } = setupTestWrapper({ + Component: (props) => ( + + ), + query: graphql` + query NotificationTestsQuery @relay_test_operation { + followedArtistsArtworksGroup: node(id: "test-id") { + ... on FollowedArtistsArtworksGroup { + ...Notification_notification + } + } + } + `, + }) + it.only("renders notification properly", () => { + renderWithRelay({ + FollowedArtistsArtworksGroup: () => notification(), + }) -it("renders without throwing an error for read notification", () => { - const props = notification() - props.status = "READ" - renderWithLayout(, { width: 768 }) -}) + expect(screen.getByText("Jean-Michel Basquiat")).toBeTruthy() + }) -it("renders without throwing an error if no avatar image exists", () => { - const props = notification() - const convertedProps = { - ...props, - image: { - resized: { - url: null, + it.only("renders without throwing an error if no avatar image exists", () => { + const props = notification() + const convertedProps = { + ...props, + image: { + resized: { + url: null, + }, }, - }, - } - renderWithLayout(, { - width: 300, + } + + renderWithRelay({ + FollowedArtistsArtworksGroup: () => convertedProps, + }) }) }) diff --git a/src/app/Scenes/ArtQuiz/ArtQuizResults/ArtQuizResultsTabs/ArtQuizExploreArtworks.tsx b/src/app/Scenes/ArtQuiz/ArtQuizResults/ArtQuizResultsTabs/ArtQuizExploreArtworks.tsx index 6ae51845a1f..46ead282769 100644 --- a/src/app/Scenes/ArtQuiz/ArtQuizResults/ArtQuizResultsTabs/ArtQuizExploreArtworks.tsx +++ b/src/app/Scenes/ArtQuiz/ArtQuizResults/ArtQuizResultsTabs/ArtQuizExploreArtworks.tsx @@ -1,4 +1,4 @@ -import { Tabs, Text, useScreenDimensions, useSpace } from "@artsy/palette-mobile" +import { Flex, Tabs, Text, useSpace } from "@artsy/palette-mobile" import { ArtQuizExploreArtworksFragment_artwork$key } from "__generated__/ArtQuizExploreArtworksFragment_artwork.graphql" import { ArtQuizResultsTabs_me$data } from "__generated__/ArtQuizResultsTabs_me.graphql" import GenericGrid from "app/Components/ArtworkGrids/GenericGrid" @@ -17,28 +17,26 @@ export const ArtQuizExploreArtworks = ({ recommendedArtworks ) - const dimensions = useScreenDimensions() - return ( {artworks.length ? ( ) : ( - - We don't have any recommendations for you at this time. - + + + We don't have any recommendations for you at this time. + + )} ) diff --git a/src/app/Scenes/ArtQuiz/ArtQuizResults/ArtQuizResultsTabs/ArtQuizLikedArtworks.tsx b/src/app/Scenes/ArtQuiz/ArtQuizResults/ArtQuizResultsTabs/ArtQuizLikedArtworks.tsx index c272ba32764..02aa190df4c 100644 --- a/src/app/Scenes/ArtQuiz/ArtQuizResults/ArtQuizResultsTabs/ArtQuizLikedArtworks.tsx +++ b/src/app/Scenes/ArtQuiz/ArtQuizResults/ArtQuizResultsTabs/ArtQuizLikedArtworks.tsx @@ -2,8 +2,6 @@ import { Tabs, useSpace } from "@artsy/palette-mobile" import { ArtQuizLikedArtworks_artworks$key } from "__generated__/ArtQuizLikedArtworks_artworks.graphql" import { ArtQuizResultsTabs_me$data } from "__generated__/ArtQuizResultsTabs_me.graphql" import GenericGrid from "app/Components/ArtworkGrids/GenericGrid" - -import { useScreenDimensions } from "app/utils/hooks" import { graphql, useFragment } from "react-relay" export const ArtQuizLikedArtworks = ({ @@ -17,19 +15,16 @@ export const ArtQuizLikedArtworks = ({ ) const space = useSpace() - const dimensions = useScreenDimensions() return ( { const SimilarArtworksContainer: React.FC<{ attributes: SearchCriteriaAttributes }> = withSuspense({ Component: ({ attributes }) => { - const screen = useScreenDimensions() - const { space } = useTheme() - const data = useLazyLoadQuery(similarArtworksQuery, { first: NUMBER_OF_ARTWORKS_TO_SHOW, input: { @@ -114,7 +111,9 @@ const SimilarArtworksContainer: React.FC<{ attributes: SearchCriteriaAttributes return ( <> - + + + diff --git a/src/app/Scenes/Artwork/Components/OtherWorks/OtherWorks.tsx b/src/app/Scenes/Artwork/Components/OtherWorks/OtherWorks.tsx index 0f9f02cc966..33503d559e0 100644 --- a/src/app/Scenes/Artwork/Components/OtherWorks/OtherWorks.tsx +++ b/src/app/Scenes/Artwork/Components/OtherWorks/OtherWorks.tsx @@ -1,11 +1,9 @@ import { ContextModule } from "@artsy/cohesion" -import { Spacer, Box, Text, useSpace, Separator, Join } from "@artsy/palette-mobile" +import { Box, Flex, Join, Separator, Spacer, Text } from "@artsy/palette-mobile" import { Artwork_artworkBelowTheFold$data } from "__generated__/Artwork_artworkBelowTheFold.graphql" import { OtherWorks_artwork$data } from "__generated__/OtherWorks_artwork.graphql" import GenericGrid from "app/Components/ArtworkGrids/GenericGrid" import { extractNodes } from "app/utils/extractNodes" -import { useScreenDimensions } from "app/utils/hooks" -import { Schema } from "app/utils/track" import { filter } from "lodash" import React from "react" import { createFragmentContainer, graphql } from "react-relay" @@ -26,8 +24,6 @@ export const populatedGrids = (grids?: ReadonlyArray | } const OtherWorks: React.FC<{ artwork: OtherWorks_artwork$data }> = ({ artwork }) => { - const { width } = useScreenDimensions() - const space = useSpace() const grids = artwork.contextGrids const gridsToShow = populatedGrids(grids) as ReadonlyArray @@ -49,12 +45,12 @@ const OtherWorks: React.FC<{ artwork: OtherWorks_artwork$data }> = ({ artwork }) {grid.title} - + + + = ({ return ( - - + + + + + + ) diff --git a/src/app/Scenes/Feature/Feature.tsx b/src/app/Scenes/Feature/Feature.tsx index 008a05a41a6..fdacfdd3cae 100644 --- a/src/app/Scenes/Feature/Feature.tsx +++ b/src/app/Scenes/Feature/Feature.tsx @@ -175,8 +175,8 @@ const FeatureApp: React.FC = ({ feature }) => { allSections.push({ key: "artworks:" + set.id, content: ( - - + + ), }) diff --git a/src/app/Scenes/SavedSearchAlert/AlertArtworksGrid.tsx b/src/app/Scenes/SavedSearchAlert/AlertArtworksGrid.tsx index 52f54c5653a..498b6a5a6fa 100644 --- a/src/app/Scenes/SavedSearchAlert/AlertArtworksGrid.tsx +++ b/src/app/Scenes/SavedSearchAlert/AlertArtworksGrid.tsx @@ -27,9 +27,6 @@ interface AlertArtworksGridProps { const NUMBER_OF_ARTWORKS_TO_SHOW = 10 export const AlertArtworksGrid: FC = ({ alertId, fetchKey }) => { - const screenDimensions = useScreenDimensions() - const { space } = useTheme() - const data = useLazyLoadQuery( alertArtworksGridQuery, { @@ -76,11 +73,9 @@ export const AlertArtworksGrid: FC = ({ alertId, fetchKe {numWorks} currently on Artsy match your criteria. See our top picks for you: - + + + )} {artworksCount === 0 && ( diff --git a/src/app/Scenes/SavedSearchAlert/screens/ConfirmationScreen.tsx b/src/app/Scenes/SavedSearchAlert/screens/ConfirmationScreen.tsx index 6905ec55cf0..8b6342a471f 100644 --- a/src/app/Scenes/SavedSearchAlert/screens/ConfirmationScreen.tsx +++ b/src/app/Scenes/SavedSearchAlert/screens/ConfirmationScreen.tsx @@ -170,8 +170,6 @@ interface MatchingArtworksProps { } const MatchingArtworks: React.FC = ({ artworksConnection, closeModal }) => { - const screen = useScreenDimensions() - const { space } = useTheme() const { trackEvent } = useTracking() const route = useRoute>() const artworks = extractNodes(artworksConnection) @@ -218,15 +216,16 @@ const MatchingArtworks: React.FC = ({ artworksConnection, - { - closeModal?.() - trackEvent(tracks.tappedArtworkGroup(slug, artwork?.collectorSignals)) - }} - /> + + { + closeModal?.() + trackEvent(tracks.tappedArtworkGroup(slug, artwork?.collectorSignals)) + }} + /> + From c8ae3cec877e1db09392a40ed1a2f8abe203c9a5 Mon Sep 17 00:00:00 2001 From: Mounir Dhahri Date: Tue, 16 Dec 2025 14:43:59 +0100 Subject: [PATCH 067/123] chore: bump palette-mobile again --- package.json | 2 +- yarn.lock | 14 ++++++++++---- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 6501904a86f..c3c6fe1599d 100644 --- a/package.json +++ b/package.json @@ -109,7 +109,7 @@ "dependencies": { "@artsy/cohesion": "4.336.0", "@artsy/icons": "3.63.0", - "@artsy/palette-mobile": "22.2.0--canary.425.5130.0", + "@artsy/palette-mobile": "22.2.0--canary.425.5134.0", "@artsy/to-title-case": "1.2.0", "@braze/react-native-sdk": "16.1.0", "@d11/react-native-fast-image": "8.12.0", diff --git a/yarn.lock b/yarn.lock index d0fccb31dfd..98ff9c8f9c5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -72,9 +72,9 @@ __metadata: languageName: node linkType: hard -"@artsy/palette-mobile@npm:22.2.0--canary.425.5130.0": - version: 22.2.0--canary.425.5130.0 - resolution: "@artsy/palette-mobile@npm:22.2.0--canary.425.5130.0" +"@artsy/palette-mobile@npm:22.2.0--canary.425.5134.0": + version: 22.2.0--canary.425.5134.0 + resolution: "@artsy/palette-mobile@npm:22.2.0--canary.425.5134.0" dependencies: "@artsy/icons": "npm:^3.49.0" "@artsy/palette-tokens": "npm:7.0.0" @@ -101,7 +101,7 @@ __metadata: react-native-reanimated: "*" react-native-svg: "*" styled-components: ">= 5" - checksum: 10c0/f6823d1bd50f9d32b2af0c39ef2bd6bcd97af3a3ab99bb69f65f8f286d018c3b1981f2282682d491d8242c6f8ce1f77cfdd09b4cd04a635304e995a3f89ffd57 + checksum: 10c0/8faf76baf78931a6e249ed63f3f2431fc1cb01e99c886ed075910eb0f0f1f73428b35dec8dcd02ca8225363d9c30f9114bc05dbd58f4afb8530f4204e843816e languageName: node linkType: hard @@ -13163,9 +13163,15 @@ __metadata: version: 0.0.0-use.local resolution: "eigen@workspace:." dependencies: +<<<<<<< HEAD "@artsy/cohesion": "npm:4.336.0" "@artsy/icons": "npm:3.63.0" "@artsy/palette-mobile": "npm:22.2.0--canary.425.5130.0" +======= + "@artsy/cohesion": "npm:4.335.0" + "@artsy/icons": "npm:3.62.0" + "@artsy/palette-mobile": "npm:22.2.0--canary.425.5134.0" +>>>>>>> b944009a52 (chore: bump palette-mobile again) "@artsy/to-title-case": "npm:1.2.0" "@artsy/update-repo": "npm:0.7.0" "@babel/core": "npm:7.25.2" From 5c44d54ddb64c09dae628598a0ade1f1f127cbca Mon Sep 17 00:00:00 2001 From: Mounir Dhahri Date: Tue, 16 Dec 2025 14:48:29 +0100 Subject: [PATCH 068/123] chore: do not delete global android caches --- scripts/utils/cleaninstall.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/utils/cleaninstall.sh b/scripts/utils/cleaninstall.sh index 0909f897e6b..782fd4739e7 100755 --- a/scripts/utils/cleaninstall.sh +++ b/scripts/utils/cleaninstall.sh @@ -9,8 +9,8 @@ echo "🧹 🧽 🧼 🧹" echo "Clearing android specific caches" -rm -rf ~/.gradle/caches -rm -rf ~/.gradle/daemon +# rm -rf ~/.gradle/caches +# rm -rf ~/.gradle/daemon rm -rf .gradle rm -rf build From 2c37816c3b6d3351c6637d4af74de08c17f558e5 Mon Sep 17 00:00:00 2001 From: Mounir Dhahri Date: Tue, 16 Dec 2025 15:03:16 +0100 Subject: [PATCH 069/123] chore: increase memory on android --- android/gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/android/gradle.properties b/android/gradle.properties index 2d71ca5ec72..8240262d0fb 100644 --- a/android/gradle.properties +++ b/android/gradle.properties @@ -10,7 +10,7 @@ # Specifies the JVM arguments used for the daemon process. # The setting is particularly useful for tweaking memory settings. # Default value: -Xmx512m -XX:MaxMetaspaceSize=256m -org.gradle.jvmargs=-Xmx3g -XX:MaxMetaspaceSize=1024m +org.gradle.jvmargs=-Xmx6g -XX:MaxMetaspaceSize=1024m # When configured, Gradle will run in incubating parallel mode. # This option should only be used with decoupled projects. More details, visit From bce3cdd788b443779351d8c3831a0a2c9083a617 Mon Sep 17 00:00:00 2001 From: Mounir Dhahri Date: Tue, 16 Dec 2025 15:25:57 +0100 Subject: [PATCH 070/123] chore: add mise install to install --- scripts/setup/install | 1 - 1 file changed, 1 deletion(-) diff --git a/scripts/setup/install b/scripts/setup/install index c311de0b940..5e6bf0c8119 100755 --- a/scripts/setup/install +++ b/scripts/setup/install @@ -1,7 +1,6 @@ #!/usr/bin/env bash set -euxo pipefail - bundle check || bundle install brew bundle yarn install From 39a6ad83467455ee60c85ad07cddeb55b1ab727c Mon Sep 17 00:00:00 2001 From: Mounir Dhahri Date: Tue, 16 Dec 2025 16:15:23 +0100 Subject: [PATCH 071/123] fix: duplicate key --- src/app/utils/renderMarkdown.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/utils/renderMarkdown.tsx b/src/app/utils/renderMarkdown.tsx index 7ddd26d0cb9..71f76f818ab 100644 --- a/src/app/utils/renderMarkdown.tsx +++ b/src/app/utils/renderMarkdown.tsx @@ -227,7 +227,7 @@ export function defaultRules({ ), }, hr: { - react: () => , + react: (_node, _output, state) => , }, ...ruleOverrides, }) From 4bad1e63b1e3b1659e528873269ba9d5271731aa Mon Sep 17 00:00:00 2001 From: Mounir Dhahri Date: Tue, 16 Dec 2025 18:00:53 +0100 Subject: [PATCH 072/123] fix: attempt to fix android build --- fastlane/Fastfile | 2 +- scripts/ci/build-for-tests-android | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/fastlane/Fastfile b/fastlane/Fastfile index 9f0b1cf2f8d..0e3e9a3d174 100644 --- a/fastlane/Fastfile +++ b/fastlane/Fastfile @@ -314,7 +314,7 @@ lane :ship_beta_android do |options| tag_and_push(tag: "android-#{vname}-#{vcode}") build_type = deployment_target == 'play_store' ? 'release' : 'beta' - sh("yarn react-native build-android --mode=#{build_type} --extra-params='--no-daemon --max-workers 2'") + sh("yarn react-native build-android --mode=#{build_type} --extra-params='--no-daemon") if (deployment_target == 'play_store') # important! this must match the release version specified diff --git a/scripts/ci/build-for-tests-android b/scripts/ci/build-for-tests-android index b774d1cc7bc..c42da1b2e95 100755 --- a/scripts/ci/build-for-tests-android +++ b/scripts/ci/build-for-tests-android @@ -14,7 +14,7 @@ CAPITALIZED_BUILD_TYPE="$(echo "$BUILD_TYPE" | awk '{print toupper(substr($0,1,1 pushd android echo "Running Gradle task: assemble${CAPITALIZED_BUILD_TYPE}" -./gradlew assemble${CAPITALIZED_BUILD_TYPE} +./gradlew assemble${CAPITALIZED_BUILD_TYPE} --no-daemon popd From d1084bcc02fb9d044c51f10382ae37c3ba1fc510 Mon Sep 17 00:00:00 2001 From: Mounir Dhahri Date: Wed, 17 Dec 2025 09:55:58 +0100 Subject: [PATCH 073/123] chore: bump android cache --- .circleci/config.yml | 4 ++-- fastlane/Fastfile | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index ffa2a17aad0..08775551f72 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -530,14 +530,14 @@ parameters: default: v30-app_build_ios-{{ checksum ".manifests/app_build" }} app_build_android_cache_key: type: string - default: v15-app_build_android-{{ checksum "../workspace/.manifests/app_build" }} + default: v16-app_build_android-{{ checksum "../workspace/.manifests/app_build" }} ios_native_code_cache_prefix: type: string # this one is not including the checksum due to path differences in the checksum default: v19-test-success android_native_cache_key: type: string - default: v18-test-success-{{ checksum "../workspace/.manifests/android_native" }} + default: v19-test-success-{{ checksum "../workspace/.manifests/android_native" }} workflows: nightly: diff --git a/fastlane/Fastfile b/fastlane/Fastfile index 0e3e9a3d174..4e9a0077d47 100644 --- a/fastlane/Fastfile +++ b/fastlane/Fastfile @@ -314,7 +314,7 @@ lane :ship_beta_android do |options| tag_and_push(tag: "android-#{vname}-#{vcode}") build_type = deployment_target == 'play_store' ? 'release' : 'beta' - sh("yarn react-native build-android --mode=#{build_type} --extra-params='--no-daemon") + sh("yarn react-native build-android --mode=#{build_type} --extra-params='--no-daemon --max-workers 2'") if (deployment_target == 'play_store') # important! this must match the release version specified @@ -472,6 +472,7 @@ lane :get_next_android_build_version do end file_dir = "#{Dir.pwd}/next_version_code.txt" + puts "Writing next version code to: #{file_dir}" puts "Generated date-based version code: #{next_version_code}" File.write(file_dir, next_version_code) end From 7603ef4c9f73e28fe71cbd5c7ef9daff010255cf Mon Sep 17 00:00:00 2001 From: Sultan Date: Wed, 17 Dec 2025 10:40:00 +0100 Subject: [PATCH 074/123] run build with --info and store build log --- .circleci/config.yml | 3 +++ scripts/ci/build-for-tests-android | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 08775551f72..5f8a3c8e6f3 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -491,6 +491,9 @@ jobs: - store_artifacts: path: android/app/build/reports + - store_artifacts: + path: .gradle/daemon/ + - save_cache: key: << pipeline.parameters.android_native_cache_key >> paths: diff --git a/scripts/ci/build-for-tests-android b/scripts/ci/build-for-tests-android index c42da1b2e95..fd28671a301 100755 --- a/scripts/ci/build-for-tests-android +++ b/scripts/ci/build-for-tests-android @@ -14,7 +14,7 @@ CAPITALIZED_BUILD_TYPE="$(echo "$BUILD_TYPE" | awk '{print toupper(substr($0,1,1 pushd android echo "Running Gradle task: assemble${CAPITALIZED_BUILD_TYPE}" -./gradlew assemble${CAPITALIZED_BUILD_TYPE} --no-daemon +./gradlew assemble${CAPITALIZED_BUILD_TYPE} --no-daemon --info popd From c454cf0cb2a625c2fd1a6ebfe392a1242423f6cc Mon Sep 17 00:00:00 2001 From: Mounir Dhahri Date: Wed, 17 Dec 2025 15:02:31 +0100 Subject: [PATCH 075/123] fix: broken android build (#13106) * chore: attempt fixing android build * chore: bump cache for node * chore: try again * chore: increase workers * chore: use same build command as fastfile --- .circleci/config.yml | 2 +- android/gradle.properties | 2 +- scripts/ci/build-for-tests-android | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 5f8a3c8e6f3..914367ef845 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -521,7 +521,7 @@ parameters: # Update Manually these versions below in order to hard overwrite the caches node_modules_cache_key: type: string - default: v28-node_modules-{{ checksum ".manifests/node_modules" }} + default: v29-node_modules-{{ checksum ".manifests/node_modules" }} gems_cache_key: type: string default: v13-gems-{{ checksum "Gemfile.lock" }}-{{ arch }} diff --git a/android/gradle.properties b/android/gradle.properties index 8240262d0fb..2d71ca5ec72 100644 --- a/android/gradle.properties +++ b/android/gradle.properties @@ -10,7 +10,7 @@ # Specifies the JVM arguments used for the daemon process. # The setting is particularly useful for tweaking memory settings. # Default value: -Xmx512m -XX:MaxMetaspaceSize=256m -org.gradle.jvmargs=-Xmx6g -XX:MaxMetaspaceSize=1024m +org.gradle.jvmargs=-Xmx3g -XX:MaxMetaspaceSize=1024m # When configured, Gradle will run in incubating parallel mode. # This option should only be used with decoupled projects. More details, visit diff --git a/scripts/ci/build-for-tests-android b/scripts/ci/build-for-tests-android index fd28671a301..d9c7e23100b 100755 --- a/scripts/ci/build-for-tests-android +++ b/scripts/ci/build-for-tests-android @@ -3,10 +3,10 @@ set -exo pipefail BUILD_TYPE=${1:-release} # default to release if [ "$BUILD_TYPE" == "beta" ]; then - echo "Building Android App in Beta mode" + echo "Building Android App in Beta mode." MODE="beta" else - echo "Building Android App in Release mode" + echo "Building Android App in Release mode." MODE="release" fi CAPITALIZED_BUILD_TYPE="$(echo "$BUILD_TYPE" | awk '{print toupper(substr($0,1,1)) substr($0,2)}')" @@ -14,7 +14,7 @@ CAPITALIZED_BUILD_TYPE="$(echo "$BUILD_TYPE" | awk '{print toupper(substr($0,1,1 pushd android echo "Running Gradle task: assemble${CAPITALIZED_BUILD_TYPE}" -./gradlew assemble${CAPITALIZED_BUILD_TYPE} --no-daemon --info +./gradlew assemble${CAPITALIZED_BUILD_TYPE} --no-daemon --max-workers=2 popd From 99bdd95838144cfb8302c92fbfad2f21ab02f05d Mon Sep 17 00:00:00 2001 From: Brian Beckerle <49686530+brainbicycle@users.noreply.github.com> Date: Wed, 17 Dec 2025 13:10:55 -0500 Subject: [PATCH 076/123] fix: padding issues on new arch (#13105) * wrap switch in flex to fix flex behavior * fix padding issues in dark mode settings --- src/app/Components/SwitchMenu.tsx | 4 +++- src/app/Scenes/MyProfile/DarkModeSettings.tsx | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/app/Components/SwitchMenu.tsx b/src/app/Components/SwitchMenu.tsx index 4a3cb8f0ff9..0c2e8bf3cf4 100644 --- a/src/app/Components/SwitchMenu.tsx +++ b/src/app/Components/SwitchMenu.tsx @@ -29,7 +29,9 @@ export const SwitchMenu = ({ - + + + ) diff --git a/src/app/Scenes/MyProfile/DarkModeSettings.tsx b/src/app/Scenes/MyProfile/DarkModeSettings.tsx index 2e3a8d4de25..7f8d36a807c 100644 --- a/src/app/Scenes/MyProfile/DarkModeSettings.tsx +++ b/src/app/Scenes/MyProfile/DarkModeSettings.tsx @@ -126,7 +126,7 @@ const RadioMenuItem: React.FC<{ {title} - + From 142ce67343b2cfdf40483d45b97cc258af964156 Mon Sep 17 00:00:00 2001 From: Mounir Dhahri Date: Fri, 19 Dec 2025 09:15:31 +0000 Subject: [PATCH 077/123] fix: fair screen artworks tab issues (#13109) * fix: broken android build (#13106) * chore: attempt fixing android build * chore: bump cache for node * chore: try again * chore: increase workers * chore: use same build command as fastfile * chore: test * chore: minor fair screen improvements * chore: do not use recycled reference for flashlist * chore: bump palette-mobile version * chore: remove lazy --- package.json | 4 +- .../Scenes/Fair/Components/FairArtworks.tsx | 11 +- .../Scenes/Fair/Components/FairExhibitors.tsx | 13 +-- src/app/Scenes/Fair/Components/FairHeader.tsx | 2 +- src/app/Scenes/Fair/Fair.tsx | 104 ++++++++---------- src/app/Scenes/Fair/FairOverview.tsx | 87 ++++++++------- yarn.lock | 33 +++--- 7 files changed, 122 insertions(+), 132 deletions(-) diff --git a/package.json b/package.json index c3c6fe1599d..a7391b9cbb9 100644 --- a/package.json +++ b/package.json @@ -109,7 +109,7 @@ "dependencies": { "@artsy/cohesion": "4.336.0", "@artsy/icons": "3.63.0", - "@artsy/palette-mobile": "22.2.0--canary.425.5134.0", + "@artsy/palette-mobile": "22.2.0--canary.425.5159.0", "@artsy/to-title-case": "1.2.0", "@braze/react-native-sdk": "16.1.0", "@d11/react-native-fast-image": "8.12.0", @@ -168,7 +168,7 @@ "react-native-blob-util": "0.19.11", "react-native-blurhash": "2.1.2", "react-native-bootsplash": "6.3.10", - "react-native-collapsible-tab-view": "8.0.1", + "react-native-collapsible-tab-view": "9.0.0-rc.0", "react-native-device-info": "14.0.0", "react-native-fbsdk-next": "13.4.1", "react-native-gesture-handler": "2.28.0", diff --git a/src/app/Scenes/Fair/Components/FairArtworks.tsx b/src/app/Scenes/Fair/Components/FairArtworks.tsx index 6a5c906d60b..3b7d06b9de8 100644 --- a/src/app/Scenes/Fair/Components/FairArtworks.tsx +++ b/src/app/Scenes/Fair/Components/FairArtworks.tsx @@ -32,8 +32,6 @@ import { PlaceholderGrid } from "app/utils/placeholderGrid" import { ExtractNodeType } from "app/utils/relayHelpers" import { Schema } from "app/utils/track" import React, { useCallback, useEffect, useState } from "react" -import { Platform } from "react-native" -import { useHeaderMeasurements } from "react-native-collapsible-tab-view" import { graphql, useLazyLoadQuery, usePaginationFragment } from "react-relay" import { useTracking } from "react-tracking" @@ -407,12 +405,13 @@ export const FairArtworksQueryRenderer: React.FC const FairArtworksPlaceholder: React.FC = () => { const space = useSpace() - const { height } = useHeaderMeasurements() - // Tabs.ScrollView paddingTop is not working on Android, so we need to set it manually - const paddingTop = Platform.OS === "android" ? height + 80 : space(2) return ( - + 100 Artworks diff --git a/src/app/Scenes/Fair/Components/FairExhibitors.tsx b/src/app/Scenes/Fair/Components/FairExhibitors.tsx index fea7234fe03..be872cd9f3a 100644 --- a/src/app/Scenes/Fair/Components/FairExhibitors.tsx +++ b/src/app/Scenes/Fair/Components/FairExhibitors.tsx @@ -8,8 +8,7 @@ import { extractNodes } from "app/utils/extractNodes" import { ExtractNodeType } from "app/utils/relayHelpers" import { renderWithPlaceholder } from "app/utils/renderWithPlaceholder" import React, { useCallback } from "react" -import { ListRenderItem, Platform } from "react-native" -import { useHeaderMeasurements } from "react-native-collapsible-tab-view" +import { ListRenderItem } from "react-native" import { createPaginationContainer, graphql, QueryRenderer, RelayPaginationProp } from "react-relay" import { FairExhibitorRailQueryRenderer } from "./FairExhibitorRail" @@ -26,10 +25,6 @@ const FairExhibitors: React.FC = ({ fair, relay }) => { const showsWithArtworks = shows.filter((show) => show?.counts?.artworks ?? 0 > 0) const shouldDisplaySpinner = !!shows.length && !!relay.isLoading() && !!relay.hasMore() - const { height } = useHeaderMeasurements() - // Tabs.ScrollView paddingTop is not working on Android, so we need to set it manually - const paddingTop = Platform.OS === "android" ? height + 80 : space(2) - const loadMoreExhibitors = useCallback(() => { if (!relay.hasMore() || relay.isLoading()) { return @@ -55,7 +50,7 @@ const FairExhibitors: React.FC = ({ fair, relay }) => { return ( { return ( diff --git a/src/app/Scenes/Fair/Components/FairHeader.tsx b/src/app/Scenes/Fair/Components/FairHeader.tsx index e79e3bf4b53..a16bd5191d6 100644 --- a/src/app/Scenes/Fair/Components/FairHeader.tsx +++ b/src/app/Scenes/Fair/Components/FairHeader.tsx @@ -66,7 +66,7 @@ const fragment = graphql` slug profile { icon { - imageUrl: url(version: "untouched-png") + imageUrl: url(version: "small") } } image { diff --git a/src/app/Scenes/Fair/Fair.tsx b/src/app/Scenes/Fair/Fair.tsx index 17c7bcee269..a8500527b32 100644 --- a/src/app/Scenes/Fair/Fair.tsx +++ b/src/app/Scenes/Fair/Fair.tsx @@ -23,7 +23,6 @@ import { } from "app/Scenes/Fair/Components/FairExhibitors" import { FairOverviewQueryRenderer } from "app/Scenes/Fair/FairOverview" import { goBack } from "app/system/navigation/navigate" -import { PlaceholderGrid } from "app/utils/placeholderGrid" import { prefetchQuery } from "app/utils/queryPrefetching" import { ProvideScreenTracking, Schema } from "app/utils/track" import React, { Suspense, useCallback, useEffect } from "react" @@ -95,67 +94,56 @@ export const Fair: React.FC = ({ fair }) => { const hasExhibitors = !!data._exhibitors?.totalCount return ( - - handleTabChange(tabName)} - headerProps={{ - onBack: goBack, - rightElements: ( - { - handleSharePress() - }} - > - - - ), + + - - - - - {!!hasExhibitors ? ( - - + handleTabChange(tabName)} + allowHeaderOverscroll + headerProps={{ + onBack: goBack, + rightElements: ( + { + handleSharePress() + }} + > + + + ), + }} + > + + - ) : null} - - - - - Showing X works - Sort & Filter - - - - } - > - - - - - - + {!!hasExhibitors ? ( + + + + ) : null} + + + + + + + ) } diff --git a/src/app/Scenes/Fair/FairOverview.tsx b/src/app/Scenes/Fair/FairOverview.tsx index a98e67ce88d..3ce65d7d1aa 100644 --- a/src/app/Scenes/Fair/FairOverview.tsx +++ b/src/app/Scenes/Fair/FairOverview.tsx @@ -1,5 +1,5 @@ import { ChevronSmallRightIcon } from "@artsy/icons/native" -import { Flex, Separator, Spacer, Spinner, Tabs, Text, useSpace } from "@artsy/palette-mobile" +import { Flex, Spacer, Spinner, Tabs, Text, useSpace } from "@artsy/palette-mobile" import { FairOverviewQuery } from "__generated__/FairOverviewQuery.graphql" import { FairOverview_fair$key } from "__generated__/FairOverview_fair.graphql" import { ReadMore } from "app/Components/ReadMore" @@ -12,9 +12,8 @@ import { shouldShowLocationMap } from "app/Scenes/Fair/FairMoreInfo" import { RouterLink } from "app/system/navigation/RouterLink" import { truncatedTextLimit } from "app/utils/hardware" import { withSuspense } from "app/utils/hooks/withSuspense" +import { compact } from "lodash" import { FC } from "react" -import { Platform } from "react-native" -import { useHeaderMeasurements } from "react-native-collapsible-tab-view" import { graphql, useFragment, useLazyLoadQuery } from "react-relay" interface FairOverviewProps { @@ -46,38 +45,55 @@ export const FairOverview: FC = ({ fair }) => { !!data.tickets const isEmpty = !previewText && !hasArticles && !hasCollections && !hasFollowedArtistArtworks - return ( - - {!isEmpty ? ( - - {!!previewText && ( - - )} - {!!canShowMoreInfoLink && ( - - - More info - - - - )} - - - - - {!!hasArticles && } - {!!hasCollections && } - {!!hasFollowedArtistArtworks && ( - - )} + if (isEmpty) { + return ( + + + + ) + } + const sections = compact([ + !!previewText && { + key: "summary", + content: ( + + + + ), + }, + !!canShowMoreInfoLink && { + key: "showMoreInfoLink", + content: ( + + + More info + + + ), + }, + !!hasArticles && { + key: "editorial", + content: , + }, + !!hasCollections && { + key: "collections", + content: , + }, + !!hasFollowedArtistArtworks && { + key: "followedArtistArtworks", + content: , + }, + ]) - - - ) : ( - - )} - + return ( + item.content} + ItemSeparatorComponent={() => } + keyExtractor={(item) => item.key} + contentContainerStyle={{ marginHorizontal: 0 }} + /> ) } @@ -146,13 +162,10 @@ export const FairOverviewQueryRenderer: React.FC<{ fairID: string }> = withSuspe const FairOverviewPlaceholder: React.FC = () => { const space = useSpace() - const { height } = useHeaderMeasurements() - // Tabs.ScrollView paddingTop is not working on Android, so we need to set it manually - const paddingTop = Platform.OS === "android" ? height + 80 : space(4) return ( diff --git a/yarn.lock b/yarn.lock index 98ff9c8f9c5..7ece6d0475c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -72,9 +72,9 @@ __metadata: languageName: node linkType: hard -"@artsy/palette-mobile@npm:22.2.0--canary.425.5134.0": - version: 22.2.0--canary.425.5134.0 - resolution: "@artsy/palette-mobile@npm:22.2.0--canary.425.5134.0" +"@artsy/palette-mobile@npm:22.2.0--canary.425.5159.0": + version: 22.2.0--canary.425.5159.0 + resolution: "@artsy/palette-mobile@npm:22.2.0--canary.425.5159.0" dependencies: "@artsy/icons": "npm:^3.49.0" "@artsy/palette-tokens": "npm:7.0.0" @@ -87,7 +87,7 @@ __metadata: moti: "npm:0.30.0" react-nanny: "npm:^2.15.0" react-native-blurhash: "npm:2.1.2" - react-native-collapsible-tab-view: "npm:^8.0.1" + react-native-collapsible-tab-view: "npm:9.0.0-rc.0" react-native-pager-view: "npm:6.7.1" react-native-popover-view: "npm:^6.1.0" styled-system: "npm:^5.1.5" @@ -101,7 +101,7 @@ __metadata: react-native-reanimated: "*" react-native-svg: "*" styled-components: ">= 5" - checksum: 10c0/8faf76baf78931a6e249ed63f3f2431fc1cb01e99c886ed075910eb0f0f1f73428b35dec8dcd02ca8225363d9c30f9114bc05dbd58f4afb8530f4204e843816e + checksum: 10c0/10d113d67c810036b9c264c4b9246214183e7000d826540d8852f2db8aeae927609ef9b1ca2c1ee81c14fd92512fb376176b92b997ea6b3ee3f26f89029ba476 languageName: node linkType: hard @@ -13163,15 +13163,9 @@ __metadata: version: 0.0.0-use.local resolution: "eigen@workspace:." dependencies: -<<<<<<< HEAD "@artsy/cohesion": "npm:4.336.0" "@artsy/icons": "npm:3.63.0" - "@artsy/palette-mobile": "npm:22.2.0--canary.425.5130.0" -======= - "@artsy/cohesion": "npm:4.335.0" - "@artsy/icons": "npm:3.62.0" - "@artsy/palette-mobile": "npm:22.2.0--canary.425.5134.0" ->>>>>>> b944009a52 (chore: bump palette-mobile again) + "@artsy/palette-mobile": "npm:22.2.0--canary.425.5159.0" "@artsy/to-title-case": "npm:1.2.0" "@artsy/update-repo": "npm:0.7.0" "@babel/core": "npm:7.25.2" @@ -13331,7 +13325,7 @@ __metadata: react-native-blob-util: "npm:0.19.11" react-native-blurhash: "npm:2.1.2" react-native-bootsplash: "npm:6.3.10" - react-native-collapsible-tab-view: "npm:8.0.1" + react-native-collapsible-tab-view: "npm:9.0.0-rc.0" react-native-device-info: "npm:14.0.0" react-native-fbsdk-next: "npm:13.4.1" react-native-gesture-handler: "npm:2.28.0" @@ -22082,21 +22076,22 @@ __metadata: languageName: node linkType: hard -"react-native-collapsible-tab-view@npm:8.0.1, react-native-collapsible-tab-view@npm:^8.0.1": - version: 8.0.1 - resolution: "react-native-collapsible-tab-view@npm:8.0.1" +"react-native-collapsible-tab-view@npm:9.0.0-rc.0": + version: 9.0.0-rc.0 + resolution: "react-native-collapsible-tab-view@npm:9.0.0-rc.0" dependencies: use-deep-compare: "npm:^1.1.0" peerDependencies: - "@shopify/flash-list": ">=1.0.0" + "@shopify/flash-list": ">=2.0.0" react: "*" react-native: "*" react-native-pager-view: "*" - react-native-reanimated: ">=3.8.1" + react-native-reanimated: ">=4.1.0" + react-native-worklets: ">=0.5.1" peerDependenciesMeta: "@shopify/flash-list": optional: true - checksum: 10c0/b4d8c8936cb8b647fc50a5e8ccbb4875d74cc68f90864e13980ec5351b9b49acbe84890c629dc1343f23730295483bd25c219435fd738dd3ac7ac879f221e620 + checksum: 10c0/6297022971370d3e8819cb866203e20bbcaab50009b8f5e8cecb9bf04ae96361131aef073d4c4cc8ffa7e625934a18c2a7ee3d5bb180560c8579bea523035361 languageName: node linkType: hard From 6752901d3dbecd381fffa2e43102cc07869df0a5 Mon Sep 17 00:00:00 2001 From: Mounir Dhahri Date: Mon, 29 Dec 2025 11:45:58 +0100 Subject: [PATCH 078/123] fix: artwork grid padding issues --- .../Screens/ArtworkForm/Components/ArtworkAutosuggest.tsx | 2 +- .../ArtworkForm/Components/ArtworkAutosuggestResults.tsx | 5 +++-- src/app/Scenes/Search/SearchArtworksGrid.tsx | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/app/Scenes/MyCollection/Screens/ArtworkForm/Components/ArtworkAutosuggest.tsx b/src/app/Scenes/MyCollection/Screens/ArtworkForm/Components/ArtworkAutosuggest.tsx index 9cfb7186bf5..91b7f385797 100644 --- a/src/app/Scenes/MyCollection/Screens/ArtworkForm/Components/ArtworkAutosuggest.tsx +++ b/src/app/Scenes/MyCollection/Screens/ArtworkForm/Components/ArtworkAutosuggest.tsx @@ -58,7 +58,7 @@ export const ArtworkAutosuggest: React.FC = ({ )} {!!keyword.length && ( - + { const screen = useScreenDimensions() + const space = useSpace() return ( - - + + ) } diff --git a/src/app/Scenes/Search/SearchArtworksGrid.tsx b/src/app/Scenes/Search/SearchArtworksGrid.tsx index 70f2b832453..1f9112cdd57 100644 --- a/src/app/Scenes/Search/SearchArtworksGrid.tsx +++ b/src/app/Scenes/Search/SearchArtworksGrid.tsx @@ -103,7 +103,7 @@ const SearchArtworksGrid: React.FC = ({ viewer, relay, - + Date: Mon, 29 Dec 2025 13:56:43 +0100 Subject: [PATCH 079/123] chore: bump palette-mobile version --- package.json | 2 +- yarn.lock | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index a7391b9cbb9..44ff97dc89e 100644 --- a/package.json +++ b/package.json @@ -109,7 +109,7 @@ "dependencies": { "@artsy/cohesion": "4.336.0", "@artsy/icons": "3.63.0", - "@artsy/palette-mobile": "22.2.0--canary.425.5159.0", + "@artsy/palette-mobile": "22.2.0--canary.425.5168.0", "@artsy/to-title-case": "1.2.0", "@braze/react-native-sdk": "16.1.0", "@d11/react-native-fast-image": "8.12.0", diff --git a/yarn.lock b/yarn.lock index 7ece6d0475c..0e4922003ab 100644 --- a/yarn.lock +++ b/yarn.lock @@ -72,9 +72,9 @@ __metadata: languageName: node linkType: hard -"@artsy/palette-mobile@npm:22.2.0--canary.425.5159.0": - version: 22.2.0--canary.425.5159.0 - resolution: "@artsy/palette-mobile@npm:22.2.0--canary.425.5159.0" +"@artsy/palette-mobile@npm:22.2.0--canary.425.5168.0": + version: 22.2.0--canary.425.5168.0 + resolution: "@artsy/palette-mobile@npm:22.2.0--canary.425.5168.0" dependencies: "@artsy/icons": "npm:^3.49.0" "@artsy/palette-tokens": "npm:7.0.0" @@ -101,7 +101,7 @@ __metadata: react-native-reanimated: "*" react-native-svg: "*" styled-components: ">= 5" - checksum: 10c0/10d113d67c810036b9c264c4b9246214183e7000d826540d8852f2db8aeae927609ef9b1ca2c1ee81c14fd92512fb376176b92b997ea6b3ee3f26f89029ba476 + checksum: 10c0/7e074b6cf02860688492151c0f7c51077385f43bd298f74696ce5a3970071d2fe6ac6aa66d20f2797ad64eec5bc2c72ed256e2fe79feeaca480907e79c120e76 languageName: node linkType: hard @@ -13165,7 +13165,7 @@ __metadata: dependencies: "@artsy/cohesion": "npm:4.336.0" "@artsy/icons": "npm:3.63.0" - "@artsy/palette-mobile": "npm:22.2.0--canary.425.5159.0" + "@artsy/palette-mobile": "npm:22.2.0--canary.425.5168.0" "@artsy/to-title-case": "npm:1.2.0" "@artsy/update-repo": "npm:0.7.0" "@babel/core": "npm:7.25.2" From 4cf33ad52bb4591df546aa6f772ef425f676f5c9 Mon Sep 17 00:00:00 2001 From: Mounir Dhahri Date: Mon, 29 Dec 2025 16:22:54 +0100 Subject: [PATCH 080/123] chore: bump palette-mobile again --- package.json | 2 +- yarn.lock | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index 44ff97dc89e..4e985d734d7 100644 --- a/package.json +++ b/package.json @@ -109,7 +109,7 @@ "dependencies": { "@artsy/cohesion": "4.336.0", "@artsy/icons": "3.63.0", - "@artsy/palette-mobile": "22.2.0--canary.425.5168.0", + "@artsy/palette-mobile": "22.2.0--canary.425.5173.0", "@artsy/to-title-case": "1.2.0", "@braze/react-native-sdk": "16.1.0", "@d11/react-native-fast-image": "8.12.0", diff --git a/yarn.lock b/yarn.lock index 0e4922003ab..883a1a18f17 100644 --- a/yarn.lock +++ b/yarn.lock @@ -72,9 +72,9 @@ __metadata: languageName: node linkType: hard -"@artsy/palette-mobile@npm:22.2.0--canary.425.5168.0": - version: 22.2.0--canary.425.5168.0 - resolution: "@artsy/palette-mobile@npm:22.2.0--canary.425.5168.0" +"@artsy/palette-mobile@npm:22.2.0--canary.425.5173.0": + version: 22.2.0--canary.425.5173.0 + resolution: "@artsy/palette-mobile@npm:22.2.0--canary.425.5173.0" dependencies: "@artsy/icons": "npm:^3.49.0" "@artsy/palette-tokens": "npm:7.0.0" @@ -101,7 +101,7 @@ __metadata: react-native-reanimated: "*" react-native-svg: "*" styled-components: ">= 5" - checksum: 10c0/7e074b6cf02860688492151c0f7c51077385f43bd298f74696ce5a3970071d2fe6ac6aa66d20f2797ad64eec5bc2c72ed256e2fe79feeaca480907e79c120e76 + checksum: 10c0/2ba4f6d9c8429565dfc3b97b1597e0d7198c94ef67d6b061472b33844328ed01f5968fc734386cec272ddca2cedf364550e8490a1b78c4074263ffa426236c07 languageName: node linkType: hard @@ -13165,7 +13165,7 @@ __metadata: dependencies: "@artsy/cohesion": "npm:4.336.0" "@artsy/icons": "npm:3.63.0" - "@artsy/palette-mobile": "npm:22.2.0--canary.425.5168.0" + "@artsy/palette-mobile": "npm:22.2.0--canary.425.5173.0" "@artsy/to-title-case": "npm:1.2.0" "@artsy/update-repo": "npm:0.7.0" "@babel/core": "npm:7.25.2" From d6c06448f2d157bb9bc1a4e33100b30b2b623b18 Mon Sep 17 00:00:00 2001 From: Mounir Dhahri Date: Mon, 29 Dec 2025 16:33:49 +0100 Subject: [PATCH 081/123] chore: use PagerView instead of horizontal Flatlist for artist insights --- .../CareerHighlightsBigCardsSwiper.tsx | 29 +++++++------------ 1 file changed, 11 insertions(+), 18 deletions(-) diff --git a/src/app/Scenes/MyCollection/Screens/Insights/CareerHighlightsBigCardsSwiper.tsx b/src/app/Scenes/MyCollection/Screens/Insights/CareerHighlightsBigCardsSwiper.tsx index 5ef3bf04457..c7b91c61973 100644 --- a/src/app/Scenes/MyCollection/Screens/Insights/CareerHighlightsBigCardsSwiper.tsx +++ b/src/app/Scenes/MyCollection/Screens/Insights/CareerHighlightsBigCardsSwiper.tsx @@ -7,7 +7,8 @@ import { useScreenDimensions } from "app/utils/hooks" import { PlaceholderBox, ProvidePlaceholderContext } from "app/utils/placeholders" import { compact } from "lodash" import { Suspense, useState } from "react" -import { Animated, NativeScrollEvent, NativeSyntheticEvent, ScrollView } from "react-native" +import { Animated } from "react-native" +import PagerView from "react-native-pager-view" import { graphql, useLazyLoadQuery } from "react-relay" import { CareerHighlightBigCardBiennial, @@ -101,11 +102,9 @@ const CareerHighlightsBigCardsSwiperScreen: React.FC) => { + const setSliderPage = (event: any) => { const { currentPage } = sliderState - const { x } = event.nativeEvent.contentOffset - - const currentSlide = Math.round(x / screenWidth) + const currentSlide = event.nativeEvent.position if (currentSlide !== currentPage) { setSliderState({ @@ -160,21 +159,15 @@ const CareerHighlightsBigCardsSwiperScreen: React.FC - ) => - setSliderPage(event) - } - > + {slides.map(({ key, content }) => { - return {content} + return ( + + {content} + + ) })} - + ) } From 2acaef0b69b2326f4cdd4b308c52d51160d68f6e Mon Sep 17 00:00:00 2001 From: Mounir Dhahri Date: Mon, 29 Dec 2025 16:37:49 +0100 Subject: [PATCH 082/123] fix: nested scrollview warning --- .../Components/MyCollectionCollectedArtistsView.tsx | 5 ++--- src/app/Scenes/MyCollection/MyCollection.tsx | 4 +--- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/app/Scenes/MyCollection/Components/MyCollectionCollectedArtistsView.tsx b/src/app/Scenes/MyCollection/Components/MyCollectionCollectedArtistsView.tsx index e36650140a4..e0a211773da 100644 --- a/src/app/Scenes/MyCollection/Components/MyCollectionCollectedArtistsView.tsx +++ b/src/app/Scenes/MyCollection/Components/MyCollectionCollectedArtistsView.tsx @@ -1,4 +1,4 @@ -import { Flex, Spacer, Spinner } from "@artsy/palette-mobile" +import { Flex, Spacer, Spinner, Tabs } from "@artsy/palette-mobile" import { MyCollectionCollectedArtistsView_me$key } from "__generated__/MyCollectionCollectedArtistsView_me.graphql" import { FilteredArtworkGridZeroState as FilteredArtistsZeroState } from "app/Components/ArtworkGrids/FilteredArtworkGridZeroState" import { MyCollectionArtistFilters } from "app/Scenes/MyCollection/Components/MyCollectionArtistFiltersStickyTab" @@ -9,7 +9,6 @@ import { extractEdges } from "app/utils/extractEdges" import { useRefreshControl } from "app/utils/refreshHelpers" import { stringIncludes } from "app/utils/stringHelpers" import { useEffect } from "react" -import { FlatList } from "react-native" import { graphql, usePaginationFragment } from "react-relay" interface MyCollectionCollectedArtistsViewProps { @@ -64,7 +63,7 @@ export const MyCollectionCollectedArtistsView: React.FC {filteredUserInterests.length > 0 ? ( - "list" + item?.internalID} diff --git a/src/app/Scenes/MyCollection/MyCollection.tsx b/src/app/Scenes/MyCollection/MyCollection.tsx index 51e2edc1a82..c1ffef89a8b 100644 --- a/src/app/Scenes/MyCollection/MyCollection.tsx +++ b/src/app/Scenes/MyCollection/MyCollection.tsx @@ -143,9 +143,7 @@ const MyCollection: React.FC = () => { - - - + From 42e108fd32cbc57cf15a5e49235bdddc4c39965b Mon Sep 17 00:00:00 2001 From: Mounir Dhahri Date: Mon, 29 Dec 2025 17:00:42 +0100 Subject: [PATCH 083/123] chore: enable freeze for performance --- src/app/App.tsx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/app/App.tsx b/src/app/App.tsx index 5806535cc52..ab2137332db 100644 --- a/src/app/App.tsx +++ b/src/app/App.tsx @@ -28,6 +28,7 @@ import { NativeModules, UIManager, View } from "react-native" import { Settings } from "react-native-fbsdk-next" import "react-native-get-random-values" import Keys from "react-native-keys" +import { enableFreeze } from "react-native-screens" import { useWebViewCookies } from "./Components/ArtsyWebView" import { Providers } from "./Providers" import { ForceUpdate } from "./Scenes/ForceUpdate/ForceUpdate" @@ -41,6 +42,8 @@ import useSyncNativeAuthState from "./utils/useSyncAuthState" require("./system/ignoreLogs") +enableFreeze(true) + if (__DEV__) { // Don't open RN dev menu with shake. We use it for our own Dev Menu. NativeModules.DevSettings.setIsShakeToShowDevMenuEnabled(false) From 852460cb6373fef0f7b9d6bb9d19719952fd726c Mon Sep 17 00:00:00 2001 From: Mounir Dhahri Date: Mon, 5 Jan 2026 10:43:39 +0100 Subject: [PATCH 084/123] fix: blank screen on sign out --- src/app/store/AuthModel.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/app/store/AuthModel.ts b/src/app/store/AuthModel.ts index 3562255565f..193a323723d 100644 --- a/src/app/store/AuthModel.ts +++ b/src/app/store/AuthModel.ts @@ -1002,9 +1002,8 @@ export const getAuthModel = (): AuthModel => ({ await AsyncStorage.clear(), CookieManager.clearAll(), _globalCacheRef?.clear(), + actions.setSessionState({ isUserIdentified: true }), ]) - - actions.setSessionState({ isUserIdentified: true }) }), verifyUser: thunk(async (actions, { email, recaptchaToken }) => { let result: Response From ea2133c46f07294ff8671d115fa50b32dcb42a22 Mon Sep 17 00:00:00 2001 From: Mounir Dhahri Date: Mon, 5 Jan 2026 10:43:53 +0100 Subject: [PATCH 085/123] chore: do not freeze --- src/app/App.tsx | 3 --- src/app/system/devTools/DevMenu/DevMenu.tsx | 5 ++--- src/app/system/devTools/DevMenu/DevMenuWrapper.tsx | 3 +-- .../system/devTools/DevMenu/utils/navigateToDevMenu.ts | 10 ++-------- src/app/system/devTools/useRageShakeDevMenu.ts | 5 ++--- 5 files changed, 7 insertions(+), 19 deletions(-) diff --git a/src/app/App.tsx b/src/app/App.tsx index ab2137332db..5806535cc52 100644 --- a/src/app/App.tsx +++ b/src/app/App.tsx @@ -28,7 +28,6 @@ import { NativeModules, UIManager, View } from "react-native" import { Settings } from "react-native-fbsdk-next" import "react-native-get-random-values" import Keys from "react-native-keys" -import { enableFreeze } from "react-native-screens" import { useWebViewCookies } from "./Components/ArtsyWebView" import { Providers } from "./Providers" import { ForceUpdate } from "./Scenes/ForceUpdate/ForceUpdate" @@ -42,8 +41,6 @@ import useSyncNativeAuthState from "./utils/useSyncAuthState" require("./system/ignoreLogs") -enableFreeze(true) - if (__DEV__) { // Don't open RN dev menu with shake. We use it for our own Dev Menu. NativeModules.DevSettings.setIsShakeToShowDevMenuEnabled(false) diff --git a/src/app/system/devTools/DevMenu/DevMenu.tsx b/src/app/system/devTools/DevMenu/DevMenu.tsx index 10e0415d583..10d346856f9 100644 --- a/src/app/system/devTools/DevMenu/DevMenu.tsx +++ b/src/app/system/devTools/DevMenu/DevMenu.tsx @@ -4,7 +4,6 @@ import { NavigationProp, useNavigation } from "@react-navigation/native" import { ArtsyNativeModule } from "app/NativeModules/ArtsyNativeModule" import { AuthenticatedRoutesParams } from "app/Navigation/AuthenticatedRoutes/Tabs" import { LargeHeaderView } from "app/Navigation/utils/LargeHeaderView" -import { __unsafe__onboardingNavigationRef } from "app/Scenes/Onboarding/Screens/Onboarding" import { GlobalStore } from "app/store/GlobalStore" import { DevMenuButtonItem } from "app/system/devTools/DevMenu/Components/DevMenuButtonItem" import { DevTools } from "app/system/devTools/DevMenu/Components/DevTools" @@ -26,7 +25,7 @@ export const DevMenu: React.FC<{}> = () => { const fontScale = PixelRatio.getFontScale() const navigation = useNavigation>() const setDarkModeOption = GlobalStore.actions.devicePrefs.setDarkModeOption - + const isLoggedIn = GlobalStore.useAppState((state) => !!state.auth.userAccessToken) const handleBackButton = () => { goBack() return true @@ -79,7 +78,7 @@ export const DevMenu: React.FC<{}> = () => { { // The logged out stack is using a js react-navigation stack instead of a native stack // and it doesn't support large headers so we don't need this additional header - !__unsafe__onboardingNavigationRef.current ? : null + !isLoggedIn ? : null } Build:{" "} diff --git a/src/app/system/devTools/DevMenu/DevMenuWrapper.tsx b/src/app/system/devTools/DevMenu/DevMenuWrapper.tsx index fe6aa9445a3..1b9c6ac7049 100644 --- a/src/app/system/devTools/DevMenu/DevMenuWrapper.tsx +++ b/src/app/system/devTools/DevMenu/DevMenuWrapper.tsx @@ -11,7 +11,6 @@ const MIN_DURATION_BETWEEN_TAPS = 70 export const DevMenuWrapper: React.FC = ({ children }) => { const userIsDev = GlobalStore.useAppState((store) => store.artsyPrefs.userIsDev.value) - const isLoggedIn = GlobalStore.useAppState((state) => !!state.auth.userAccessToken) const isDeepZoomModalVisible = GlobalStore.useAppState( (store) => store.devicePrefs.sessionState.isDeepZoomModalVisible ) @@ -41,7 +40,7 @@ export const DevMenuWrapper: React.FC = ({ children }) if (state.numTaps >= 5 && !isDeepZoomModalVisible) { state.numTaps = 0 - navigateToDevMenu({ isLoggedIn }) + navigateToDevMenu() } return false }, [isDeepZoomModalVisible]) diff --git a/src/app/system/devTools/DevMenu/utils/navigateToDevMenu.ts b/src/app/system/devTools/DevMenu/utils/navigateToDevMenu.ts index e4237139d3b..ec4d80b5155 100644 --- a/src/app/system/devTools/DevMenu/utils/navigateToDevMenu.ts +++ b/src/app/system/devTools/DevMenu/utils/navigateToDevMenu.ts @@ -1,11 +1,5 @@ import { internal_navigationRef } from "app/Navigation/Navigation" -import { __unsafe__onboardingNavigationRef } from "app/Scenes/Onboarding/Screens/Onboarding" -export const navigateToDevMenu = ({ isLoggedIn }: { isLoggedIn: boolean }) => { - if (!isLoggedIn) { - __unsafe__onboardingNavigationRef.current?.navigate("DevMenu") - } else { - // We are intentionally using navigate from the navigation ref to avoid showing the dev menu twice on multiple taps - internal_navigationRef.current?.navigate("DevMenu") - } +export const navigateToDevMenu = () => { + internal_navigationRef.current?.navigate("DevMenu") } diff --git a/src/app/system/devTools/useRageShakeDevMenu.ts b/src/app/system/devTools/useRageShakeDevMenu.ts index 0d87b0d836e..071f79bd23a 100644 --- a/src/app/system/devTools/useRageShakeDevMenu.ts +++ b/src/app/system/devTools/useRageShakeDevMenu.ts @@ -5,7 +5,6 @@ import RNShake from "react-native-shake" export const useRageShakeDevMenu = () => { const userIsDev = GlobalStore.useAppState((s) => s.artsyPrefs.userIsDev.value) - const isLoggedIn = GlobalStore.useAppState((state) => !!state.auth.userAccessToken) const isHydrated = GlobalStore.useAppState((state) => state.sessionState.isHydrated) useEffect(() => { @@ -14,11 +13,11 @@ export const useRageShakeDevMenu = () => { return } - navigateToDevMenu({ isLoggedIn }) + navigateToDevMenu() }) return () => { subscription.remove() } - }, [userIsDev, isHydrated, isLoggedIn]) + }, [userIsDev, isHydrated]) } From ef19f5554299cd83d9c4413f873f16aa33925c04 Mon Sep 17 00:00:00 2001 From: Mounir Dhahri Date: Mon, 5 Jan 2026 11:50:48 +0100 Subject: [PATCH 086/123] chore: update launch arguments version --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 4e985d734d7..8a6785dc253 100644 --- a/package.json +++ b/package.json @@ -180,7 +180,7 @@ "react-native-ios-utilities": "5.2.0", "react-native-keychain": "10.0.0", "react-native-keys": "0.7.13", - "react-native-launch-arguments": "git+https://github.com/artsy/react-native-launch-arguments.git#v4.1.0-new-architecture", + "react-native-launch-arguments": "git+https://github.com/artsy/react-native-launch-arguments.git#v4.1.0-new-architecture-2", "react-native-linear-gradient": "2.8.3", "react-native-localize": "3.5.2", "react-native-pager-view": "7.0.1", diff --git a/yarn.lock b/yarn.lock index 883a1a18f17..a9b8af3b82c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -13337,7 +13337,7 @@ __metadata: react-native-ios-utilities: "npm:5.2.0" react-native-keychain: "npm:10.0.0" react-native-keys: "npm:0.7.13" - react-native-launch-arguments: "git+https://github.com/artsy/react-native-launch-arguments.git#v4.1.0-new-architecture" + react-native-launch-arguments: "git+https://github.com/artsy/react-native-launch-arguments.git#v4.1.0-new-architecture-2" react-native-linear-gradient: "npm:2.8.3" react-native-localize: "npm:3.5.2" react-native-pager-view: "npm:7.0.1" @@ -22224,13 +22224,13 @@ __metadata: languageName: node linkType: hard -"react-native-launch-arguments@git+https://github.com/artsy/react-native-launch-arguments.git#v4.1.0-new-architecture": +"react-native-launch-arguments@git+https://github.com/artsy/react-native-launch-arguments.git#v4.1.0-new-architecture-2": version: 4.1.0 - resolution: "react-native-launch-arguments@https://github.com/artsy/react-native-launch-arguments.git#commit=c870e0469deef35920bcc267da48d77cd7521924" + resolution: "react-native-launch-arguments@https://github.com/artsy/react-native-launch-arguments.git#commit=329441de0f5cecd0f421a601c9f9c8cfae8b017e" peerDependencies: react: ">=16.8.1" react-native: ">=0.60.0-rc.0 <1.0.x" - checksum: 10c0/75046c7efff16d148527c7e89475c706227c5ddb066ca8dcb8a9a4d2ab7f2d11934a34b036a91b0999098a7692c9465374de2f7194adc53a6ca42bb1a12b9637 + checksum: 10c0/5688b748a5cd02a334675293b4748db2660120681586e9dbee04be712f59bc8e983dc3dc4f476ffe66bafaffa050f61bc16589eb0d685a47d8034a5f6ef22508 languageName: node linkType: hard From af5383bed1ba145a4c15cbc8dd938612b26bd28f Mon Sep 17 00:00:00 2001 From: Mounir Dhahri Date: Mon, 5 Jan 2026 14:54:31 +0100 Subject: [PATCH 087/123] fix: broken career highlights year test --- .../Insights/CareerHighlightBottomSheet.tsx | 4 +++- .../CareerHighlightBottomSheet.tests.tsx | 18 ++++++++++-------- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/src/app/Scenes/MyCollection/Screens/Insights/CareerHighlightBottomSheet.tsx b/src/app/Scenes/MyCollection/Screens/Insights/CareerHighlightBottomSheet.tsx index 5700f2d3cc7..95481d0109b 100644 --- a/src/app/Scenes/MyCollection/Screens/Insights/CareerHighlightBottomSheet.tsx +++ b/src/app/Scenes/MyCollection/Screens/Insights/CareerHighlightBottomSheet.tsx @@ -164,6 +164,8 @@ const careerHighlighsBottomSheetFragment = graphql` } ` +const MAX_YEAR_DIFFERENCE = 8 +export const MINIMUM_YEAR = new Date().getFullYear() - MAX_YEAR_DIFFERENCE /** * Prepares the eventDigest and creates a map of each year to the highlight kind * @param eventDigest @@ -183,7 +185,7 @@ const careerHighlighsBottomSheetFragment = graphql` export const makeCareerHighlightMap = ( eventDigest: string ): Record> => { - const minimumYear = new Date().getFullYear() - 8 + const minimumYear = MINIMUM_YEAR const result: Record> = {} const arr = eventDigest ? eventDigest.split(";") : [] if (!arr.length) { diff --git a/src/app/Scenes/MyCollection/Screens/Insights/__tests__/CareerHighlightBottomSheet.tests.tsx b/src/app/Scenes/MyCollection/Screens/Insights/__tests__/CareerHighlightBottomSheet.tests.tsx index 7676988e54d..2054dfee23d 100644 --- a/src/app/Scenes/MyCollection/Screens/Insights/__tests__/CareerHighlightBottomSheet.tests.tsx +++ b/src/app/Scenes/MyCollection/Screens/Insights/__tests__/CareerHighlightBottomSheet.tests.tsx @@ -3,6 +3,7 @@ import { MedianSalePriceAtAuctionQuery } from "__generated__/MedianSalePriceAtAu import { CareerHighlightBottomSheet, makeCareerHighlightMap, + MINIMUM_YEAR, } from "app/Scenes/MyCollection/Screens/Insights/CareerHighlightBottomSheet" import { MedianSalePriceAtAuctionScreenQuery } from "app/Scenes/MyCollection/Screens/Insights/MedianSalePriceAtAuction" import { @@ -64,16 +65,17 @@ describe(makeCareerHighlightMap, () => { it("Prepares the eventDigest and creates a map of each year to the highlight kind", () => { const result = makeCareerHighlightMap( - "2017 Group Show @ MOCA Los Angeles; 2015 Reviewed Solo Show @ The Guardian; 2015 Reviewed Solo Show @ Art in America" + `2020 Group Show @ MOCA Los Angeles; ${MINIMUM_YEAR} Reviewed Solo Show @ The Guardian; 2018 Reviewed Solo Show @ Art in America` ) expect(result).toEqual({ - 2017: { "Group Show": ["MOCA Los Angeles"] }, + [MINIMUM_YEAR]: { Review: ["The Guardian", "Art in America"] }, + 2020: { "Group Show": ["MOCA Los Angeles"] }, }) }) - it("Returns an empty object if the year is less than 2014", async () => { - const result = await makeCareerHighlightMap( + it("Returns an empty object if the year is outside the 8-year window", () => { + const result = makeCareerHighlightMap( "2013 Group Show @ MOCA Los Angeles; 2012 Reviewed Solo Show @ The Guardian; 2011 Reviewed Solo Show @ Art in America" ) @@ -87,17 +89,17 @@ const bottomSheetDataMock = { { node: { eventDigest: - "2018 Group Show @ MOCA Los Angeles; 2015 Reviewed Solo Show @ The Guardian; 2015 Reviewed Solo Show @ Art in America; ", + "2020 Group Show @ MOCA Los Angeles; 2018 Reviewed Solo Show @ The Guardian; 2018 Reviewed Solo Show @ Art in America; ", sparkles: "0", - year: "year_2017", + year: "year_2019", }, }, { node: { eventDigest: - "2018 Group Show @ MOCA Los Angeles; 2015 Reviewed Solo Show @ The Guardian; 2015 Reviewed Solo Show @ Art in America; ", + "2020 Group Show @ MOCA Los Angeles; 2018 Reviewed Solo Show @ The Guardian; 2018 Reviewed Solo Show @ Art in America; ", sparkles: "10", - year: "year_2018", + year: "year_2020", }, }, ], From 59bc54af35b044e3b15df92bdee1c1c1113e52e1 Mon Sep 17 00:00:00 2001 From: George Kartalis Date: Mon, 5 Jan 2026 16:51:49 +0100 Subject: [PATCH 088/123] free up disk space --- .github/workflows/android-e2e-maestro.yml | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/.github/workflows/android-e2e-maestro.yml b/.github/workflows/android-e2e-maestro.yml index d9e177a7764..144b4dcb974 100644 --- a/.github/workflows/android-e2e-maestro.yml +++ b/.github/workflows/android-e2e-maestro.yml @@ -65,6 +65,17 @@ jobs: - name: Add Maestro to PATH run: echo "$HOME/.maestro/bin" >> $GITHUB_PATH + - name: Free up disk space + run: | + echo "🧹 Before cleanup:" + df -h + sudo rm -rf /usr/share/dotnet + sudo rm -rf /opt/ghc + sudo rm -rf /usr/local/share/boost + sudo rm -rf "$AGENT_TOOLSDIRECTORY" + echo "🧹 After cleanup:" + df -h + - name: Run tests with Android emulator uses: reactivecircus/android-emulator-runner@v2 with: @@ -73,7 +84,7 @@ jobs: arch: x86_64 ram-size: "8192M" heap-size: "4096M" - disk-size: "10G" + disk-size: "8G" cores: 4 disable-animations: false disable-spellchecker: true From 2319d271e112cedff2911fbde329d68202757373 Mon Sep 17 00:00:00 2001 From: George Kartalis Date: Mon, 5 Jan 2026 16:53:26 +0100 Subject: [PATCH 089/123] increase timeout for ios build --- .github/workflows/build-maestro-ios.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-maestro-ios.yml b/.github/workflows/build-maestro-ios.yml index 78513e9cfb1..6a6066ab173 100644 --- a/.github/workflows/build-maestro-ios.yml +++ b/.github/workflows/build-maestro-ios.yml @@ -12,7 +12,7 @@ jobs: build-ios-qa: # if: github.ref == 'refs/heads/main' runs-on: macos-15 - timeout-minutes: 90 + timeout-minutes: 120 steps: - name: Checkout repository From 105675fd9506ea3fe55ec46be8177861b020704e Mon Sep 17 00:00:00 2001 From: George Kartalis Date: Tue, 6 Jan 2026 10:46:10 +0100 Subject: [PATCH 090/123] free disk space --- .github/workflows/android-e2e-maestro.yml | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/.github/workflows/android-e2e-maestro.yml b/.github/workflows/android-e2e-maestro.yml index 144b4dcb974..9e3a6aa8efd 100644 --- a/.github/workflows/android-e2e-maestro.yml +++ b/.github/workflows/android-e2e-maestro.yml @@ -65,16 +65,14 @@ jobs: - name: Add Maestro to PATH run: echo "$HOME/.maestro/bin" >> $GITHUB_PATH - - name: Free up disk space - run: | - echo "🧹 Before cleanup:" - df -h - sudo rm -rf /usr/share/dotnet - sudo rm -rf /opt/ghc - sudo rm -rf /usr/local/share/boost - sudo rm -rf "$AGENT_TOOLSDIRECTORY" - echo "🧹 After cleanup:" - df -h + - name: Free Disk Space (Ubuntu) + uses: AdityaGarg8/remove-unwanted-software@v5 + with: + remove-dotnet: true + remove-haskell: true + remove-codeql: true + remove-docker-images: true + remove-large-packages: true - name: Run tests with Android emulator uses: reactivecircus/android-emulator-runner@v2 From 91d36bcb9b44b7133f5add5b32041daa8f1b132f Mon Sep 17 00:00:00 2001 From: George Kartalis Date: Tue, 6 Jan 2026 13:07:52 +0100 Subject: [PATCH 091/123] free disk space --- .github/workflows/android-e2e-maestro.yml | 29 ++++++++++++--------- .github/workflows/build-maestro-android.yml | 5 +--- .github/workflows/build-maestro-ios.yml | 5 +--- 3 files changed, 19 insertions(+), 20 deletions(-) diff --git a/.github/workflows/android-e2e-maestro.yml b/.github/workflows/android-e2e-maestro.yml index 9e3a6aa8efd..11d113339df 100644 --- a/.github/workflows/android-e2e-maestro.yml +++ b/.github/workflows/android-e2e-maestro.yml @@ -1,15 +1,18 @@ name: Android E2E Tests (Maestro) on: - workflow_run: - workflows: ["Build Android QA App for Maestro"] - types: - - completed + # workflow_run: + # workflows: ["Build Android QA App for Maestro"] + # types: + # - completed workflow_dispatch: # Allows you to trigger the workflow manually from the Actions tab + push: + branches: + - moplat/new-arch-revisited jobs: e2e-tests: - if: ${{ github.event.workflow_run.conclusion == 'success' }} + # if: ${{ github.event.workflow_run.conclusion == 'success' }} runs-on: ubuntu-latest # Use ubuntu-latest for better Android emulator support timeout-minutes: 30 strategy: @@ -65,14 +68,16 @@ jobs: - name: Add Maestro to PATH run: echo "$HOME/.maestro/bin" >> $GITHUB_PATH - - name: Free Disk Space (Ubuntu) - uses: AdityaGarg8/remove-unwanted-software@v5 + - name: Free Disk Space + uses: jlumbroso/free-disk-space@54081f138730dfa15788a46383842cd2f914a1be with: - remove-dotnet: true - remove-haskell: true - remove-codeql: true - remove-docker-images: true - remove-large-packages: true + tool-cache: false + android: false + dotnet: true + haskell: true + large-packages: true + docker-images: true + swap-storage: true - name: Run tests with Android emulator uses: reactivecircus/android-emulator-runner@v2 diff --git a/.github/workflows/build-maestro-android.yml b/.github/workflows/build-maestro-android.yml index 9cd468bee4e..e578cc2f2a5 100644 --- a/.github/workflows/build-maestro-android.yml +++ b/.github/workflows/build-maestro-android.yml @@ -4,13 +4,10 @@ on: schedule: - cron: "0 6 * * *" # Runs daily at 6:00 AM UTC workflow_dispatch: # Allows manual trigger - push: - branches: - - moplat/new-arch-revisited jobs: build-android-qa: - # if: github.ref == 'refs/heads/main' + if: github.ref == 'refs/heads/main' runs-on: ubuntu-latest timeout-minutes: 90 diff --git a/.github/workflows/build-maestro-ios.yml b/.github/workflows/build-maestro-ios.yml index 6a6066ab173..7566282cae6 100644 --- a/.github/workflows/build-maestro-ios.yml +++ b/.github/workflows/build-maestro-ios.yml @@ -4,13 +4,10 @@ on: schedule: - cron: "0 6 * * *" # Runs daily at 6:00 AM UTC workflow_dispatch: # Allows manual trigger - push: - branches: - - moplat/new-arch-revisited jobs: build-ios-qa: - # if: github.ref == 'refs/heads/main' + if: github.ref == 'refs/heads/main' runs-on: macos-15 timeout-minutes: 120 From 462652f9a7528b66f5111aa731cd2f3a0ddbd9bd Mon Sep 17 00:00:00 2001 From: George Kartalis Date: Tue, 6 Jan 2026 13:41:22 +0100 Subject: [PATCH 092/123] retry ios --- .github/workflows/ios-e2e-maestro.yml | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ios-e2e-maestro.yml b/.github/workflows/ios-e2e-maestro.yml index 9e5c043f16c..f03ac5d6d89 100644 --- a/.github/workflows/ios-e2e-maestro.yml +++ b/.github/workflows/ios-e2e-maestro.yml @@ -1,15 +1,18 @@ name: iOS E2E Tests (Maestro) on: - workflow_run: - workflows: ["Build iOS QA App for Maestro"] - types: - - completed + # workflow_run: + # workflows: ["Build iOS QA App for Maestro"] + # types: + # - completed workflow_dispatch: # Allows you to trigger the workflow manually from the Actions tab + push: + branches: + - moplat/new-arch-revisited jobs: e2e-tests: - if: ${{ github.event.workflow_run.conclusion == 'success' }} + # if: ${{ github.event.workflow_run.conclusion == 'success' }} runs-on: macos-15 # iOS simulators require macOS runners timeout-minutes: 45 strategy: From 4f570327d7b3369320cf69c29682dcf8277c7710 Mon Sep 17 00:00:00 2001 From: George Kartalis Date: Tue, 6 Jan 2026 14:29:07 +0100 Subject: [PATCH 093/123] fix dev menu --- src/app/Navigation/routes.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/app/Navigation/routes.tsx b/src/app/Navigation/routes.tsx index e78fcbdc1a7..021b0ca13ad 100644 --- a/src/app/Navigation/routes.tsx +++ b/src/app/Navigation/routes.tsx @@ -826,7 +826,6 @@ export const artsyDotNetRoutes = defineRoutes([ alwaysPresentModally: true, screenOptions: { headerTitle: "Dev Settings", - headerLargeTitle: true, headerLeft: () => { return }, From 58d6314df7fdbbb039bb0961f1e7f30ab40dd84e Mon Sep 17 00:00:00 2001 From: George Kartalis Date: Tue, 6 Jan 2026 14:30:14 +0100 Subject: [PATCH 094/123] revert branch specific e2e run logic --- .github/workflows/android-e2e-maestro.yml | 13 +++++-------- .github/workflows/ios-e2e-maestro.yml | 13 +++++-------- 2 files changed, 10 insertions(+), 16 deletions(-) diff --git a/.github/workflows/android-e2e-maestro.yml b/.github/workflows/android-e2e-maestro.yml index 11d113339df..d1de46324a5 100644 --- a/.github/workflows/android-e2e-maestro.yml +++ b/.github/workflows/android-e2e-maestro.yml @@ -1,18 +1,15 @@ name: Android E2E Tests (Maestro) on: - # workflow_run: - # workflows: ["Build Android QA App for Maestro"] - # types: - # - completed + workflow_run: + workflows: ["Build Android QA App for Maestro"] + types: + - completed workflow_dispatch: # Allows you to trigger the workflow manually from the Actions tab - push: - branches: - - moplat/new-arch-revisited jobs: e2e-tests: - # if: ${{ github.event.workflow_run.conclusion == 'success' }} + if: ${{ github.event.workflow_run.conclusion == 'success' }} runs-on: ubuntu-latest # Use ubuntu-latest for better Android emulator support timeout-minutes: 30 strategy: diff --git a/.github/workflows/ios-e2e-maestro.yml b/.github/workflows/ios-e2e-maestro.yml index f03ac5d6d89..9e5c043f16c 100644 --- a/.github/workflows/ios-e2e-maestro.yml +++ b/.github/workflows/ios-e2e-maestro.yml @@ -1,18 +1,15 @@ name: iOS E2E Tests (Maestro) on: - # workflow_run: - # workflows: ["Build iOS QA App for Maestro"] - # types: - # - completed + workflow_run: + workflows: ["Build iOS QA App for Maestro"] + types: + - completed workflow_dispatch: # Allows you to trigger the workflow manually from the Actions tab - push: - branches: - - moplat/new-arch-revisited jobs: e2e-tests: - # if: ${{ github.event.workflow_run.conclusion == 'success' }} + if: ${{ github.event.workflow_run.conclusion == 'success' }} runs-on: macos-15 # iOS simulators require macOS runners timeout-minutes: 45 strategy: From 0727bb475546ffd484ff52941d7476c900e472d1 Mon Sep 17 00:00:00 2001 From: George Kartalis Date: Tue, 6 Jan 2026 15:09:29 +0100 Subject: [PATCH 095/123] chore: bring back slack alert for beta failures Co-authored-by: Mounir Dhahri --- fastlane/utility_fastlane.rb | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/fastlane/utility_fastlane.rb b/fastlane/utility_fastlane.rb index 94e9e95dc55..4fe5af79c3e 100644 --- a/fastlane/utility_fastlane.rb +++ b/fastlane/utility_fastlane.rb @@ -95,15 +95,15 @@ run_id = ENV['GITHUB_RUN_ID'] github_url = "https://github.com/#{github_repo}/actions/runs/#{run_id}" - # slack( - # message: message, - # success: false, - # payload: { - # 'GitHub Actions' => github_url, - # 'Exception' => exception.message - # }, - # default_payloads: [] - # ) + slack( + message: message, + success: false, + payload: { + 'GitHub Actions' => github_url, + 'Exception' => exception.message + }, + default_payloads: [] + ) end desc "Notifies in slack if a new beta is needed" From 19c6db5d8c3d8643e8cd778b6862696d64ce3c14 Mon Sep 17 00:00:00 2001 From: George Kartalis Date: Tue, 6 Jan 2026 15:20:27 +0100 Subject: [PATCH 096/123] chore: enhance hacks.md adding info about rn patch Co-authored-by: Mounir Dhahri --- HACKS.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/HACKS.md b/HACKS.md index dada013673e..c833499a8b2 100644 --- a/HACKS.md +++ b/HACKS.md @@ -284,7 +284,7 @@ not reset. This causes the module to never start listening again causing events It can be removed once if we stop using the singleton pattern or get rid of ARNotificationsManagerModule, or it is fixed upstream. -## react-native-reanimated package.json flags +## react-native-reanimated package.json flags and react-native patch ### USE_COMMIT_HOOK_ONLY_FOR_REACT_COMMITS @@ -292,6 +292,8 @@ It can be removed once if we stop using the singleton pattern or get rid of ARNo This feature flag was added to fix performance issues with scrolling. See https://docs.swmansion.com/react-native-reanimated/docs/guides/performance/#%EF%B8%8F-lower-fps-while-scrolling +We also added a patch to react-native to support this flag and temporarily enabled preventShadowTreeCommitExhaustion and enableCppPropsIteratorSetter flags to fix performance issues. + #### When can we remove this: When reanimated adopts this by default. From 94a621b1a288528af249d4fe2f8b551f72dfb8c6 Mon Sep 17 00:00:00 2001 From: George Kartalis Date: Tue, 6 Jan 2026 16:38:56 +0100 Subject: [PATCH 097/123] fix: update setSliderPage event type to use NativeSyntheticEvent --- .../Screens/Insights/CareerHighlightsBigCardsSwiper.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/app/Scenes/MyCollection/Screens/Insights/CareerHighlightsBigCardsSwiper.tsx b/src/app/Scenes/MyCollection/Screens/Insights/CareerHighlightsBigCardsSwiper.tsx index c7b91c61973..91dafca2c3c 100644 --- a/src/app/Scenes/MyCollection/Screens/Insights/CareerHighlightsBigCardsSwiper.tsx +++ b/src/app/Scenes/MyCollection/Screens/Insights/CareerHighlightsBigCardsSwiper.tsx @@ -7,8 +7,9 @@ import { useScreenDimensions } from "app/utils/hooks" import { PlaceholderBox, ProvidePlaceholderContext } from "app/utils/placeholders" import { compact } from "lodash" import { Suspense, useState } from "react" -import { Animated } from "react-native" +import { Animated, NativeSyntheticEvent } from "react-native" import PagerView from "react-native-pager-view" +import { OnPageSelectedEventData } from "react-native-pager-view/lib/typescript/PagerViewNativeComponent" import { graphql, useLazyLoadQuery } from "react-relay" import { CareerHighlightBigCardBiennial, @@ -102,7 +103,7 @@ const CareerHighlightsBigCardsSwiperScreen: React.FC { + const setSliderPage = (event: NativeSyntheticEvent) => { const { currentPage } = sliderState const currentSlide = event.nativeEvent.position From bef3a6abbefd64cd60c04e3991a591682080adaa Mon Sep 17 00:00:00 2001 From: George Date: Tue, 6 Jan 2026 16:56:24 +0100 Subject: [PATCH 098/123] Update src/app/Components/WorksForYou/__tests__/Notification.tests.tsx --- src/app/Components/WorksForYou/__tests__/Notification.tests.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/Components/WorksForYou/__tests__/Notification.tests.tsx b/src/app/Components/WorksForYou/__tests__/Notification.tests.tsx index d5341872b63..c45d9c2d8e8 100644 --- a/src/app/Components/WorksForYou/__tests__/Notification.tests.tsx +++ b/src/app/Components/WorksForYou/__tests__/Notification.tests.tsx @@ -31,7 +31,7 @@ describe("Notification", () => { expect(screen.getByText("Jean-Michel Basquiat")).toBeTruthy() }) - it.only("renders without throwing an error if no avatar image exists", () => { + it("renders without throwing an error if no avatar image exists", () => { const props = notification() const convertedProps = { ...props, From 0d0cd31dd906fe6b81acf979f41f35b0de6d3029 Mon Sep 17 00:00:00 2001 From: Mounir Dhahri Date: Wed, 7 Jan 2026 11:06:34 +0100 Subject: [PATCH 099/123] fix: broken android preview card (#13129) fix: broken preview card centering on android --- .../ContextMenu/ContextMenuArtwork.tsx | 44 ++++++++++--------- 1 file changed, 23 insertions(+), 21 deletions(-) diff --git a/src/app/Components/ContextMenu/ContextMenuArtwork.tsx b/src/app/Components/ContextMenu/ContextMenuArtwork.tsx index be74101d414..659bdca4035 100644 --- a/src/app/Components/ContextMenu/ContextMenuArtwork.tsx +++ b/src/app/Components/ContextMenu/ContextMenuArtwork.tsx @@ -269,31 +269,33 @@ export const ContextMenuArtwork: React.FC setAndroidVisible(false)}> - - + + {/* Always show light mode on Android for the bottom sheet */} {artworkPreviewComponent(artwork, { ...artworkDisplayProps, dark: false })} - }> - {contextActions.map((action, index) => { - return ( - { - setAndroidVisible(false) - - action.onPress?.() - }} - > - - {action.title} - - - ) - })} - + + }> + {contextActions.map((action, index) => { + return ( + { + setAndroidVisible(false) + + action.onPress?.() + }} + > + + {action.title} + + + ) + })} + + From 933b7c1493fb55087c66f5d1d7bf600938da72f1 Mon Sep 17 00:00:00 2001 From: Mounir Dhahri Date: Wed, 7 Jan 2026 12:21:12 +0100 Subject: [PATCH 100/123] chore: bring back Tabs.Lazy (#13130) --- .../ArtQuizResultsEmptyTabs.tsx | 8 +++- .../ArtQuizResultsTabs/ArtQuizResultsTabs.tsx | 12 +++-- src/app/Scenes/Artist/Artist.tsx | 46 +++++++++++-------- src/app/Scenes/ArtistSeries/ArtistSeries.tsx | 16 ++++--- src/app/Scenes/Collection/Collection.tsx | 8 +++- src/app/Scenes/Fair/Fair.tsx | 12 +++-- 6 files changed, 66 insertions(+), 36 deletions(-) diff --git a/src/app/Scenes/ArtQuiz/ArtQuizResults/ArtQuizResultsTabs/ArtQuizResultsEmptyTabs.tsx b/src/app/Scenes/ArtQuiz/ArtQuizResults/ArtQuizResultsTabs/ArtQuizResultsEmptyTabs.tsx index 485da1f70e9..70c49202de5 100644 --- a/src/app/Scenes/ArtQuiz/ArtQuizResults/ArtQuizResultsTabs/ArtQuizResultsEmptyTabs.tsx +++ b/src/app/Scenes/ArtQuiz/ArtQuizResults/ArtQuizResultsTabs/ArtQuizResultsEmptyTabs.tsx @@ -28,10 +28,14 @@ export const ArtQuizResultsEmptyTabs = () => { )} > - + + + - + + + ) diff --git a/src/app/Scenes/ArtQuiz/ArtQuizResults/ArtQuizResultsTabs/ArtQuizResultsTabs.tsx b/src/app/Scenes/ArtQuiz/ArtQuizResults/ArtQuizResultsTabs/ArtQuizResultsTabs.tsx index abe24d2f560..06d26c99994 100644 --- a/src/app/Scenes/ArtQuiz/ArtQuizResults/ArtQuizResultsTabs/ArtQuizResultsTabs.tsx +++ b/src/app/Scenes/ArtQuiz/ArtQuizResults/ArtQuizResultsTabs/ArtQuizResultsTabs.tsx @@ -34,13 +34,19 @@ export const ArtQuizResultsTabs = ({ me }: { me: ArtQuizResultsQuery$data["me"] BelowTitleHeaderComponent={() => } > - + + + - + + + - + + + ) diff --git a/src/app/Scenes/Artist/Artist.tsx b/src/app/Scenes/Artist/Artist.tsx index 119e025c636..b0a15b00631 100644 --- a/src/app/Scenes/Artist/Artist.tsx +++ b/src/app/Scenes/Artist/Artist.tsx @@ -116,32 +116,38 @@ export const Artist: React.FC = ({ }} > - + + + - {artistBelowTheFold ? ( - - ) : ( - - )} + + {artistBelowTheFold ? ( + + ) : ( + + )} + - {artistBelowTheFold ? ( - - ) : ( - - )} + + {artistBelowTheFold ? ( + + ) : ( + + )} + diff --git a/src/app/Scenes/ArtistSeries/ArtistSeries.tsx b/src/app/Scenes/ArtistSeries/ArtistSeries.tsx index 6d3a67a4711..d9691c8cf7c 100644 --- a/src/app/Scenes/ArtistSeries/ArtistSeries.tsx +++ b/src/app/Scenes/ArtistSeries/ArtistSeries.tsx @@ -53,14 +53,18 @@ export const ArtistSeries: React.FC = (props) => { }} > - }> - - + + }> + + + - - - + + + + + diff --git a/src/app/Scenes/Collection/Collection.tsx b/src/app/Scenes/Collection/Collection.tsx index 060b859d81a..92d7e4a5762 100644 --- a/src/app/Scenes/Collection/Collection.tsx +++ b/src/app/Scenes/Collection/Collection.tsx @@ -103,11 +103,15 @@ export const CollectionContent: React.FC = ({ collection }) => }} > - + + + {!!shouldRenderOverviewTab ? ( - + + + ) : null} diff --git a/src/app/Scenes/Fair/Fair.tsx b/src/app/Scenes/Fair/Fair.tsx index a8500527b32..bc4d2b4591d 100644 --- a/src/app/Scenes/Fair/Fair.tsx +++ b/src/app/Scenes/Fair/Fair.tsx @@ -129,17 +129,23 @@ export const Fair: React.FC = ({ fair }) => { }} > - + + + {!!hasExhibitors ? ( - + + + ) : null} - + + + From 5a09f741c570e62d61db058b1dc3b9a81e41bb37 Mon Sep 17 00:00:00 2001 From: Mounir Dhahri Date: Wed, 7 Jan 2026 15:40:06 +0100 Subject: [PATCH 101/123] chore: reset watchman --- scripts/utils/clean | 3 +++ scripts/utils/cleaninstall.sh | 3 +++ 2 files changed, 6 insertions(+) diff --git a/scripts/utils/clean b/scripts/utils/clean index 10806960c30..aebe6257504 100755 --- a/scripts/utils/clean +++ b/scripts/utils/clean @@ -28,6 +28,9 @@ fi echo 'Clear node modules (┛ಠ_ಠ)┛彡┻━┻' rm -rf node_modules +echo "Reset watchman (ノಠ益ಠ)ノ彡┻━┻" +watchman watch-del . + echo "Clear caches (linting and metro) (┛◉Д◉)┛彡┻━┻" rm -rf .cache rm -rf "${TMPDIR%/}"/metro-* diff --git a/scripts/utils/cleaninstall.sh b/scripts/utils/cleaninstall.sh index 782fd4739e7..f98571464da 100755 --- a/scripts/utils/cleaninstall.sh +++ b/scripts/utils/cleaninstall.sh @@ -23,6 +23,9 @@ echo "Clear caches (linting and metro) (┛◉Д◉)┛彡┻━┻" rm -rf .cache rm -rf "$TMPDIR/metro*" +echo "Reset watchman (ノಠ益ಠ)ノ彡┻━┻" +watchman watch-del . + echo "Clear hastemap (╯ರ ~ ರ)╯︵ ┻━┻" rm -rf "$TMPDIR/haste-map-*" From 789d7d770293fc8f1c626fdef720a6ae5fa68930 Mon Sep 17 00:00:00 2001 From: Mounir Dhahri Date: Mon, 12 Jan 2026 15:49:54 +0100 Subject: [PATCH 102/123] chore: add iterationCount on performance tests --- e2e/README.md | 16 +++++++++++++--- e2e/perf/run-perf-tests.sh | 3 ++- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/e2e/README.md b/e2e/README.md index 067681cad14..d5c0b69f99d 100644 --- a/e2e/README.md +++ b/e2e/README.md @@ -6,9 +6,19 @@ It is used like other tools such as Cypress, Appium, and Detox in order to run t ## Steps to run 1. install maestro by following the instructions [here](https://maestro.mobile.dev/getting-started/installing-maestro) - - `curl -Ls "https://get.maestro.mobile.dev" | bash` - - `brew tap facebook/fb` - - `brew install facebook/fb/idb-companion` + + - Using Curl + + ```bash + curl -Ls "https://get.maestro.mobile.dev" | bash + ``` + + - Using Homebrew + + ```bash + brew tap facebook/fb + brew install facebook/fb/idb-companion + ``` ### iOS diff --git a/e2e/perf/run-perf-tests.sh b/e2e/perf/run-perf-tests.sh index 6ed9495d69f..52389f6fc95 100755 --- a/e2e/perf/run-perf-tests.sh +++ b/e2e/perf/run-perf-tests.sh @@ -16,8 +16,9 @@ timestamp=$(date +"%Y-%m-%d_%H:%M:%S") # Note that this is only supported on android devices or emulators at the moment. flashlight test --bundleId net.artsy.app \ --testCommand "maestro test e2e/perf/perf-test-home.yml" \ + --beforeEachCommand "adb shell am force-stop net.artsy.app" \ --duration 10000 \ - --iterationCount 1 \ + --iterationCount 3 \ --skipRestart \ --record \ --resultsFilePath "flashlight_results_$timestamp.json" \ From e1b77d63dd659ac8cd8cfd778d635d405a102d3b Mon Sep 17 00:00:00 2001 From: Mounir Dhahri Date: Mon, 12 Jan 2026 18:10:47 +0100 Subject: [PATCH 103/123] chore: use default flatlist --- src/app/Components/CardRail/CardRailFlatList.tsx | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/app/Components/CardRail/CardRailFlatList.tsx b/src/app/Components/CardRail/CardRailFlatList.tsx index 2293626da58..f2c06975cb9 100644 --- a/src/app/Components/CardRail/CardRailFlatList.tsx +++ b/src/app/Components/CardRail/CardRailFlatList.tsx @@ -8,15 +8,12 @@ import { Spacer, useSpace, } from "@artsy/palette-mobile" -import { - AboveTheFoldFlatList, - AboveTheFoldFlatListProps, -} from "app/Components/AboveTheFoldFlatList" +import { AboveTheFoldFlatListProps } from "app/Components/AboveTheFoldFlatList" import { CardRailCard, CardRailMetadataContainer } from "app/Components/CardRail/CardRailCard" import { LARGE_IMAGE_SIZE, SMALL_IMAGE_SIZE } from "app/Components/MultipleImageLayout" import Spinner from "app/Components/Spinner" import { Ref } from "react" -import { FlatListProps, View } from "react-native" +import { FlatList, FlatListProps, View } from "react-native" type CardRailFlatList = AboveTheFoldFlatListProps @@ -27,7 +24,7 @@ export function CardRailFlatList( const space = useSpace() return ( - + ListHeaderComponent={() => } ListFooterComponent={() => } ItemSeparatorComponent={() => } From 02ab5933be30ce79f423dcc167038e983bdb1f0e Mon Sep 17 00:00:00 2001 From: Mounir Dhahri Date: Mon, 12 Jan 2026 18:11:02 +0100 Subject: [PATCH 104/123] chore: disable save animation --- .../ArtworkGrids/ArtworkSaveIconWrapper.tsx | 45 ++----------------- 1 file changed, 3 insertions(+), 42 deletions(-) diff --git a/src/app/Components/ArtworkGrids/ArtworkSaveIconWrapper.tsx b/src/app/Components/ArtworkGrids/ArtworkSaveIconWrapper.tsx index ff34ca0d722..6576b332269 100644 --- a/src/app/Components/ArtworkGrids/ArtworkSaveIconWrapper.tsx +++ b/src/app/Components/ArtworkGrids/ArtworkSaveIconWrapper.tsx @@ -1,7 +1,6 @@ import { HeartFillIcon, HeartStrokeIcon } from "@artsy/icons/native" import { HEART_ICON_SIZE } from "app/Components/constants" -import { useEffect, useRef } from "react" -import { Animated, useAnimatedValue } from "react-native" +import { View } from "react-native" interface ArtworkSaveIconWrapperProps { isSaved: boolean @@ -16,46 +15,8 @@ export const ArtworkSaveIconWrapper: React.FC = ({ accessibilityLabel, fill, }) => { - const scaleAnimation = useAnimatedValue(1) - const didMount = useRef(false) - - useEffect(() => { - if (!didMount.current) { - didMount.current = true - return - } - - if (isSaved) { - Animated.sequence([ - Animated.spring(scaleAnimation, { - toValue: 0.7, - mass: 0.01, - stiffness: 300, - useNativeDriver: true, - }), - Animated.timing(scaleAnimation, { - toValue: 1.1, - duration: 300, - useNativeDriver: true, - }), - Animated.timing(scaleAnimation, { - toValue: 1, - duration: 200, - useNativeDriver: true, - }), - ]).start() - } else { - // We don't want to animation the dislike - scaleAnimation.setValue(1) - } - }, [isSaved, scaleAnimation]) - return ( - + {!!isSaved ? ( = ({ testID="empty-heart-icon" /> )} - + ) } From 1eb5effd9fcb7533f0a70e9cc7032ac2fb0bafee Mon Sep 17 00:00:00 2001 From: Mounir Dhahri Date: Mon, 12 Jan 2026 18:35:26 +0100 Subject: [PATCH 105/123] chore: artist nav header broken animation on android --- .../Artist/ArtistHeaderNavRight.tsx | 123 +---------------- ...eaderNavRightFragmentContainer.android.tsx | 100 ++++++++++++++ ...istHeaderNavRightFragmentContainer.ios.tsx | 127 ++++++++++++++++++ 3 files changed, 233 insertions(+), 117 deletions(-) create mode 100644 src/app/Components/Artist/ArtistHeaderNavRightFragmentContainer.android.tsx create mode 100644 src/app/Components/Artist/ArtistHeaderNavRightFragmentContainer.ios.tsx diff --git a/src/app/Components/Artist/ArtistHeaderNavRight.tsx b/src/app/Components/Artist/ArtistHeaderNavRight.tsx index 547171a0d5d..cc52602de30 100644 --- a/src/app/Components/Artist/ArtistHeaderNavRight.tsx +++ b/src/app/Components/Artist/ArtistHeaderNavRight.tsx @@ -1,133 +1,22 @@ -import { ShareIcon } from "@artsy/icons/native" -import { Flex, FollowButton, NAVBAR_HEIGHT, useSpace } from "@artsy/palette-mobile" -import { useScreenScrollContext } from "@artsy/palette-mobile/dist/elements/Screen/ScreenScrollContext" +import { Flex } from "@artsy/palette-mobile" import { ArtistHeaderNavRightQuery } from "__generated__/ArtistHeaderNavRightQuery.graphql" import { ArtistHeaderNavRight_artist$key } from "__generated__/ArtistHeaderNavRight_artist.graphql" -import { useFollowArtist } from "app/Components/Artist/useFollowArtist" -import { useShareSheet } from "app/Components/ShareSheet/ShareSheetContext" -import { ACCESSIBLE_DEFAULT_ICON_SIZE } from "app/Components/constants" +// @ts-ignore +import { ArtistHeaderNavRight as ArtistHeaderNavRightFragmentContainer } from "app/Components/Artist/ArtistHeaderNavRightFragmentContainer" import { NoFallback, withSuspense } from "app/utils/hooks/withSuspense" -import { MotiView } from "moti" -import { useCallback, useState } from "react" -import { PixelRatio, TouchableOpacity } from "react-native" -import { Easing, useAnimatedStyle, useDerivedValue, withTiming } from "react-native-reanimated" -import { graphql, useFragment, useLazyLoadQuery } from "react-relay" -import useDebounce from "react-use/lib/useDebounce" +import { graphql, useLazyLoadQuery } from "react-relay" interface ArtistHeaderNavRightProps { artist: ArtistHeaderNavRight_artist$key } -const CONTAINER_WIDTH = 185 * PixelRatio.getFontScale() - export const ArtistHeaderNavRight: React.FC = ({ artist: artistProp, }) => { - const space = useSpace() - const { currentScrollYAnimated, scrollYOffset } = useScreenScrollContext() - const artist = useFragment(fragment, artistProp) - const [isFollowed, setIsFollowed] = useState(!!artist?.isFollowed) - - const { showShareSheet } = useShareSheet() - const { handleFollowToggle } = useFollowArtist(artist) - - // The container width minus the share icon width minus the padding on the left and right - const followButtonWidth = CONTAINER_WIDTH - ACCESSIBLE_DEFAULT_ICON_SIZE - space(2) - - useDebounce( - () => { - if (isFollowed !== artist?.isFollowed) { - handleFollowToggle() - } - }, - 350, - [isFollowed] - ) - - const followAreaDeltaX = (followButtonWidth + space(2)) * PixelRatio.getFontScale() - const displayFollowButton = useDerivedValue(() => { - return !scrollYOffset || currentScrollYAnimated.value < scrollYOffset + NAVBAR_HEIGHT - }) - - // convert the space into primitive types to be user on the UI thread - const space2 = space(2) - - const followButtonTranslateX = useDerivedValue(() => - displayFollowButton.value ? 0 : followAreaDeltaX - ) - - const followButtonOpacity = useDerivedValue(() => (displayFollowButton.value ? 1 : 0)) - - const viewStyle = useAnimatedStyle( - () => ({ - transform: [ - { - translateX: withTiming( - followButtonTranslateX.value - (displayFollowButton.value ? 0 : space2), - { - duration: 200, - easing: Easing.sin, - } - ), - }, - ], - }), - [followAreaDeltaX] - ) - - const followButtonStyle = useAnimatedStyle(() => ({ - opacity: withTiming(followButtonOpacity.value, { duration: 200 }), - })) - - const handleSharePress = useCallback(() => { - if (artist?.name && artist?.name && artist?.slug && artist?.href) { - showShareSheet({ - type: "artist", - internalID: artist.internalID, - slug: artist.slug, - artists: [{ name: artist.name ?? null }], - title: artist.name, - href: artist.href, - currentImageUrl: artist.shareImage?.image?.url ?? undefined, - }) - } - }, [artist, showShareSheet]) - - return ( - - - - - - - - setIsFollowed(!isFollowed)} - // Using maxWidth and minWidth to prevent the button from changing width when the text changes - maxWidth={followButtonWidth} - minWidth={followButtonWidth} - /> - - - - ) + return } -const fragment = graphql` +export const artistHeaderNavRightFragment = graphql` fragment ArtistHeaderNavRight_artist on Artist { isFollowed counts @required(action: NONE) { diff --git a/src/app/Components/Artist/ArtistHeaderNavRightFragmentContainer.android.tsx b/src/app/Components/Artist/ArtistHeaderNavRightFragmentContainer.android.tsx new file mode 100644 index 00000000000..345567038c3 --- /dev/null +++ b/src/app/Components/Artist/ArtistHeaderNavRightFragmentContainer.android.tsx @@ -0,0 +1,100 @@ +import { ShareIcon } from "@artsy/icons/native" +import { Flex, FollowButton, NAVBAR_HEIGHT, useSpace } from "@artsy/palette-mobile" +import { useScreenScrollContext } from "@artsy/palette-mobile/dist/elements/Screen/ScreenScrollContext" +import { ArtistHeaderNavRight_artist$key } from "__generated__/ArtistHeaderNavRight_artist.graphql" +import { artistHeaderNavRightFragment } from "app/Components/Artist/ArtistHeaderNavRight" +import { useFollowArtist } from "app/Components/Artist/useFollowArtist" +import { useShareSheet } from "app/Components/ShareSheet/ShareSheetContext" +import { ACCESSIBLE_DEFAULT_ICON_SIZE } from "app/Components/constants" +import { useCallback, useState } from "react" +import { PixelRatio, TouchableOpacity } from "react-native" +import { runOnJS, useAnimatedReaction } from "react-native-reanimated" +import { useFragment } from "react-relay" +import useDebounce from "react-use/lib/useDebounce" + +interface ArtistHeaderNavRightProps { + artist: ArtistHeaderNavRight_artist$key +} + +const CONTAINER_WIDTH = 185 * PixelRatio.getFontScale() + +export const ArtistHeaderNavRight: React.FC = ({ + artist: artistProp, +}) => { + const space = useSpace() + const { currentScrollYAnimated, scrollYOffset } = useScreenScrollContext() + const artist = useFragment(artistHeaderNavRightFragment, artistProp) + const [isFollowed, setIsFollowed] = useState(!!artist?.isFollowed) + const [showFollowButton, setShowFollowButton] = useState(true) + + const { showShareSheet } = useShareSheet() + const { handleFollowToggle } = useFollowArtist(artist) + + useAnimatedReaction( + () => { + return !scrollYOffset || currentScrollYAnimated.value + 50 < scrollYOffset + NAVBAR_HEIGHT + }, + (shouldShow) => { + runOnJS(setShowFollowButton)(shouldShow) + }, + [scrollYOffset] + ) + + // The container width minus the share icon width minus the padding on the left and right + const followButtonWidth = CONTAINER_WIDTH - ACCESSIBLE_DEFAULT_ICON_SIZE - space(2) + + useDebounce( + () => { + if (isFollowed !== artist?.isFollowed) { + handleFollowToggle() + } + }, + 350, + [isFollowed] + ) + + const handleSharePress = useCallback(() => { + if (artist?.name && artist?.name && artist?.slug && artist?.href) { + showShareSheet({ + type: "artist", + internalID: artist.internalID, + slug: artist.slug, + artists: [{ name: artist.name ?? null }], + title: artist.name, + href: artist.href, + currentImageUrl: artist.shareImage?.image?.url ?? undefined, + }) + } + }, [artist, showShareSheet]) + + return ( + + + + + + {showFollowButton ? ( + setIsFollowed(!isFollowed)} + // Using maxWidth and minWidth to prevent the button from changing width when the text changes + maxWidth={followButtonWidth} + minWidth={followButtonWidth} + /> + ) : null} + + ) +} diff --git a/src/app/Components/Artist/ArtistHeaderNavRightFragmentContainer.ios.tsx b/src/app/Components/Artist/ArtistHeaderNavRightFragmentContainer.ios.tsx new file mode 100644 index 00000000000..3d2adf8ea51 --- /dev/null +++ b/src/app/Components/Artist/ArtistHeaderNavRightFragmentContainer.ios.tsx @@ -0,0 +1,127 @@ +import { ShareIcon } from "@artsy/icons/native" +import { Flex, FollowButton, NAVBAR_HEIGHT, useSpace } from "@artsy/palette-mobile" +import { useScreenScrollContext } from "@artsy/palette-mobile/dist/elements/Screen/ScreenScrollContext" +import { ArtistHeaderNavRight_artist$key } from "__generated__/ArtistHeaderNavRight_artist.graphql" +import { artistHeaderNavRightFragment } from "app/Components/Artist/ArtistHeaderNavRight" +import { useFollowArtist } from "app/Components/Artist/useFollowArtist" +import { useShareSheet } from "app/Components/ShareSheet/ShareSheetContext" +import { ACCESSIBLE_DEFAULT_ICON_SIZE } from "app/Components/constants" +import { MotiView } from "moti" +import { useCallback, useState } from "react" +import { PixelRatio, TouchableOpacity } from "react-native" +import { Easing, useAnimatedStyle, useDerivedValue, withTiming } from "react-native-reanimated" +import { useFragment } from "react-relay" +import useDebounce from "react-use/lib/useDebounce" + +interface ArtistHeaderNavRightProps { + artist: ArtistHeaderNavRight_artist$key +} + +const CONTAINER_WIDTH = 185 * PixelRatio.getFontScale() + +export const ArtistHeaderNavRight: React.FC = ({ + artist: artistProp, +}) => { + const space = useSpace() + const { currentScrollYAnimated, scrollYOffset } = useScreenScrollContext() + const artist = useFragment(artistHeaderNavRightFragment, artistProp) + const [isFollowed, setIsFollowed] = useState(!!artist?.isFollowed) + + const { showShareSheet } = useShareSheet() + const { handleFollowToggle } = useFollowArtist(artist) + + // The container width minus the share icon width minus the padding on the left and right + const followButtonWidth = CONTAINER_WIDTH - ACCESSIBLE_DEFAULT_ICON_SIZE - space(2) + + useDebounce( + () => { + if (isFollowed !== artist?.isFollowed) { + handleFollowToggle() + } + }, + 350, + [isFollowed] + ) + + const followAreaDeltaX = (followButtonWidth + space(2)) * PixelRatio.getFontScale() + const displayFollowButton = useDerivedValue(() => { + return !scrollYOffset || currentScrollYAnimated.value < scrollYOffset + NAVBAR_HEIGHT + }) + + // convert the space into primitive types to be user on the UI thread + const space2 = space(2) + + const followButtonTranslateX = useDerivedValue(() => + displayFollowButton.value ? 0 : followAreaDeltaX + ) + + const followButtonOpacity = useDerivedValue(() => (displayFollowButton.value ? 1 : 0)) + + const viewStyle = useAnimatedStyle( + () => ({ + transform: [ + { + translateX: withTiming( + followButtonTranslateX.value - (displayFollowButton.value ? 0 : space2), + { + duration: 200, + easing: Easing.sin, + } + ), + }, + ], + }), + [followAreaDeltaX] + ) + + const followButtonStyle = useAnimatedStyle(() => ({ + opacity: withTiming(followButtonOpacity.value, { duration: 200 }), + })) + + const handleSharePress = useCallback(() => { + if (artist?.name && artist?.name && artist?.slug && artist?.href) { + showShareSheet({ + type: "artist", + internalID: artist.internalID, + slug: artist.slug, + artists: [{ name: artist.name ?? null }], + title: artist.name, + href: artist.href, + currentImageUrl: artist.shareImage?.image?.url ?? undefined, + }) + } + }, [artist, showShareSheet]) + + return ( + + + + + + + + setIsFollowed(!isFollowed)} + // Using maxWidth and minWidth to prevent the button from changing width when the text changes + maxWidth={followButtonWidth} + minWidth={followButtonWidth} + /> + + + + ) +} From 18acbd24b58c9dc3e6924ae88fadedf8d3682965 Mon Sep 17 00:00:00 2001 From: Mounir Dhahri Date: Tue, 13 Jan 2026 11:49:51 +0100 Subject: [PATCH 106/123] chore: remove ANDROID_SYNCHRONOUSLY_UPDATE_UI_PROPS --- package.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/package.json b/package.json index d570d707dac..e5849c5c9e8 100644 --- a/package.json +++ b/package.json @@ -363,8 +363,7 @@ "staticFeatureFlags": { "USE_COMMIT_HOOK_ONLY_FOR_REACT_COMMITS": true, "DISABLE_COMMIT_PAUSING_MECHANISM": true, - "IOS_SYNCHRONOUSLY_UPDATE_UI_PROPS": true, - "ANDROID_SYNCHRONOUSLY_UPDATE_UI_PROPS": true + "IOS_SYNCHRONOUSLY_UPDATE_UI_PROPS": true } }, "packageManager": "yarn@4.10.3" From 857c4fe7472cfb25de148ded1244683473d9e560 Mon Sep 17 00:00:00 2001 From: Mounir Dhahri Date: Tue, 13 Jan 2026 13:46:44 +0100 Subject: [PATCH 107/123] chore: remove IOS_SYNCHRONOUSLY_UPDATE_UI_PROPS --- package.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/package.json b/package.json index e5849c5c9e8..e8dc8edb609 100644 --- a/package.json +++ b/package.json @@ -362,8 +362,7 @@ "reanimated": { "staticFeatureFlags": { "USE_COMMIT_HOOK_ONLY_FOR_REACT_COMMITS": true, - "DISABLE_COMMIT_PAUSING_MECHANISM": true, - "IOS_SYNCHRONOUSLY_UPDATE_UI_PROPS": true + "DISABLE_COMMIT_PAUSING_MECHANISM": true } }, "packageManager": "yarn@4.10.3" From 918d89a9589d6786157835db9c1a7e6dbe3956ef Mon Sep 17 00:00:00 2001 From: Mounir Dhahri Date: Tue, 13 Jan 2026 14:04:00 +0100 Subject: [PATCH 108/123] chore(experimental): remove all flags --- ios/Podfile.lock | 2 +- package.json | 6 ----- patches/react-native+0.81.5.patch | 26 ++----------------- .../Artist/ArtistInsights/ArtistInsights.tsx | 1 + 4 files changed, 4 insertions(+), 31 deletions(-) diff --git a/ios/Podfile.lock b/ios/Podfile.lock index a539fa41ba8..bbb1fac452a 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -4726,7 +4726,7 @@ SPEC CHECKSUMS: RNNotifee: 5e3b271e8ea7456a36eec994085543c9adca9168 RNPermissions: 663a639fdc5aa46b853f514ae8a86dd4deb160cb RNReactNativeHapticFeedback: 7601768ee65ffc86fc93d7c30dd917031144ed3d - RNReanimated: ceb81fcfe01e98bff4193366893e4e341de500a5 + RNReanimated: 142b5513b136714ea7abef65b46e04c12ce7194e RNScreens: 0bbf16c074ae6bb1058a7bf2d1ae017f4306797c RNSentry: ab7ba8bd678713c94762d2d3f2087d47105b6cf3 RNShare: 1dba46787d6e5543e05655efaefa0e4bb98380d9 diff --git a/package.json b/package.json index e8dc8edb609..2f4c4e98aab 100644 --- a/package.json +++ b/package.json @@ -359,11 +359,5 @@ "yarn prettier-write" ] }, - "reanimated": { - "staticFeatureFlags": { - "USE_COMMIT_HOOK_ONLY_FOR_REACT_COMMITS": true, - "DISABLE_COMMIT_PAUSING_MECHANISM": true - } - }, "packageManager": "yarn@4.10.3" } diff --git a/patches/react-native+0.81.5.patch b/patches/react-native+0.81.5.patch index d524d9f00cf..7f406048816 100644 --- a/patches/react-native+0.81.5.patch +++ b/patches/react-native+0.81.5.patch @@ -3,7 +3,7 @@ index 6cdec32..8f7cf70 100644 --- a/node_modules/react-native/React/Modules/RCTEventEmitter.m +++ b/node_modules/react-native/React/Modules/RCTEventEmitter.m @@ -89,6 +89,10 @@ - + if (_listenerCount > 0) { [self stopObserving]; + // Reset listener count to allow proper re-initialization on bridge reload @@ -12,26 +12,4 @@ index 6cdec32..8f7cf70 100644 + _listenerCount = 0; } } - -diff --git a/node_modules/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDefaults.h b/node_modules/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDefaults.h -index e0742c9..77fab8b 100644 ---- a/node_modules/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDefaults.h -+++ b/node_modules/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDefaults.h -@@ -72,7 +72,7 @@ class ReactNativeFeatureFlagsDefaults : public ReactNativeFeatureFlagsProvider { - } - - bool enableCppPropsIteratorSetter() override { -- return false; -+ return true; - } - - bool enableCustomFocusSearchOnClippedElementsAndroid() override { -@@ -216,7 +216,7 @@ class ReactNativeFeatureFlagsDefaults : public ReactNativeFeatureFlagsProvider { - } - - bool preventShadowTreeCommitExhaustion() override { -- return false; -+ return true; - } - - bool traceTurboModulePromiseRejectionsOnAndroid() override { + diff --git a/src/app/Components/Artist/ArtistInsights/ArtistInsights.tsx b/src/app/Components/Artist/ArtistInsights/ArtistInsights.tsx index 13278b1493b..be8f6494993 100644 --- a/src/app/Components/Artist/ArtistInsights/ArtistInsights.tsx +++ b/src/app/Components/Artist/ArtistInsights/ArtistInsights.tsx @@ -110,6 +110,7 @@ export const ArtistInsights: React.FC = (props) => { data={components} keyExtractor={(_, index) => `ArtistInsight-FlatList-element-${index}`} renderItem={({ item: { Component } }) => } + // scrollEventThrottle={0.000001} /> Date: Tue, 13 Jan 2026 17:04:35 +0100 Subject: [PATCH 109/123] chore(experiment): fix android artist header --- .../main/java/net/artsy/app/MainApplication.kt | 4 +++- android/gradle.properties | 5 ++++- ios/Podfile.lock | 2 +- package.json | 5 +++++ patches/react-native+0.81.5.patch | 17 +++++++++++++++-- 5 files changed, 28 insertions(+), 5 deletions(-) diff --git a/android/app/src/main/java/net/artsy/app/MainApplication.kt b/android/app/src/main/java/net/artsy/app/MainApplication.kt index 2a805374669..8b41387c7b9 100644 --- a/android/app/src/main/java/net/artsy/app/MainApplication.kt +++ b/android/app/src/main/java/net/artsy/app/MainApplication.kt @@ -48,9 +48,11 @@ class MainApplication : Application(), ReactApplication { override fun onCreate() { super.onCreate() + DefaultNewArchitectureEntryPoint.releaseLevel = ReleaseLevel.EXPERIMENTAL try { - DefaultNewArchitectureEntryPoint.releaseLevel = ReleaseLevel.valueOf(BuildConfig.REACT_NATIVE_RELEASE_LEVEL.uppercase()) + DefaultNewArchitectureEntryPoint.releaseLevel = ReleaseLevel.EXPERIMENTAL + // DefaultNewArchitectureEntryPoint.releaseLevel = ReleaseLevel.valueOf(BuildConfig.REACT_NATIVE_RELEASE_LEVEL.uppercase()) } catch (e: IllegalArgumentException) { DefaultNewArchitectureEntryPoint.releaseLevel = ReleaseLevel.STABLE } diff --git a/android/gradle.properties b/android/gradle.properties index 2d71ca5ec72..2147181f0cd 100644 --- a/android/gradle.properties +++ b/android/gradle.properties @@ -50,4 +50,7 @@ newArchEnabled=true hermesEnabled=true # Specify dotenv file name for access in build.gradle -dotenv.filename=../.env.shared \ No newline at end of file +dotenv.filename=../.env.shared + +# We are enabling this to fix scroll performance issues on Android +reactNativeReleaseLevel=experimental diff --git a/ios/Podfile.lock b/ios/Podfile.lock index bbb1fac452a..cb8571c802c 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -4726,7 +4726,7 @@ SPEC CHECKSUMS: RNNotifee: 5e3b271e8ea7456a36eec994085543c9adca9168 RNPermissions: 663a639fdc5aa46b853f514ae8a86dd4deb160cb RNReactNativeHapticFeedback: 7601768ee65ffc86fc93d7c30dd917031144ed3d - RNReanimated: 142b5513b136714ea7abef65b46e04c12ce7194e + RNReanimated: 4375bbe48a18fbe20aefef133770ae33b22fb386 RNScreens: 0bbf16c074ae6bb1058a7bf2d1ae017f4306797c RNSentry: ab7ba8bd678713c94762d2d3f2087d47105b6cf3 RNShare: 1dba46787d6e5543e05655efaefa0e4bb98380d9 diff --git a/package.json b/package.json index 2f4c4e98aab..522954dcde1 100644 --- a/package.json +++ b/package.json @@ -359,5 +359,10 @@ "yarn prettier-write" ] }, + "reanimated": { + "staticFeatureFlags": { + "DISABLE_COMMIT_PAUSING_MECHANISM": true + } + }, "packageManager": "yarn@4.10.3" } diff --git a/patches/react-native+0.81.5.patch b/patches/react-native+0.81.5.patch index 7f406048816..c60236942fc 100644 --- a/patches/react-native+0.81.5.patch +++ b/patches/react-native+0.81.5.patch @@ -3,7 +3,7 @@ index 6cdec32..8f7cf70 100644 --- a/node_modules/react-native/React/Modules/RCTEventEmitter.m +++ b/node_modules/react-native/React/Modules/RCTEventEmitter.m @@ -89,6 +89,10 @@ - + if (_listenerCount > 0) { [self stopObserving]; + // Reset listener count to allow proper re-initialization on bridge reload @@ -12,4 +12,17 @@ index 6cdec32..8f7cf70 100644 + _listenerCount = 0; } } - + +diff --git a/node_modules/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDefaults.h b/node_modules/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDefaults.h +index e0742c9..a5cd8cf 100644 +--- a/node_modules/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDefaults.h ++++ b/node_modules/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDefaults.h +@@ -216,7 +216,7 @@ class ReactNativeFeatureFlagsDefaults : public ReactNativeFeatureFlagsProvider { + } + + bool preventShadowTreeCommitExhaustion() override { +- return false; ++ return true; + } + + bool traceTurboModulePromiseRejectionsOnAndroid() override { From 8a8495a16a3253e03c43fc69c8137b63e3927fda Mon Sep 17 00:00:00 2001 From: Mounir Dhahri Date: Tue, 13 Jan 2026 17:28:04 +0100 Subject: [PATCH 110/123] fix: remove .only from test --- src/app/Components/WorksForYou/__tests__/Notification.tests.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/Components/WorksForYou/__tests__/Notification.tests.tsx b/src/app/Components/WorksForYou/__tests__/Notification.tests.tsx index c45d9c2d8e8..37e28892248 100644 --- a/src/app/Components/WorksForYou/__tests__/Notification.tests.tsx +++ b/src/app/Components/WorksForYou/__tests__/Notification.tests.tsx @@ -23,7 +23,7 @@ describe("Notification", () => { } `, }) - it.only("renders notification properly", () => { + it("renders notification properly", () => { renderWithRelay({ FollowedArtistsArtworksGroup: () => notification(), }) From d2a7fd167a936df6e0b6d47f59cf44e0f879bf96 Mon Sep 17 00:00:00 2001 From: Mounir Dhahri Date: Wed, 14 Jan 2026 09:39:21 +0100 Subject: [PATCH 111/123] chore: revert all previous changes --- .../main/java/net/artsy/app/MainApplication.kt | 4 +--- android/gradle.properties | 2 -- ios/Podfile.lock | 2 +- package.json | 5 ----- patches/react-native+0.81.5.patch | 17 ++--------------- 5 files changed, 4 insertions(+), 26 deletions(-) diff --git a/android/app/src/main/java/net/artsy/app/MainApplication.kt b/android/app/src/main/java/net/artsy/app/MainApplication.kt index 8b41387c7b9..2a805374669 100644 --- a/android/app/src/main/java/net/artsy/app/MainApplication.kt +++ b/android/app/src/main/java/net/artsy/app/MainApplication.kt @@ -48,11 +48,9 @@ class MainApplication : Application(), ReactApplication { override fun onCreate() { super.onCreate() - DefaultNewArchitectureEntryPoint.releaseLevel = ReleaseLevel.EXPERIMENTAL try { - DefaultNewArchitectureEntryPoint.releaseLevel = ReleaseLevel.EXPERIMENTAL - // DefaultNewArchitectureEntryPoint.releaseLevel = ReleaseLevel.valueOf(BuildConfig.REACT_NATIVE_RELEASE_LEVEL.uppercase()) + DefaultNewArchitectureEntryPoint.releaseLevel = ReleaseLevel.valueOf(BuildConfig.REACT_NATIVE_RELEASE_LEVEL.uppercase()) } catch (e: IllegalArgumentException) { DefaultNewArchitectureEntryPoint.releaseLevel = ReleaseLevel.STABLE } diff --git a/android/gradle.properties b/android/gradle.properties index 2147181f0cd..46d55964774 100644 --- a/android/gradle.properties +++ b/android/gradle.properties @@ -52,5 +52,3 @@ hermesEnabled=true # Specify dotenv file name for access in build.gradle dotenv.filename=../.env.shared -# We are enabling this to fix scroll performance issues on Android -reactNativeReleaseLevel=experimental diff --git a/ios/Podfile.lock b/ios/Podfile.lock index cb8571c802c..bbb1fac452a 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -4726,7 +4726,7 @@ SPEC CHECKSUMS: RNNotifee: 5e3b271e8ea7456a36eec994085543c9adca9168 RNPermissions: 663a639fdc5aa46b853f514ae8a86dd4deb160cb RNReactNativeHapticFeedback: 7601768ee65ffc86fc93d7c30dd917031144ed3d - RNReanimated: 4375bbe48a18fbe20aefef133770ae33b22fb386 + RNReanimated: 142b5513b136714ea7abef65b46e04c12ce7194e RNScreens: 0bbf16c074ae6bb1058a7bf2d1ae017f4306797c RNSentry: ab7ba8bd678713c94762d2d3f2087d47105b6cf3 RNShare: 1dba46787d6e5543e05655efaefa0e4bb98380d9 diff --git a/package.json b/package.json index 522954dcde1..2f4c4e98aab 100644 --- a/package.json +++ b/package.json @@ -359,10 +359,5 @@ "yarn prettier-write" ] }, - "reanimated": { - "staticFeatureFlags": { - "DISABLE_COMMIT_PAUSING_MECHANISM": true - } - }, "packageManager": "yarn@4.10.3" } diff --git a/patches/react-native+0.81.5.patch b/patches/react-native+0.81.5.patch index c60236942fc..7f406048816 100644 --- a/patches/react-native+0.81.5.patch +++ b/patches/react-native+0.81.5.patch @@ -3,7 +3,7 @@ index 6cdec32..8f7cf70 100644 --- a/node_modules/react-native/React/Modules/RCTEventEmitter.m +++ b/node_modules/react-native/React/Modules/RCTEventEmitter.m @@ -89,6 +89,10 @@ - + if (_listenerCount > 0) { [self stopObserving]; + // Reset listener count to allow proper re-initialization on bridge reload @@ -12,17 +12,4 @@ index 6cdec32..8f7cf70 100644 + _listenerCount = 0; } } - -diff --git a/node_modules/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDefaults.h b/node_modules/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDefaults.h -index e0742c9..a5cd8cf 100644 ---- a/node_modules/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDefaults.h -+++ b/node_modules/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDefaults.h -@@ -216,7 +216,7 @@ class ReactNativeFeatureFlagsDefaults : public ReactNativeFeatureFlagsProvider { - } - - bool preventShadowTreeCommitExhaustion() override { -- return false; -+ return true; - } - - bool traceTurboModulePromiseRejectionsOnAndroid() override { + From b77f447a0aed01d0b268ad2f3fb070744b998002 Mon Sep 17 00:00:00 2001 From: Mounir Dhahri Date: Wed, 14 Jan 2026 09:43:47 +0100 Subject: [PATCH 112/123] fix: dev menu broken on double tap on android --- src/app/Scenes/MyProfile/MyProfileSettings.tsx | 2 +- src/app/system/devTools/DevMenu/DevMenuWrapper.tsx | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/app/Scenes/MyProfile/MyProfileSettings.tsx b/src/app/Scenes/MyProfile/MyProfileSettings.tsx index b20fffe5993..b258694e5db 100644 --- a/src/app/Scenes/MyProfile/MyProfileSettings.tsx +++ b/src/app/Scenes/MyProfile/MyProfileSettings.tsx @@ -142,7 +142,7 @@ const MyProfileSettingsContent: React.FC = () => { accessibilityRole="button" onPress={() => updateTapCount((count) => count + 1)} > - + Version: {appVersion} diff --git a/src/app/system/devTools/DevMenu/DevMenuWrapper.tsx b/src/app/system/devTools/DevMenu/DevMenuWrapper.tsx index 1b9c6ac7049..c76b69eb6c9 100644 --- a/src/app/system/devTools/DevMenu/DevMenuWrapper.tsx +++ b/src/app/system/devTools/DevMenu/DevMenuWrapper.tsx @@ -16,7 +16,7 @@ export const DevMenuWrapper: React.FC = ({ children }) ) const gestureState = useRef({ lastTapTimestamp: 0, numTaps: 0 }) - if (!userIsDev || Platform.OS === "ios") { + if (Platform.OS === "ios") { return {children} } @@ -45,6 +45,10 @@ export const DevMenuWrapper: React.FC = ({ children }) return false }, [isDeepZoomModalVisible]) + if (!userIsDev) { + return {children} + } + return ( {children} From a1eb4572f3c83d1b5b3fe254e9e5b85412c77f5c Mon Sep 17 00:00:00 2001 From: Mounir Dhahri Date: Wed, 14 Jan 2026 11:39:53 +0100 Subject: [PATCH 113/123] chore: bring back enableCppPropsIteratorSetter --- patches/react-native+0.81.5.patch | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/patches/react-native+0.81.5.patch b/patches/react-native+0.81.5.patch index 7f406048816..e9982948b11 100644 --- a/patches/react-native+0.81.5.patch +++ b/patches/react-native+0.81.5.patch @@ -3,7 +3,7 @@ index 6cdec32..8f7cf70 100644 --- a/node_modules/react-native/React/Modules/RCTEventEmitter.m +++ b/node_modules/react-native/React/Modules/RCTEventEmitter.m @@ -89,6 +89,10 @@ - + if (_listenerCount > 0) { [self stopObserving]; + // Reset listener count to allow proper re-initialization on bridge reload @@ -12,4 +12,17 @@ index 6cdec32..8f7cf70 100644 + _listenerCount = 0; } } - + +diff --git a/node_modules/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDefaults.h b/node_modules/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDefaults.h +index e0742c9..eae3d69 100644 +--- a/node_modules/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDefaults.h ++++ b/node_modules/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDefaults.h +@@ -72,7 +72,7 @@ class ReactNativeFeatureFlagsDefaults : public ReactNativeFeatureFlagsProvider { + } + + bool enableCppPropsIteratorSetter() override { +- return false; ++ return true; + } + + bool enableCustomFocusSearchOnClippedElementsAndroid() override { From a02d34f45e1982d5cc1be5ff8e56078692a25288 Mon Sep 17 00:00:00 2001 From: Mounir Dhahri Date: Thu, 15 Jan 2026 17:39:02 +0100 Subject: [PATCH 114/123] chore: downgrade reanimated --- babel.config.js | 2 +- ios/Podfile.lock | 82 ++++---------- package.json | 7 +- src/app/Components/Disappearable.tsx | 10 +- src/app/Components/Swipeable/Swipeable.tsx | 10 +- .../HomeView/hooks/useImpressionsTracking.ts | 5 +- .../Components/Swiper/Swiper.tsx | 12 +- .../Components/SavedSearchListItem.tsx | 4 +- yarn.lock | 104 +++++++++--------- 9 files changed, 100 insertions(+), 136 deletions(-) diff --git a/babel.config.js b/babel.config.js index 1328ea4209d..31ecee15e1a 100644 --- a/babel.config.js +++ b/babel.config.js @@ -24,7 +24,7 @@ module.exports = (api) => { "relay", ["module-resolver", { alias: moduleResolverAlias }], - "react-native-worklets/plugin", // has to be listed last according to the documentation. https://docs.swmansion.com/react-native-reanimated/docs/fundamentals/installation/#babel-plugin + "react-native-reanimated/plugin", // has to be listed last according to the documentation. https://docs.swmansion.com/react-native-reanimated/docs/fundamentals/installation/#babel-plugin ] const prodPlugins = [["transform-remove-console", { exclude: ["error"] }], ...plugins] diff --git a/ios/Podfile.lock b/ios/Podfile.lock index bbb1fac452a..49f01ccb362 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -3478,7 +3478,7 @@ PODS: - Yoga - RNReactNativeHapticFeedback (1.13.0): - React-Core - - RNReanimated (4.1.5): + - RNReanimated (3.19.5): - boost - DoubleConversion - fast_float @@ -3505,11 +3505,11 @@ PODS: - ReactCodegen - ReactCommon/turbomodule/bridging - ReactCommon/turbomodule/core - - RNReanimated/reanimated (= 4.1.5) - - RNWorklets + - RNReanimated/reanimated (= 3.19.5) + - RNReanimated/worklets (= 3.19.5) - SocketRocket - Yoga - - RNReanimated/reanimated (4.1.5): + - RNReanimated/reanimated (3.19.5): - boost - DoubleConversion - fast_float @@ -3536,11 +3536,10 @@ PODS: - ReactCodegen - ReactCommon/turbomodule/bridging - ReactCommon/turbomodule/core - - RNReanimated/reanimated/apple (= 4.1.5) - - RNWorklets + - RNReanimated/reanimated/apple (= 3.19.5) - SocketRocket - Yoga - - RNReanimated/reanimated/apple (4.1.5): + - RNReanimated/reanimated/apple (3.19.5): - boost - DoubleConversion - fast_float @@ -3567,40 +3566,9 @@ PODS: - ReactCodegen - ReactCommon/turbomodule/bridging - ReactCommon/turbomodule/core - - RNWorklets - SocketRocket - Yoga - - RNScreens (4.16.0): - - boost - - DoubleConversion - - fast_float - - fmt - - glog - - hermes-engine - - RCT-Folly - - RCT-Folly/Fabric - - RCTRequired - - RCTTypeSafety - - React-Core - - React-debug - - React-Fabric - - React-featureflags - - React-graphics - - React-ImageManager - - React-jsi - - React-NativeModulesApple - - React-RCTFabric - - React-RCTImage - - React-renderercss - - React-rendererdebug - - React-utils - - ReactCodegen - - ReactCommon/turbomodule/bridging - - ReactCommon/turbomodule/core - - RNScreens/common (= 4.16.0) - - SocketRocket - - Yoga - - RNScreens/common (4.16.0): + - RNReanimated/worklets (3.19.5): - boost - DoubleConversion - fast_float @@ -3616,20 +3584,21 @@ PODS: - React-Fabric - React-featureflags - React-graphics + - React-hermes - React-ImageManager - React-jsi - React-NativeModulesApple - React-RCTFabric - - React-RCTImage - React-renderercss - React-rendererdebug - React-utils - ReactCodegen - ReactCommon/turbomodule/bridging - ReactCommon/turbomodule/core + - RNReanimated/worklets/apple (= 3.19.5) - SocketRocket - Yoga - - RNSentry (6.21.0): + - RNReanimated/worklets/apple (3.19.5): - boost - DoubleConversion - fast_float @@ -3656,10 +3625,9 @@ PODS: - ReactCodegen - ReactCommon/turbomodule/bridging - ReactCommon/turbomodule/core - - Sentry/HybridSDK (= 8.53.2) - SocketRocket - Yoga - - RNShare (12.0.9): + - RNScreens (4.16.0): - boost - DoubleConversion - fast_float @@ -3679,15 +3647,17 @@ PODS: - React-jsi - React-NativeModulesApple - React-RCTFabric + - React-RCTImage - React-renderercss - React-rendererdebug - React-utils - ReactCodegen - ReactCommon/turbomodule/bridging - ReactCommon/turbomodule/core + - RNScreens/common (= 4.16.0) - SocketRocket - Yoga - - RNSVG (15.14.0): + - RNScreens/common (4.16.0): - boost - DoubleConversion - fast_float @@ -3707,16 +3677,16 @@ PODS: - React-jsi - React-NativeModulesApple - React-RCTFabric + - React-RCTImage - React-renderercss - React-rendererdebug - React-utils - ReactCodegen - ReactCommon/turbomodule/bridging - ReactCommon/turbomodule/core - - RNSVG/common (= 15.14.0) - SocketRocket - Yoga - - RNSVG/common (15.14.0): + - RNSentry (6.21.0): - boost - DoubleConversion - fast_float @@ -3732,6 +3702,7 @@ PODS: - React-Fabric - React-featureflags - React-graphics + - React-hermes - React-ImageManager - React-jsi - React-NativeModulesApple @@ -3742,9 +3713,10 @@ PODS: - ReactCodegen - ReactCommon/turbomodule/bridging - ReactCommon/turbomodule/core + - Sentry/HybridSDK (= 8.53.2) - SocketRocket - Yoga - - RNWorklets (0.6.1): + - RNShare (12.0.9): - boost - DoubleConversion - fast_float @@ -3760,7 +3732,6 @@ PODS: - React-Fabric - React-featureflags - React-graphics - - React-hermes - React-ImageManager - React-jsi - React-NativeModulesApple @@ -3771,10 +3742,9 @@ PODS: - ReactCodegen - ReactCommon/turbomodule/bridging - ReactCommon/turbomodule/core - - RNWorklets/worklets (= 0.6.1) - SocketRocket - Yoga - - RNWorklets/worklets (0.6.1): + - RNSVG (15.14.0): - boost - DoubleConversion - fast_float @@ -3790,7 +3760,6 @@ PODS: - React-Fabric - React-featureflags - React-graphics - - React-hermes - React-ImageManager - React-jsi - React-NativeModulesApple @@ -3801,10 +3770,10 @@ PODS: - ReactCodegen - ReactCommon/turbomodule/bridging - ReactCommon/turbomodule/core - - RNWorklets/worklets/apple (= 0.6.1) + - RNSVG/common (= 15.14.0) - SocketRocket - Yoga - - RNWorklets/worklets/apple (0.6.1): + - RNSVG/common (15.14.0): - boost - DoubleConversion - fast_float @@ -3820,7 +3789,6 @@ PODS: - React-Fabric - React-featureflags - React-graphics - - React-hermes - React-ImageManager - React-jsi - React-NativeModulesApple @@ -4128,7 +4096,6 @@ DEPENDENCIES: - "RNSentry (from `../node_modules/@sentry/react-native`)" - RNShare (from `../node_modules/react-native-share`) - RNSVG (from `../node_modules/react-native-svg`) - - RNWorklets (from `../node_modules/react-native-worklets`) - SDWebImage (= 5.19.1) - "segment-analytics-react-native (from `../node_modules/@segment/analytics-react-native`)" - sift-react-native (from `../node_modules/sift-react-native`) @@ -4505,8 +4472,6 @@ EXTERNAL SOURCES: :path: "../node_modules/react-native-share" RNSVG: :path: "../node_modules/react-native-svg" - RNWorklets: - :path: "../node_modules/react-native-worklets" segment-analytics-react-native: :path: "../node_modules/@segment/analytics-react-native" sift-react-native: @@ -4726,12 +4691,11 @@ SPEC CHECKSUMS: RNNotifee: 5e3b271e8ea7456a36eec994085543c9adca9168 RNPermissions: 663a639fdc5aa46b853f514ae8a86dd4deb160cb RNReactNativeHapticFeedback: 7601768ee65ffc86fc93d7c30dd917031144ed3d - RNReanimated: 142b5513b136714ea7abef65b46e04c12ce7194e + RNReanimated: 9af1b9f7d221d1cc2f99d935bab08419cae7c1ce RNScreens: 0bbf16c074ae6bb1058a7bf2d1ae017f4306797c RNSentry: ab7ba8bd678713c94762d2d3f2087d47105b6cf3 RNShare: 1dba46787d6e5543e05655efaefa0e4bb98380d9 RNSVG: c5807de8e337c7a643f9bad2ecf48a15aefcc23c - RNWorklets: ab618bf7d1c7fd2cb793b9f0f39c3e29274b3ebf SDWebImage: 40b0b4053e36c660a764958bff99eed16610acbb SDWebImageAVIFCoder: afe194a084e851f70228e4be35ef651df0fc5c57 SDWebImageWebPCoder: e38c0a70396191361d60c092933e22c20d5b1380 diff --git a/package.json b/package.json index 2f4c4e98aab..c7f66fa6e3b 100644 --- a/package.json +++ b/package.json @@ -109,7 +109,7 @@ "dependencies": { "@artsy/cohesion": "4.336.0", "@artsy/icons": "3.64.0", - "@artsy/palette-mobile": "22.2.0--canary.425.5173.0", + "@artsy/palette-mobile": "22.4.0--canary.425.5208.0", "@artsy/to-title-case": "1.2.0", "@braze/react-native-sdk": "16.1.0", "@d11/react-native-fast-image": "8.12.0", @@ -168,7 +168,7 @@ "react-native-blob-util": "0.19.11", "react-native-blurhash": "2.1.2", "react-native-bootsplash": "6.3.10", - "react-native-collapsible-tab-view": "9.0.0-rc.0", + "react-native-collapsible-tab-view": "8.0.1", "react-native-device-info": "14.0.0", "react-native-fbsdk-next": "13.4.1", "react-native-gesture-handler": "2.28.0", @@ -185,7 +185,7 @@ "react-native-localize": "3.5.2", "react-native-pager-view": "7.0.1", "react-native-permissions": "3.8.4", - "react-native-reanimated": "4.1.5", + "react-native-reanimated": "3.19.5", "react-native-reanimated-zoom": "0.3.3", "react-native-render-html": "6.3.4", "react-native-safe-area-context": "5.6.1", @@ -197,7 +197,6 @@ "react-native-view-shot": "4.0.3", "react-native-vimeo-iframe": "1.2.1", "react-native-webview": "13.15.0", - "react-native-worklets": "0.6.1", "react-native-youtube-iframe": "^2.4.1", "react-relay": "18.2.0", "react-tracking": "9.3.2", diff --git a/src/app/Components/Disappearable.tsx b/src/app/Components/Disappearable.tsx index 71bbced01e4..1c86de1d48d 100644 --- a/src/app/Components/Disappearable.tsx +++ b/src/app/Components/Disappearable.tsx @@ -1,6 +1,10 @@ import { forwardRef, useImperativeHandle, useState } from "react" -import Animated, { useAnimatedStyle, useSharedValue, withTiming } from "react-native-reanimated" -import { scheduleOnRN } from "react-native-worklets" +import Animated, { + runOnJS, + useAnimatedStyle, + useSharedValue, + withTiming, +} from "react-native-reanimated" export interface Disappearable { disappear(): Promise @@ -28,7 +32,7 @@ export const Disappearable = forwardRef withTiming(0, { duration: 500 }, () => { - scheduleOnRN(setShowContent, false) + runOnJS(setShowContent)(false) }) ) }, diff --git a/src/app/Components/Swipeable/Swipeable.tsx b/src/app/Components/Swipeable/Swipeable.tsx index 7d3f1326c5f..549959c5619 100644 --- a/src/app/Components/Swipeable/Swipeable.tsx +++ b/src/app/Components/Swipeable/Swipeable.tsx @@ -6,8 +6,12 @@ import ReanimatedSwipeable, { SwipeableProps, } from "react-native-gesture-handler/ReanimatedSwipeable" import ReactNativeHapticFeedback from "react-native-haptic-feedback" -import Animated, { SharedValue, useAnimatedStyle, useSharedValue } from "react-native-reanimated" -import { scheduleOnRN } from "react-native-worklets" +import Animated, { + runOnJS, + SharedValue, + useAnimatedStyle, + useSharedValue, +} from "react-native-reanimated" const FRICTION = 1 const SWIPE_TO_INTERACT_THRESHOLD = 80 @@ -68,7 +72,7 @@ export const Swipeable = forwardRef(( const swipeDistance = width.get() + dragX.get() * FRICTION if (swipeDistance <= SWIPE_TO_INTERACT_THRESHOLD) { - scheduleOnRN(handleSwipeToInteract, swipeDistance) + runOnJS(handleSwipeToInteract)(swipeDistance) } return style diff --git a/src/app/Scenes/HomeView/hooks/useImpressionsTracking.ts b/src/app/Scenes/HomeView/hooks/useImpressionsTracking.ts index e64db8a9a8b..feecaa18ea9 100644 --- a/src/app/Scenes/HomeView/hooks/useImpressionsTracking.ts +++ b/src/app/Scenes/HomeView/hooks/useImpressionsTracking.ts @@ -4,8 +4,7 @@ import { useFeatureFlag } from "app/utils/hooks/useFeatureFlag" import { useViewabilityConfig } from "app/utils/hooks/useViewabilityConfig" import { useCallback, useEffect, useRef, useState } from "react" import { ViewToken } from "react-native" -import { useAnimatedReaction, useSharedValue } from "react-native-reanimated" -import { scheduleOnRN } from "react-native-worklets" +import { runOnJS, useAnimatedReaction, useSharedValue } from "react-native-reanimated" import { useTracking } from "react-tracking" type TrackableItem = { id: string; index: number | null } @@ -104,7 +103,7 @@ export const useItemsImpressionsTracking = ({ () => renderedItems.value, (currentItems) => { if (!__TEST__) { - scheduleOnRN(trackItems, currentItems) + runOnJS(trackItems)(currentItems) } }, [enableItemsViewsTracking, isInViewport, contextScreenOwnerType, contextModule] diff --git a/src/app/Scenes/InfiniteDiscovery/Components/Swiper/Swiper.tsx b/src/app/Scenes/InfiniteDiscovery/Components/Swiper/Swiper.tsx index e70f0c68335..9db21f5e639 100644 --- a/src/app/Scenes/InfiniteDiscovery/Components/Swiper/Swiper.tsx +++ b/src/app/Scenes/InfiniteDiscovery/Components/Swiper/Swiper.tsx @@ -10,13 +10,13 @@ import { Easing, Extrapolation, interpolate, + runOnJS, useAnimatedReaction, useSharedValue, withDelay, withSequence, withTiming, } from "react-native-reanimated" -import { scheduleOnRN } from "react-native-worklets" type SwiperProps = { cards: InfiniteDiscoveryArtwork[] @@ -70,7 +70,7 @@ export const Swiper = forwardRef( () => _activeIndex.value, (current, previous) => { if (current !== previous) { - scheduleOnRN(setActiveIndex, current) + runOnJS(setActiveIndex)(current) } } ) @@ -129,7 +129,7 @@ export const Swiper = forwardRef( // if this is the first time that the user has navigated to this card, record it if (nextCardKey && !seenCardKeys.value.includes(nextCardKey) && onNewCardReached) { seenCardKeys.value = [...seenCardKeys.value, nextCardKey] - scheduleOnRN(onNewCardReached, nextCardKey) + runOnJS(onNewCardReached)(nextCardKey) } activeCardX.value = withTiming(-width, { duration: 300, easing: Easing.linear }, () => { @@ -139,7 +139,7 @@ export const Swiper = forwardRef( return }) - scheduleOnRN(onSwipe, swipedCardKey, nextCardKey) + runOnJS(onSwipe)(swipedCardKey, nextCardKey) } const swipeRight = () => { @@ -158,7 +158,7 @@ export const Swiper = forwardRef( swipedCardX.value = -width } ) - scheduleOnRN(onRewind, lastSwipedCardKey as Key) + runOnJS(onRewind)(lastSwipedCardKey as Key) return } @@ -183,7 +183,7 @@ export const Swiper = forwardRef( // Fetching more cards on the 3rd, 8th, 13th... swipe if (isSwipeLeft && !isLastCard && cards.length - 1 - _activeIndex.value === triggerIndex) { - scheduleOnRN(onReachTriggerIndex, _activeIndex.value + 1) + runOnJS(onReachTriggerIndex)(_activeIndex.value + 1) } const swipedCardIndex = _activeIndex.value diff --git a/src/app/Scenes/SavedSearchAlertsList/Components/SavedSearchListItem.tsx b/src/app/Scenes/SavedSearchAlertsList/Components/SavedSearchListItem.tsx index 82f5e76adde..632240f292b 100644 --- a/src/app/Scenes/SavedSearchAlertsList/Components/SavedSearchListItem.tsx +++ b/src/app/Scenes/SavedSearchAlertsList/Components/SavedSearchListItem.tsx @@ -10,11 +10,11 @@ import { Alert } from "react-native" import { Gesture, GestureDetector } from "react-native-gesture-handler" import Animated, { Easing, + runOnJS, useAnimatedStyle, useSharedValue, withTiming, } from "react-native-reanimated" -import { scheduleOnRN } from "react-native-worklets" import { graphql, useFragment } from "react-relay" import { useTracking } from "react-tracking" @@ -58,7 +58,7 @@ export const SavedSearchListItem: React.FC = (props) = .activeOffsetX([-5, 5]) .withTestId(`pan-alert-${alert.internalID}`) .onBegin(() => { - scheduleOnRN(onSwipeBegin, alert.internalID) + runOnJS(onSwipeBegin)(alert.internalID) }) .onChange((event) => { // Prevent swiping to the right diff --git a/yarn.lock b/yarn.lock index dedae48490c..53db77e13c0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -72,9 +72,9 @@ __metadata: languageName: node linkType: hard -"@artsy/palette-mobile@npm:22.2.0--canary.425.5173.0": - version: 22.2.0--canary.425.5173.0 - resolution: "@artsy/palette-mobile@npm:22.2.0--canary.425.5173.0" +"@artsy/palette-mobile@npm:22.4.0--canary.425.5208.0": + version: 22.4.0--canary.425.5208.0 + resolution: "@artsy/palette-mobile@npm:22.4.0--canary.425.5208.0" dependencies: "@artsy/icons": "npm:^3.49.0" "@artsy/palette-tokens": "npm:7.0.0" @@ -87,7 +87,7 @@ __metadata: moti: "npm:0.30.0" react-nanny: "npm:^2.15.0" react-native-blurhash: "npm:2.1.2" - react-native-collapsible-tab-view: "npm:9.0.0-rc.0" + react-native-collapsible-tab-view: "npm:8.0.1" react-native-pager-view: "npm:6.7.1" react-native-popover-view: "npm:^6.1.0" styled-system: "npm:^5.1.5" @@ -101,7 +101,7 @@ __metadata: react-native-reanimated: "*" react-native-svg: "*" styled-components: ">= 5" - checksum: 10c0/2ba4f6d9c8429565dfc3b97b1597e0d7198c94ef67d6b061472b33844328ed01f5968fc734386cec272ddca2cedf364550e8490a1b78c4074263ffa426236c07 + checksum: 10c0/63f190416d00ca8d47b75e209db620377f831c6312bd5199ae180d116aafec5154d81f92e261daf6b4fc0669f8d25c549b7c2568ecf08e17fe9899fee5539263 languageName: node linkType: hard @@ -13165,7 +13165,7 @@ __metadata: dependencies: "@artsy/cohesion": "npm:4.336.0" "@artsy/icons": "npm:3.64.0" - "@artsy/palette-mobile": "npm:22.2.0--canary.425.5173.0" + "@artsy/palette-mobile": "npm:22.4.0--canary.425.5208.0" "@artsy/to-title-case": "npm:1.2.0" "@artsy/update-repo": "npm:0.7.0" "@babel/core": "npm:7.25.2" @@ -13325,7 +13325,7 @@ __metadata: react-native-blob-util: "npm:0.19.11" react-native-blurhash: "npm:2.1.2" react-native-bootsplash: "npm:6.3.10" - react-native-collapsible-tab-view: "npm:9.0.0-rc.0" + react-native-collapsible-tab-view: "npm:8.0.1" react-native-device-info: "npm:14.0.0" react-native-fbsdk-next: "npm:13.4.1" react-native-gesture-handler: "npm:2.28.0" @@ -13343,7 +13343,7 @@ __metadata: react-native-pager-view: "npm:7.0.1" react-native-performance: "npm:5.1.4" react-native-permissions: "npm:3.8.4" - react-native-reanimated: "npm:4.1.5" + react-native-reanimated: "npm:3.19.5" react-native-reanimated-zoom: "npm:0.3.3" react-native-render-html: "npm:6.3.4" react-native-safe-area-context: "npm:5.6.1" @@ -13355,7 +13355,6 @@ __metadata: react-native-view-shot: "npm:4.0.3" react-native-vimeo-iframe: "npm:1.2.1" react-native-webview: "npm:13.15.0" - react-native-worklets: "npm:0.6.1" react-native-youtube-iframe: "npm:^2.4.1" react-relay: "npm:18.2.0" react-relay-network-modern: "npm:6.2.2" @@ -22076,22 +22075,21 @@ __metadata: languageName: node linkType: hard -"react-native-collapsible-tab-view@npm:9.0.0-rc.0": - version: 9.0.0-rc.0 - resolution: "react-native-collapsible-tab-view@npm:9.0.0-rc.0" +"react-native-collapsible-tab-view@npm:8.0.1": + version: 8.0.1 + resolution: "react-native-collapsible-tab-view@npm:8.0.1" dependencies: use-deep-compare: "npm:^1.1.0" peerDependencies: - "@shopify/flash-list": ">=2.0.0" + "@shopify/flash-list": ">=1.0.0" react: "*" react-native: "*" react-native-pager-view: "*" - react-native-reanimated: ">=4.1.0" - react-native-worklets: ">=0.5.1" + react-native-reanimated: ">=3.8.1" peerDependenciesMeta: "@shopify/flash-list": optional: true - checksum: 10c0/6297022971370d3e8819cb866203e20bbcaab50009b8f5e8cecb9bf04ae96361131aef073d4c4cc8ffa7e625934a18c2a7ee3d5bb180560c8579bea523035361 + checksum: 10c0/b4d8c8936cb8b647fc50a5e8ccbb4875d74cc68f90864e13980ec5351b9b49acbe84890c629dc1343f23730295483bd25c219435fd738dd3ac7ac879f221e620 languageName: node linkType: hard @@ -22191,6 +22189,16 @@ __metadata: languageName: node linkType: hard +"react-native-is-edge-to-edge@npm:1.1.7": + version: 1.1.7 + resolution: "react-native-is-edge-to-edge@npm:1.1.7" + peerDependencies: + react: "*" + react-native: "*" + checksum: 10c0/b7a37437f439b1e27a4d980de01994aa71b9091dc3ed00c21172d5505fb11978cd5ed3a43f97c89d502a3a08cf26e5cea6435b8d6e93d3557a92dd43563f7021 + languageName: node + linkType: hard + "react-native-is-edge-to-edge@npm:^1.2.1": version: 1.2.1 resolution: "react-native-is-edge-to-edge@npm:1.2.1" @@ -22329,18 +22337,27 @@ __metadata: languageName: node linkType: hard -"react-native-reanimated@npm:4.1.5": - version: 4.1.5 - resolution: "react-native-reanimated@npm:4.1.5" +"react-native-reanimated@npm:3.19.5": + version: 3.19.5 + resolution: "react-native-reanimated@npm:3.19.5" dependencies: - react-native-is-edge-to-edge: "npm:^1.2.1" - semver: "npm:7.7.2" + "@babel/plugin-transform-arrow-functions": "npm:^7.0.0-0" + "@babel/plugin-transform-class-properties": "npm:^7.0.0-0" + "@babel/plugin-transform-classes": "npm:^7.0.0-0" + "@babel/plugin-transform-nullish-coalescing-operator": "npm:^7.0.0-0" + "@babel/plugin-transform-optional-chaining": "npm:^7.0.0-0" + "@babel/plugin-transform-shorthand-properties": "npm:^7.0.0-0" + "@babel/plugin-transform-template-literals": "npm:^7.0.0-0" + "@babel/plugin-transform-unicode-regex": "npm:^7.0.0-0" + "@babel/preset-typescript": "npm:^7.16.7" + convert-source-map: "npm:^2.0.0" + invariant: "npm:^2.2.4" + react-native-is-edge-to-edge: "npm:1.1.7" peerDependencies: "@babel/core": ^7.0.0-0 react: "*" react-native: "*" - react-native-worklets: ">=0.5.0" - checksum: 10c0/af4aeb17b23089819c8d1dbf7f06ac4e7116cf86c1350a44ee6b6b1d262ce4d93ee28b1e3ffc7ec12f2fd261a8d6436ecf4b771e47127ebdb2e5b509f177a2b5 + checksum: 10c0/5da1e142b5c2fefc118a2c6b2bba224deffb98048399b350c22e3496d36ff348ca0d72f7a0b8478db069b1d10e56f42c070c03807fa7e384cf12d9f35c8fc6cf languageName: node linkType: hard @@ -22479,29 +22496,6 @@ __metadata: languageName: node linkType: hard -"react-native-worklets@npm:0.6.1": - version: 0.6.1 - resolution: "react-native-worklets@npm:0.6.1" - dependencies: - "@babel/plugin-transform-arrow-functions": "npm:^7.0.0-0" - "@babel/plugin-transform-class-properties": "npm:^7.0.0-0" - "@babel/plugin-transform-classes": "npm:^7.0.0-0" - "@babel/plugin-transform-nullish-coalescing-operator": "npm:^7.0.0-0" - "@babel/plugin-transform-optional-chaining": "npm:^7.0.0-0" - "@babel/plugin-transform-shorthand-properties": "npm:^7.0.0-0" - "@babel/plugin-transform-template-literals": "npm:^7.0.0-0" - "@babel/plugin-transform-unicode-regex": "npm:^7.0.0-0" - "@babel/preset-typescript": "npm:^7.16.7" - convert-source-map: "npm:^2.0.0" - semver: "npm:7.7.2" - peerDependencies: - "@babel/core": ^7.0.0-0 - react: "*" - react-native: "*" - checksum: 10c0/bc3dcca00e287939aeb7ee7be501f15a0ac59c9351c60efafa89447d70e549e7f126705c154d92dd6e0cab924bf25f3c6ec1234a55a4daa9d3b3f26aa7871777 - languageName: node - linkType: hard - "react-native-youtube-iframe@npm:^2.4.1": version: 2.4.1 resolution: "react-native-youtube-iframe@npm:2.4.1" @@ -23704,15 +23698,6 @@ __metadata: languageName: node linkType: hard -"semver@npm:7.7.2, semver@npm:^7.7.2": - version: 7.7.2 - resolution: "semver@npm:7.7.2" - bin: - semver: bin/semver.js - checksum: 10c0/aca305edfbf2383c22571cb7714f48cadc7ac95371b4b52362fb8eeffdfbc0de0669368b82b2b15978f8848f01d7114da65697e56cd8c37b0dab8c58e543f9ea - languageName: node - linkType: hard - "semver@npm:^5.5.0": version: 5.7.2 resolution: "semver@npm:5.7.2" @@ -23751,6 +23736,15 @@ __metadata: languageName: node linkType: hard +"semver@npm:^7.7.2": + version: 7.7.2 + resolution: "semver@npm:7.7.2" + bin: + semver: bin/semver.js + checksum: 10c0/aca305edfbf2383c22571cb7714f48cadc7ac95371b4b52362fb8eeffdfbc0de0669368b82b2b15978f8848f01d7114da65697e56cd8c37b0dab8c58e543f9ea + languageName: node + linkType: hard + "send@npm:0.18.0": version: 0.18.0 resolution: "send@npm:0.18.0" From 8aa5785e9e9bc3244a08a1743d357db469d2c058 Mon Sep 17 00:00:00 2001 From: Mounir Dhahri Date: Thu, 15 Jan 2026 17:39:54 +0100 Subject: [PATCH 115/123] Revert "chore: artist nav header broken animation on android" This reverts commit 1eb5effd9fcb7533f0a70e9cc7032ac2fb0bafee. --- .../Artist/ArtistHeaderNavRight.tsx | 123 ++++++++++++++++- ...eaderNavRightFragmentContainer.android.tsx | 100 -------------- ...istHeaderNavRightFragmentContainer.ios.tsx | 127 ------------------ 3 files changed, 117 insertions(+), 233 deletions(-) delete mode 100644 src/app/Components/Artist/ArtistHeaderNavRightFragmentContainer.android.tsx delete mode 100644 src/app/Components/Artist/ArtistHeaderNavRightFragmentContainer.ios.tsx diff --git a/src/app/Components/Artist/ArtistHeaderNavRight.tsx b/src/app/Components/Artist/ArtistHeaderNavRight.tsx index cc52602de30..547171a0d5d 100644 --- a/src/app/Components/Artist/ArtistHeaderNavRight.tsx +++ b/src/app/Components/Artist/ArtistHeaderNavRight.tsx @@ -1,22 +1,133 @@ -import { Flex } from "@artsy/palette-mobile" +import { ShareIcon } from "@artsy/icons/native" +import { Flex, FollowButton, NAVBAR_HEIGHT, useSpace } from "@artsy/palette-mobile" +import { useScreenScrollContext } from "@artsy/palette-mobile/dist/elements/Screen/ScreenScrollContext" import { ArtistHeaderNavRightQuery } from "__generated__/ArtistHeaderNavRightQuery.graphql" import { ArtistHeaderNavRight_artist$key } from "__generated__/ArtistHeaderNavRight_artist.graphql" -// @ts-ignore -import { ArtistHeaderNavRight as ArtistHeaderNavRightFragmentContainer } from "app/Components/Artist/ArtistHeaderNavRightFragmentContainer" +import { useFollowArtist } from "app/Components/Artist/useFollowArtist" +import { useShareSheet } from "app/Components/ShareSheet/ShareSheetContext" +import { ACCESSIBLE_DEFAULT_ICON_SIZE } from "app/Components/constants" import { NoFallback, withSuspense } from "app/utils/hooks/withSuspense" -import { graphql, useLazyLoadQuery } from "react-relay" +import { MotiView } from "moti" +import { useCallback, useState } from "react" +import { PixelRatio, TouchableOpacity } from "react-native" +import { Easing, useAnimatedStyle, useDerivedValue, withTiming } from "react-native-reanimated" +import { graphql, useFragment, useLazyLoadQuery } from "react-relay" +import useDebounce from "react-use/lib/useDebounce" interface ArtistHeaderNavRightProps { artist: ArtistHeaderNavRight_artist$key } +const CONTAINER_WIDTH = 185 * PixelRatio.getFontScale() + export const ArtistHeaderNavRight: React.FC = ({ artist: artistProp, }) => { - return + const space = useSpace() + const { currentScrollYAnimated, scrollYOffset } = useScreenScrollContext() + const artist = useFragment(fragment, artistProp) + const [isFollowed, setIsFollowed] = useState(!!artist?.isFollowed) + + const { showShareSheet } = useShareSheet() + const { handleFollowToggle } = useFollowArtist(artist) + + // The container width minus the share icon width minus the padding on the left and right + const followButtonWidth = CONTAINER_WIDTH - ACCESSIBLE_DEFAULT_ICON_SIZE - space(2) + + useDebounce( + () => { + if (isFollowed !== artist?.isFollowed) { + handleFollowToggle() + } + }, + 350, + [isFollowed] + ) + + const followAreaDeltaX = (followButtonWidth + space(2)) * PixelRatio.getFontScale() + const displayFollowButton = useDerivedValue(() => { + return !scrollYOffset || currentScrollYAnimated.value < scrollYOffset + NAVBAR_HEIGHT + }) + + // convert the space into primitive types to be user on the UI thread + const space2 = space(2) + + const followButtonTranslateX = useDerivedValue(() => + displayFollowButton.value ? 0 : followAreaDeltaX + ) + + const followButtonOpacity = useDerivedValue(() => (displayFollowButton.value ? 1 : 0)) + + const viewStyle = useAnimatedStyle( + () => ({ + transform: [ + { + translateX: withTiming( + followButtonTranslateX.value - (displayFollowButton.value ? 0 : space2), + { + duration: 200, + easing: Easing.sin, + } + ), + }, + ], + }), + [followAreaDeltaX] + ) + + const followButtonStyle = useAnimatedStyle(() => ({ + opacity: withTiming(followButtonOpacity.value, { duration: 200 }), + })) + + const handleSharePress = useCallback(() => { + if (artist?.name && artist?.name && artist?.slug && artist?.href) { + showShareSheet({ + type: "artist", + internalID: artist.internalID, + slug: artist.slug, + artists: [{ name: artist.name ?? null }], + title: artist.name, + href: artist.href, + currentImageUrl: artist.shareImage?.image?.url ?? undefined, + }) + } + }, [artist, showShareSheet]) + + return ( + + + + + + + + setIsFollowed(!isFollowed)} + // Using maxWidth and minWidth to prevent the button from changing width when the text changes + maxWidth={followButtonWidth} + minWidth={followButtonWidth} + /> + + + + ) } -export const artistHeaderNavRightFragment = graphql` +const fragment = graphql` fragment ArtistHeaderNavRight_artist on Artist { isFollowed counts @required(action: NONE) { diff --git a/src/app/Components/Artist/ArtistHeaderNavRightFragmentContainer.android.tsx b/src/app/Components/Artist/ArtistHeaderNavRightFragmentContainer.android.tsx deleted file mode 100644 index 345567038c3..00000000000 --- a/src/app/Components/Artist/ArtistHeaderNavRightFragmentContainer.android.tsx +++ /dev/null @@ -1,100 +0,0 @@ -import { ShareIcon } from "@artsy/icons/native" -import { Flex, FollowButton, NAVBAR_HEIGHT, useSpace } from "@artsy/palette-mobile" -import { useScreenScrollContext } from "@artsy/palette-mobile/dist/elements/Screen/ScreenScrollContext" -import { ArtistHeaderNavRight_artist$key } from "__generated__/ArtistHeaderNavRight_artist.graphql" -import { artistHeaderNavRightFragment } from "app/Components/Artist/ArtistHeaderNavRight" -import { useFollowArtist } from "app/Components/Artist/useFollowArtist" -import { useShareSheet } from "app/Components/ShareSheet/ShareSheetContext" -import { ACCESSIBLE_DEFAULT_ICON_SIZE } from "app/Components/constants" -import { useCallback, useState } from "react" -import { PixelRatio, TouchableOpacity } from "react-native" -import { runOnJS, useAnimatedReaction } from "react-native-reanimated" -import { useFragment } from "react-relay" -import useDebounce from "react-use/lib/useDebounce" - -interface ArtistHeaderNavRightProps { - artist: ArtistHeaderNavRight_artist$key -} - -const CONTAINER_WIDTH = 185 * PixelRatio.getFontScale() - -export const ArtistHeaderNavRight: React.FC = ({ - artist: artistProp, -}) => { - const space = useSpace() - const { currentScrollYAnimated, scrollYOffset } = useScreenScrollContext() - const artist = useFragment(artistHeaderNavRightFragment, artistProp) - const [isFollowed, setIsFollowed] = useState(!!artist?.isFollowed) - const [showFollowButton, setShowFollowButton] = useState(true) - - const { showShareSheet } = useShareSheet() - const { handleFollowToggle } = useFollowArtist(artist) - - useAnimatedReaction( - () => { - return !scrollYOffset || currentScrollYAnimated.value + 50 < scrollYOffset + NAVBAR_HEIGHT - }, - (shouldShow) => { - runOnJS(setShowFollowButton)(shouldShow) - }, - [scrollYOffset] - ) - - // The container width minus the share icon width minus the padding on the left and right - const followButtonWidth = CONTAINER_WIDTH - ACCESSIBLE_DEFAULT_ICON_SIZE - space(2) - - useDebounce( - () => { - if (isFollowed !== artist?.isFollowed) { - handleFollowToggle() - } - }, - 350, - [isFollowed] - ) - - const handleSharePress = useCallback(() => { - if (artist?.name && artist?.name && artist?.slug && artist?.href) { - showShareSheet({ - type: "artist", - internalID: artist.internalID, - slug: artist.slug, - artists: [{ name: artist.name ?? null }], - title: artist.name, - href: artist.href, - currentImageUrl: artist.shareImage?.image?.url ?? undefined, - }) - } - }, [artist, showShareSheet]) - - return ( - - - - - - {showFollowButton ? ( - setIsFollowed(!isFollowed)} - // Using maxWidth and minWidth to prevent the button from changing width when the text changes - maxWidth={followButtonWidth} - minWidth={followButtonWidth} - /> - ) : null} - - ) -} diff --git a/src/app/Components/Artist/ArtistHeaderNavRightFragmentContainer.ios.tsx b/src/app/Components/Artist/ArtistHeaderNavRightFragmentContainer.ios.tsx deleted file mode 100644 index 3d2adf8ea51..00000000000 --- a/src/app/Components/Artist/ArtistHeaderNavRightFragmentContainer.ios.tsx +++ /dev/null @@ -1,127 +0,0 @@ -import { ShareIcon } from "@artsy/icons/native" -import { Flex, FollowButton, NAVBAR_HEIGHT, useSpace } from "@artsy/palette-mobile" -import { useScreenScrollContext } from "@artsy/palette-mobile/dist/elements/Screen/ScreenScrollContext" -import { ArtistHeaderNavRight_artist$key } from "__generated__/ArtistHeaderNavRight_artist.graphql" -import { artistHeaderNavRightFragment } from "app/Components/Artist/ArtistHeaderNavRight" -import { useFollowArtist } from "app/Components/Artist/useFollowArtist" -import { useShareSheet } from "app/Components/ShareSheet/ShareSheetContext" -import { ACCESSIBLE_DEFAULT_ICON_SIZE } from "app/Components/constants" -import { MotiView } from "moti" -import { useCallback, useState } from "react" -import { PixelRatio, TouchableOpacity } from "react-native" -import { Easing, useAnimatedStyle, useDerivedValue, withTiming } from "react-native-reanimated" -import { useFragment } from "react-relay" -import useDebounce from "react-use/lib/useDebounce" - -interface ArtistHeaderNavRightProps { - artist: ArtistHeaderNavRight_artist$key -} - -const CONTAINER_WIDTH = 185 * PixelRatio.getFontScale() - -export const ArtistHeaderNavRight: React.FC = ({ - artist: artistProp, -}) => { - const space = useSpace() - const { currentScrollYAnimated, scrollYOffset } = useScreenScrollContext() - const artist = useFragment(artistHeaderNavRightFragment, artistProp) - const [isFollowed, setIsFollowed] = useState(!!artist?.isFollowed) - - const { showShareSheet } = useShareSheet() - const { handleFollowToggle } = useFollowArtist(artist) - - // The container width minus the share icon width minus the padding on the left and right - const followButtonWidth = CONTAINER_WIDTH - ACCESSIBLE_DEFAULT_ICON_SIZE - space(2) - - useDebounce( - () => { - if (isFollowed !== artist?.isFollowed) { - handleFollowToggle() - } - }, - 350, - [isFollowed] - ) - - const followAreaDeltaX = (followButtonWidth + space(2)) * PixelRatio.getFontScale() - const displayFollowButton = useDerivedValue(() => { - return !scrollYOffset || currentScrollYAnimated.value < scrollYOffset + NAVBAR_HEIGHT - }) - - // convert the space into primitive types to be user on the UI thread - const space2 = space(2) - - const followButtonTranslateX = useDerivedValue(() => - displayFollowButton.value ? 0 : followAreaDeltaX - ) - - const followButtonOpacity = useDerivedValue(() => (displayFollowButton.value ? 1 : 0)) - - const viewStyle = useAnimatedStyle( - () => ({ - transform: [ - { - translateX: withTiming( - followButtonTranslateX.value - (displayFollowButton.value ? 0 : space2), - { - duration: 200, - easing: Easing.sin, - } - ), - }, - ], - }), - [followAreaDeltaX] - ) - - const followButtonStyle = useAnimatedStyle(() => ({ - opacity: withTiming(followButtonOpacity.value, { duration: 200 }), - })) - - const handleSharePress = useCallback(() => { - if (artist?.name && artist?.name && artist?.slug && artist?.href) { - showShareSheet({ - type: "artist", - internalID: artist.internalID, - slug: artist.slug, - artists: [{ name: artist.name ?? null }], - title: artist.name, - href: artist.href, - currentImageUrl: artist.shareImage?.image?.url ?? undefined, - }) - } - }, [artist, showShareSheet]) - - return ( - - - - - - - - setIsFollowed(!isFollowed)} - // Using maxWidth and minWidth to prevent the button from changing width when the text changes - maxWidth={followButtonWidth} - minWidth={followButtonWidth} - /> - - - - ) -} From 3c40813af5199d54125568b184d5cc3c81f35c27 Mon Sep 17 00:00:00 2001 From: Mounir Dhahri Date: Fri, 16 Jan 2026 17:10:24 +0100 Subject: [PATCH 116/123] chore: update palette-mobile --- package.json | 2 +- yarn.lock | 30 ++++++------------------------ 2 files changed, 7 insertions(+), 25 deletions(-) diff --git a/package.json b/package.json index 0fb8ca5efa8..47980dce63e 100644 --- a/package.json +++ b/package.json @@ -109,7 +109,7 @@ "dependencies": { "@artsy/cohesion": "4.336.0", "@artsy/icons": "3.64.0", - "@artsy/palette-mobile": "22.4.0--canary.425.5208.0", + "@artsy/palette-mobile": "22.6.0--canary.425.5263.0", "@artsy/to-title-case": "1.2.0", "@braze/react-native-sdk": "16.1.0", "@d11/react-native-fast-image": "8.12.0", diff --git a/yarn.lock b/yarn.lock index c0c133e4213..e01bcbc8ba5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -54,29 +54,11 @@ __metadata: languageName: node linkType: hard -"@artsy/icons@npm:^3.49.0": - version: 3.50.0 - resolution: "@artsy/icons@npm:3.50.0" - peerDependencies: - react: ">=16.2.0" - react-native: ">=0.70.15" - react-native-svg: ">=15.0.0" - styled-components: ">=4" - styled-system: ^5 - peerDependenciesMeta: - react-native: - optional: true - react-native-svg: - optional: true - checksum: 10c0/c01cdc4e76aa6dfb77a8f5647b6e58d35b1464a2f19fba7a9d6251ed3f56fe6de7968ffa9bd8c46bd48a827c832be9fc90bce756b446ca4f9b12df3b0c21c1ee - languageName: node - linkType: hard - -"@artsy/palette-mobile@npm:22.4.0--canary.425.5208.0": - version: 22.4.0--canary.425.5208.0 - resolution: "@artsy/palette-mobile@npm:22.4.0--canary.425.5208.0" +"@artsy/palette-mobile@npm:22.6.0--canary.425.5263.0": + version: 22.6.0--canary.425.5263.0 + resolution: "@artsy/palette-mobile@npm:22.6.0--canary.425.5263.0" dependencies: - "@artsy/icons": "npm:^3.49.0" + "@artsy/icons": "npm:3.64.0" "@artsy/palette-tokens": "npm:7.0.0" "@d11/react-native-fast-image": "npm:8.12.0" "@react-spring/native": "npm:^10.0.3" @@ -101,7 +83,7 @@ __metadata: react-native-reanimated: "*" react-native-svg: "*" styled-components: ">= 5" - checksum: 10c0/63f190416d00ca8d47b75e209db620377f831c6312bd5199ae180d116aafec5154d81f92e261daf6b4fc0669f8d25c549b7c2568ecf08e17fe9899fee5539263 + checksum: 10c0/18453ac43ec9bf58fcd3cc5c3f1eb3501e4ba118055d90d4fdcfce2c3452ac64be1ef971d69425373c61bc377627eae4cbcb3c72338dfab8dd353cf4b1a87e19 languageName: node linkType: hard @@ -13165,7 +13147,7 @@ __metadata: dependencies: "@artsy/cohesion": "npm:4.336.0" "@artsy/icons": "npm:3.64.0" - "@artsy/palette-mobile": "npm:22.4.0--canary.425.5208.0" + "@artsy/palette-mobile": "npm:22.6.0--canary.425.5263.0" "@artsy/to-title-case": "npm:1.2.0" "@artsy/update-repo": "npm:0.7.0" "@babel/core": "npm:7.25.2" From 23f836f27137519bde9782cf3d17773c20dfbb4c Mon Sep 17 00:00:00 2001 From: George Date: Mon, 19 Jan 2026 15:23:31 +0100 Subject: [PATCH 117/123] build(deps): bumps sentry to latest version (#13164) --- .../AppDelegate+DeeplinkTimeout.m | 2 +- .../Util/Errors/ARNetworkErrorManager.m | 2 +- .../Util/Errors/ARSentryReporter.m | 2 +- ios/Podfile.lock | 10 +- package.json | 2 +- src/app/system/errorReporting/setupSentry.ts | 1 - yarn.lock | 205 +++++++++--------- 7 files changed, 106 insertions(+), 118 deletions(-) diff --git a/ios/Artsy/App/AppDelegateCategories/AppDelegate+DeeplinkTimeout.m b/ios/Artsy/App/AppDelegateCategories/AppDelegate+DeeplinkTimeout.m index 28a8af86ec4..25aa01b4e34 100644 --- a/ios/Artsy/App/AppDelegateCategories/AppDelegate+DeeplinkTimeout.m +++ b/ios/Artsy/App/AppDelegateCategories/AppDelegate+DeeplinkTimeout.m @@ -1,5 +1,5 @@ #import "AppDelegate+DeeplinkTimeout.h" -#import +@import Sentry; @implementation ARAppDelegateHelper (DeeplinkTimeout) diff --git a/ios/Artsy/View_Controllers/Util/Errors/ARNetworkErrorManager.m b/ios/Artsy/View_Controllers/Util/Errors/ARNetworkErrorManager.m index ba8ab42e6d5..05350588163 100644 --- a/ios/Artsy/View_Controllers/Util/Errors/ARNetworkErrorManager.m +++ b/ios/Artsy/View_Controllers/Util/Errors/ARNetworkErrorManager.m @@ -3,7 +3,7 @@ #import "ARTNativeScreenPresenterModule.h" #import -#import +@import Sentry; @interface ARNetworkErrorManager () @property (nonatomic, strong) UILabel *activeModalView; diff --git a/ios/Artsy/View_Controllers/Util/Errors/ARSentryReporter.m b/ios/Artsy/View_Controllers/Util/Errors/ARSentryReporter.m index 4812a5a9d05..10c29bdb36e 100644 --- a/ios/Artsy/View_Controllers/Util/Errors/ARSentryReporter.m +++ b/ios/Artsy/View_Controllers/Util/Errors/ARSentryReporter.m @@ -1,5 +1,5 @@ #import "ARSentryReporter.h" -#import +@import Sentry; @implementation ARSentryReporter diff --git a/ios/Podfile.lock b/ios/Podfile.lock index a5dbeb3badc..ff8c53cb2d5 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -3743,7 +3743,7 @@ PODS: - ReactCommon/turbomodule/core - SocketRocket - Yoga - - RNSentry (6.21.0): + - RNSentry (7.9.0): - boost - DoubleConversion - fast_float @@ -3770,7 +3770,7 @@ PODS: - ReactCodegen - ReactCommon/turbomodule/bridging - ReactCommon/turbomodule/core - - Sentry/HybridSDK (= 8.53.2) + - Sentry/HybridSDK (= 8.58.0) - SocketRocket - Yoga - RNShare (12.0.9): @@ -3870,7 +3870,7 @@ PODS: - segment-analytics-react-native (2.21.3): - React-Core - sovran-react-native - - Sentry/HybridSDK (8.53.2) + - Sentry/HybridSDK (8.58.0) - Sift (2.2.4) - sift-react-native (0.1.15): - React @@ -4754,14 +4754,14 @@ SPEC CHECKSUMS: RNReactNativeHapticFeedback: 7601768ee65ffc86fc93d7c30dd917031144ed3d RNReanimated: 9af1b9f7d221d1cc2f99d935bab08419cae7c1ce RNScreens: 0bbf16c074ae6bb1058a7bf2d1ae017f4306797c - RNSentry: ab7ba8bd678713c94762d2d3f2087d47105b6cf3 + RNSentry: 8dade4197bddd74024f1e8160669c0ee44dade5a RNShare: 1dba46787d6e5543e05655efaefa0e4bb98380d9 RNSVG: c5807de8e337c7a643f9bad2ecf48a15aefcc23c SDWebImage: 40b0b4053e36c660a764958bff99eed16610acbb SDWebImageAVIFCoder: afe194a084e851f70228e4be35ef651df0fc5c57 SDWebImageWebPCoder: e38c0a70396191361d60c092933e22c20d5b1380 segment-analytics-react-native: a0c29c75ede1989118b50cac96b9495ea5c91a1d - Sentry: 59993bffde4a1ac297ba6d268dc4bbce068d7c1b + Sentry: d587a8fe91ca13503ecd69a1905f3e8a0fcf61be Sift: 742454b5796a717df185f6dbae569e5dce357322 sift-react-native: 136f9b31b8324dbed1436bfbb0ec6b3b01c587e1 SocketRocket: d4aabe649be1e368d1318fdf28a022d714d65748 diff --git a/package.json b/package.json index 5f5cb605e06..1656ee4e4e3 100644 --- a/package.json +++ b/package.json @@ -140,7 +140,7 @@ "@segment/analytics-react-native": "2.21.3", "@segment/analytics-react-native-plugin-braze": "0.9.0", "@segment/sovran-react-native": "1.1.3", - "@sentry/react-native": "6.21.0", + "@sentry/react-native": "7.9.0", "@shopify/flash-list": "2.2.0", "@stripe/stripe-react-native": "0.50.3", "@styled-system/theme-get": "5.1.2", diff --git a/src/app/system/errorReporting/setupSentry.ts b/src/app/system/errorReporting/setupSentry.ts index a70eba136d7..f93b3857aca 100644 --- a/src/app/system/errorReporting/setupSentry.ts +++ b/src/app/system/errorReporting/setupSentry.ts @@ -64,7 +64,6 @@ export function setupSentry(props: SetupSentryProps = { debug: false }) { release: eigenSentryReleaseName(), dist: eigenSentryDist(), enableAutoSessionTracking: true, - autoSessionTracking: true, enableWatchdogTerminationTracking: false, attachStacktrace: true, tracesSampleRate: props.debug ? 1.0 : 0.05, diff --git a/yarn.lock b/yarn.lock index 6f4a04a7a30..fd676581456 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7252,132 +7252,132 @@ __metadata: languageName: node linkType: hard -"@sentry-internal/browser-utils@npm:8.55.0": - version: 8.55.0 - resolution: "@sentry-internal/browser-utils@npm:8.55.0" +"@sentry-internal/browser-utils@npm:10.34.0": + version: 10.34.0 + resolution: "@sentry-internal/browser-utils@npm:10.34.0" dependencies: - "@sentry/core": "npm:8.55.0" - checksum: 10c0/201eb94ee64a4dab058153c64dd4ce0af082f3c3bc84a5441cdadf344d9554a0a67c9d9dfdff720eb42de214d67d734d5bda25a050c2efd59c03f60562bb139a + "@sentry/core": "npm:10.34.0" + checksum: 10c0/dc30e293b0b5e53c76c7e25e123bb5890ef11eed319d3bc29d7698191c21ca73914791e28df58a2aef373846a5d5584fec33b6e8691542e8c59adafce78abb1c languageName: node linkType: hard -"@sentry-internal/feedback@npm:8.55.0": - version: 8.55.0 - resolution: "@sentry-internal/feedback@npm:8.55.0" +"@sentry-internal/feedback@npm:10.34.0": + version: 10.34.0 + resolution: "@sentry-internal/feedback@npm:10.34.0" dependencies: - "@sentry/core": "npm:8.55.0" - checksum: 10c0/2515c4eca6226e3df28a498f7f3771d7820556887bf8c06f2d5469c92474cf72ed81eaa0079f6bcf46905c54315e2631bb7b9ed7ed6741cf9b7f73a3f4875acc + "@sentry/core": "npm:10.34.0" + checksum: 10c0/78387e30255f598e7bb1108a23b520f2f0edbd0fa5acd1a85e14a10ab179cca7877a5baa5cda56ae54571fa1f558d1e554bb29777a87fb6869b3ab2454880f51 languageName: node linkType: hard -"@sentry-internal/replay-canvas@npm:8.55.0": - version: 8.55.0 - resolution: "@sentry-internal/replay-canvas@npm:8.55.0" +"@sentry-internal/replay-canvas@npm:10.34.0": + version: 10.34.0 + resolution: "@sentry-internal/replay-canvas@npm:10.34.0" dependencies: - "@sentry-internal/replay": "npm:8.55.0" - "@sentry/core": "npm:8.55.0" - checksum: 10c0/6f3c619ede1de47635035f74477dd5a11e5c2cac9d0906448a7fffb6dad1c5bd9a49a594fbc2a51ba3b1859a91f60e08ab6de2d9961ccbaa343af580f1d13fb1 + "@sentry-internal/replay": "npm:10.34.0" + "@sentry/core": "npm:10.34.0" + checksum: 10c0/ef616161b8d6a876824dffac50a28d5fb5db56fe87e72a07377cdc50ed521ed512b631aed05b7be119377b340dc6860439d76433e0f1898517cc1d92d6025ac7 languageName: node linkType: hard -"@sentry-internal/replay@npm:8.55.0": - version: 8.55.0 - resolution: "@sentry-internal/replay@npm:8.55.0" +"@sentry-internal/replay@npm:10.34.0": + version: 10.34.0 + resolution: "@sentry-internal/replay@npm:10.34.0" dependencies: - "@sentry-internal/browser-utils": "npm:8.55.0" - "@sentry/core": "npm:8.55.0" - checksum: 10c0/320fd5685c1e84c5feebaa88fc72afd0bd5189b95d690f8c24301cd8b13789431b2c1d28e3e5a93f669ca3b80cdc830e672723aa7a28ff8f0b901674ce0c0529 + "@sentry-internal/browser-utils": "npm:10.34.0" + "@sentry/core": "npm:10.34.0" + checksum: 10c0/a864af981489f7187f2e98dbc4cc4c27d59a0229a692c0e665d5dc23397f27a4bea5f5c82043febcf601594e8b171790a303c91c154a144c6ac155bc2c9b55dc languageName: node linkType: hard -"@sentry/babel-plugin-component-annotate@npm:4.2.0": - version: 4.2.0 - resolution: "@sentry/babel-plugin-component-annotate@npm:4.2.0" - checksum: 10c0/595a46e9436665371c668a7522ca59ee1b37bf72ac79d762de6e148f7ca2c6e7f67cee0cb07c3f42c35286401b0dd74e85e1a29368812befa8e66d3b35b83b50 +"@sentry/babel-plugin-component-annotate@npm:4.6.2": + version: 4.6.2 + resolution: "@sentry/babel-plugin-component-annotate@npm:4.6.2" + checksum: 10c0/0e171366c60b1b2ce5c49de20935f1c308fdacdb72cf8f8f32765ebb598c57129a8d952dacf647ae82cc75fb034c6188f9ee8e2d756769f17954aafe29955480 languageName: node linkType: hard -"@sentry/browser@npm:8.55.0": - version: 8.55.0 - resolution: "@sentry/browser@npm:8.55.0" +"@sentry/browser@npm:10.34.0": + version: 10.34.0 + resolution: "@sentry/browser@npm:10.34.0" dependencies: - "@sentry-internal/browser-utils": "npm:8.55.0" - "@sentry-internal/feedback": "npm:8.55.0" - "@sentry-internal/replay": "npm:8.55.0" - "@sentry-internal/replay-canvas": "npm:8.55.0" - "@sentry/core": "npm:8.55.0" - checksum: 10c0/a485de7385851c96ed4c2291d065594aeea2076b11b3b113f4866fdbff1522524abd97664f0d0b011e0eff6c4986a556f080bccfa1b770466c6afcb6122dfbaf + "@sentry-internal/browser-utils": "npm:10.34.0" + "@sentry-internal/feedback": "npm:10.34.0" + "@sentry-internal/replay": "npm:10.34.0" + "@sentry-internal/replay-canvas": "npm:10.34.0" + "@sentry/core": "npm:10.34.0" + checksum: 10c0/305fd4743decccb09d8294d4d3ff01fe2e431194905ee6e8f03f339f9137f29ea836a10b6a6c2226eb4d37656bd0136191830997c09bb86ee5f8dd8ba84d7bfb languageName: node linkType: hard -"@sentry/cli-darwin@npm:2.53.0": - version: 2.53.0 - resolution: "@sentry/cli-darwin@npm:2.53.0" +"@sentry/cli-darwin@npm:2.58.4": + version: 2.58.4 + resolution: "@sentry/cli-darwin@npm:2.58.4" conditions: os=darwin languageName: node linkType: hard -"@sentry/cli-linux-arm64@npm:2.53.0": - version: 2.53.0 - resolution: "@sentry/cli-linux-arm64@npm:2.53.0" +"@sentry/cli-linux-arm64@npm:2.58.4": + version: 2.58.4 + resolution: "@sentry/cli-linux-arm64@npm:2.58.4" conditions: (os=linux | os=freebsd | os=android) & cpu=arm64 languageName: node linkType: hard -"@sentry/cli-linux-arm@npm:2.53.0": - version: 2.53.0 - resolution: "@sentry/cli-linux-arm@npm:2.53.0" +"@sentry/cli-linux-arm@npm:2.58.4": + version: 2.58.4 + resolution: "@sentry/cli-linux-arm@npm:2.58.4" conditions: (os=linux | os=freebsd | os=android) & cpu=arm languageName: node linkType: hard -"@sentry/cli-linux-i686@npm:2.53.0": - version: 2.53.0 - resolution: "@sentry/cli-linux-i686@npm:2.53.0" +"@sentry/cli-linux-i686@npm:2.58.4": + version: 2.58.4 + resolution: "@sentry/cli-linux-i686@npm:2.58.4" conditions: (os=linux | os=freebsd | os=android) & (cpu=x86 | cpu=ia32) languageName: node linkType: hard -"@sentry/cli-linux-x64@npm:2.53.0": - version: 2.53.0 - resolution: "@sentry/cli-linux-x64@npm:2.53.0" +"@sentry/cli-linux-x64@npm:2.58.4": + version: 2.58.4 + resolution: "@sentry/cli-linux-x64@npm:2.58.4" conditions: (os=linux | os=freebsd | os=android) & cpu=x64 languageName: node linkType: hard -"@sentry/cli-win32-arm64@npm:2.53.0": - version: 2.53.0 - resolution: "@sentry/cli-win32-arm64@npm:2.53.0" +"@sentry/cli-win32-arm64@npm:2.58.4": + version: 2.58.4 + resolution: "@sentry/cli-win32-arm64@npm:2.58.4" conditions: os=win32 & cpu=arm64 languageName: node linkType: hard -"@sentry/cli-win32-i686@npm:2.53.0": - version: 2.53.0 - resolution: "@sentry/cli-win32-i686@npm:2.53.0" +"@sentry/cli-win32-i686@npm:2.58.4": + version: 2.58.4 + resolution: "@sentry/cli-win32-i686@npm:2.58.4" conditions: os=win32 & (cpu=x86 | cpu=ia32) languageName: node linkType: hard -"@sentry/cli-win32-x64@npm:2.53.0": - version: 2.53.0 - resolution: "@sentry/cli-win32-x64@npm:2.53.0" +"@sentry/cli-win32-x64@npm:2.58.4": + version: 2.58.4 + resolution: "@sentry/cli-win32-x64@npm:2.58.4" conditions: os=win32 & cpu=x64 languageName: node linkType: hard -"@sentry/cli@npm:2.53.0": - version: 2.53.0 - resolution: "@sentry/cli@npm:2.53.0" +"@sentry/cli@npm:2.58.4": + version: 2.58.4 + resolution: "@sentry/cli@npm:2.58.4" dependencies: - "@sentry/cli-darwin": "npm:2.53.0" - "@sentry/cli-linux-arm": "npm:2.53.0" - "@sentry/cli-linux-arm64": "npm:2.53.0" - "@sentry/cli-linux-i686": "npm:2.53.0" - "@sentry/cli-linux-x64": "npm:2.53.0" - "@sentry/cli-win32-arm64": "npm:2.53.0" - "@sentry/cli-win32-i686": "npm:2.53.0" - "@sentry/cli-win32-x64": "npm:2.53.0" + "@sentry/cli-darwin": "npm:2.58.4" + "@sentry/cli-linux-arm": "npm:2.58.4" + "@sentry/cli-linux-arm64": "npm:2.58.4" + "@sentry/cli-linux-i686": "npm:2.58.4" + "@sentry/cli-linux-x64": "npm:2.58.4" + "@sentry/cli-win32-arm64": "npm:2.58.4" + "@sentry/cli-win32-i686": "npm:2.58.4" + "@sentry/cli-win32-x64": "npm:2.58.4" https-proxy-agent: "npm:^5.0.0" node-fetch: "npm:^2.6.7" progress: "npm:^2.0.3" @@ -7402,28 +7402,27 @@ __metadata: optional: true bin: sentry-cli: bin/sentry-cli - checksum: 10c0/ea6acf44d336feb3911b07ddac4cde96a0d86cd72eb96be75ad531efa2ba713190eea02f92526b7014289dac85ede58e93575672236a8cc60695e6ad1c604df6 + checksum: 10c0/9adcc71bf2968f89e1c27c5a24c308a35281eb610bc4736b18f2396e37e9699e1e10f1be95db431e7ff939f3378fbad8634adf0d28fb2b74c74fa81a05070f10 languageName: node linkType: hard -"@sentry/core@npm:8.55.0": - version: 8.55.0 - resolution: "@sentry/core@npm:8.55.0" - checksum: 10c0/51c1768f0bd940a060787b402dba9df3347c918ea4c0fdc300d45c37703ebbf6f7adee9fff332cfd6b23372b33c46e6d2f31a04227762d490aaddc14773894a0 +"@sentry/core@npm:10.34.0": + version: 10.34.0 + resolution: "@sentry/core@npm:10.34.0" + checksum: 10c0/e30e7743b8fbf0887f1cd01f865d9ccdc4e0d9754ebeae44f4849773cef4263eaa9dee71256429e614a86e0d39fe924a9e3d9535e9a6900bb4d190789bf83fc8 languageName: node linkType: hard -"@sentry/react-native@npm:6.21.0": - version: 6.21.0 - resolution: "@sentry/react-native@npm:6.21.0" +"@sentry/react-native@npm:7.9.0": + version: 7.9.0 + resolution: "@sentry/react-native@npm:7.9.0" dependencies: - "@sentry/babel-plugin-component-annotate": "npm:4.2.0" - "@sentry/browser": "npm:8.55.0" - "@sentry/cli": "npm:2.53.0" - "@sentry/core": "npm:8.55.0" - "@sentry/react": "npm:8.55.0" - "@sentry/types": "npm:8.55.0" - "@sentry/utils": "npm:8.55.0" + "@sentry/babel-plugin-component-annotate": "npm:4.6.2" + "@sentry/browser": "npm:10.34.0" + "@sentry/cli": "npm:2.58.4" + "@sentry/core": "npm:10.34.0" + "@sentry/react": "npm:10.34.0" + "@sentry/types": "npm:10.34.0" peerDependencies: expo: ">=49.0.0" react: ">=17.0.0" @@ -7433,38 +7432,28 @@ __metadata: optional: true bin: sentry-expo-upload-sourcemaps: scripts/expo-upload-sourcemaps.js - checksum: 10c0/542e69feb99cc22a598568992dab1a8bd6cebebfb3060e66013efa2852cac944591ba7096254603583f980ba5c8818399b1b59096941d8bbe225ac51ee18f427 + checksum: 10c0/b12aa1f82ae09dab552a931a31f7502a7d4d0bd826ce5aadae5d9d78273bba129d5ba14922fa92ca93817e9153b261e2b84709a7e19d0204109bb8ac461f39c5 languageName: node linkType: hard -"@sentry/react@npm:8.55.0": - version: 8.55.0 - resolution: "@sentry/react@npm:8.55.0" +"@sentry/react@npm:10.34.0": + version: 10.34.0 + resolution: "@sentry/react@npm:10.34.0" dependencies: - "@sentry/browser": "npm:8.55.0" - "@sentry/core": "npm:8.55.0" - hoist-non-react-statics: "npm:^3.3.2" + "@sentry/browser": "npm:10.34.0" + "@sentry/core": "npm:10.34.0" peerDependencies: react: ^16.14.0 || 17.x || 18.x || 19.x - checksum: 10c0/09dafee92cb62d3aea5c4503b6d1ad79e293c0e4ad59a60b7700b9d99b18e8e8d6a47e18ed26278d7aa64adbf64c0797c2d096287eeb122a379f5b23b35f597e - languageName: node - linkType: hard - -"@sentry/types@npm:8.55.0": - version: 8.55.0 - resolution: "@sentry/types@npm:8.55.0" - dependencies: - "@sentry/core": "npm:8.55.0" - checksum: 10c0/fc0814eea9a4fd3b8acee9d8c79bd42b1193692ceaba332663f2ae781d96fbd46fc49a7b1253606f98d96487c2efda1113c2db0dff4ff6d11b8b8a879beecf7f + checksum: 10c0/84384a210b7632e4e65f66e9dc2331316fd1800d72a674f2c3e965561fec233e1d69bf21d2b9110fd419fe90d1fe4a029d25f49afd2932ca6df9aefd44428779 languageName: node linkType: hard -"@sentry/utils@npm:8.55.0": - version: 8.55.0 - resolution: "@sentry/utils@npm:8.55.0" +"@sentry/types@npm:10.34.0": + version: 10.34.0 + resolution: "@sentry/types@npm:10.34.0" dependencies: - "@sentry/core": "npm:8.55.0" - checksum: 10c0/5ec4d7c3901036a4f15192e407d8c112951283cbc530bca1a1ae5ff5231b4141b415629079f1bcf8798f7fad1e9ca5ea365b022b606f4913a4c084a21cbbab3d + "@sentry/core": "npm:10.34.0" + checksum: 10c0/bb9b140cafae75cbf7a1b529f59ff1c339320f6bb776026378e6b8a97d075f441f64d398181a7f1f95f09bb96f3c8a98e21c238ede8800cca2a805c01102c136 languageName: node linkType: hard @@ -13202,7 +13191,7 @@ __metadata: "@segment/analytics-react-native": "npm:2.21.3" "@segment/analytics-react-native-plugin-braze": "npm:0.9.0" "@segment/sovran-react-native": "npm:1.1.3" - "@sentry/react-native": "npm:6.21.0" + "@sentry/react-native": "npm:7.9.0" "@shopify/flash-list": "npm:2.2.0" "@stripe/stripe-react-native": "npm:0.50.3" "@styled-system/theme-get": "npm:5.1.2" From 0325d4702959fbd621aa6595885847e976bc0225 Mon Sep 17 00:00:00 2001 From: Mounir Dhahri Date: Tue, 3 Feb 2026 12:17:42 +0100 Subject: [PATCH 118/123] chore: use FlashList --- .../Artist/ArtistAbout/ArtistAbout.tsx | 103 +++++++++++------- .../Artist/ArtistInsights/ArtistInsights.tsx | 2 +- .../Artist/ArtistInsights/MarketStats.tsx | 2 +- .../ArtQuizExploreArtists.tsx | 3 +- .../ArtQuizTrendingArtists.tsx | 3 +- .../ArtQuizTrendingCollections.tsx | 3 +- .../Scenes/Fair/Components/FairExhibitors.tsx | 6 +- 7 files changed, 72 insertions(+), 50 deletions(-) diff --git a/src/app/Components/Artist/ArtistAbout/ArtistAbout.tsx b/src/app/Components/Artist/ArtistAbout/ArtistAbout.tsx index 2439b6a16ae..c7be510b710 100644 --- a/src/app/Components/Artist/ArtistAbout/ArtistAbout.tsx +++ b/src/app/Components/Artist/ArtistAbout/ArtistAbout.tsx @@ -1,5 +1,5 @@ import { ContextModule, OwnerType } from "@artsy/cohesion" -import { Flex, Join, Spacer, Tabs } from "@artsy/palette-mobile" +import { Flex, Spacer, Tabs, useSpace } from "@artsy/palette-mobile" import { ArtistAbout_artist$data } from "__generated__/ArtistAbout_artist.graphql" import { Articles } from "app/Components/Artist/Articles/Articles" import { ArtistAboutEmpty } from "app/Components/Artist/ArtistAbout/ArtistAboutEmpty" @@ -9,6 +9,7 @@ import { RelatedArtistsRail } from "app/Components/Artist/RelatedArtistsRail" import { SectionTitle } from "app/Components/SectionTitle" import { ArtistSeriesMoreSeriesFragmentContainer } from "app/Scenes/ArtistSeries/ArtistSeriesMoreSeries" import { extractNodes } from "app/utils/extractNodes" +import { compact } from "lodash" import { createFragmentContainer, graphql } from "react-relay" import { ArtistAboutShowsFragmentContainer } from "./ArtistAboutShows" import { ArtistCareerHighlights } from "./ArtistCareerHighlights" @@ -18,6 +19,8 @@ interface Props { } export const ArtistAbout: React.FC = ({ artist }) => { + const space = useSpace() + const articles = extractNodes(artist.articlesConnection) const relatedArtists = extractNodes(artist.related?.artistsConnection) const relatedGenes = extractNodes(artist.related?.genes) @@ -38,45 +41,69 @@ export const ArtistAbout: React.FC = ({ artist }) => { hasRelatedArtists || hasRelatedGenes - return ( - - {isDisplayable ? ( + const data = compact([ + hasBiography && { + key: "biography", + content: ( <> - - }> - {!!hasBiography && ( - <> - - - - - - - )} - {!!hasInsights && } - {!!hasArtistSeries && ( - - )} - {!!hasArticles && } - {!!hasShows && } - - {!!hasRelatedArtists && } - {!!hasRelatedGenes && } - - + + + + + - ) : ( - - )} - + ), + }, + + !!hasInsights && { + key: "insights", + content: , + }, + + !!hasArtistSeries && { + key: "artistSeries", + content: ( + + ), + }, + + !!hasArticles && { + key: "articles", + content: , + }, + + !!hasShows && { + key: "shows", + content: , + }, + + !!hasRelatedArtists && { + key: "relatedArtists", + content: , + }, + !!hasRelatedGenes && { + key: "relatedGenes", + content: , + }, + ]) + + return ( + item?.content} + keyExtractor={(item) => item?.key} + ItemSeparatorComponent={() => } + contentContainerStyle={{ paddingHorizontal: 0, paddingVertical: space(4) }} + ListEmptyComponent={() => } + /> ) } diff --git a/src/app/Components/Artist/ArtistInsights/ArtistInsights.tsx b/src/app/Components/Artist/ArtistInsights/ArtistInsights.tsx index 9b853ae7938..370d445d5d9 100644 --- a/src/app/Components/Artist/ArtistInsights/ArtistInsights.tsx +++ b/src/app/Components/Artist/ArtistInsights/ArtistInsights.tsx @@ -102,7 +102,7 @@ export const ArtistInsights: React.FC = (props) => { return ( - = ({ priceInsightsConnection }) => return ( <> - + diff --git a/src/app/Scenes/ArtQuiz/ArtQuizResults/ArtQuizResultsTabs/ArtQuizExploreArtists.tsx b/src/app/Scenes/ArtQuiz/ArtQuizResults/ArtQuizResultsTabs/ArtQuizExploreArtists.tsx index a614cc19caa..eecdb33e81f 100644 --- a/src/app/Scenes/ArtQuiz/ArtQuizResults/ArtQuizResultsTabs/ArtQuizExploreArtists.tsx +++ b/src/app/Scenes/ArtQuiz/ArtQuizResults/ArtQuizResultsTabs/ArtQuizExploreArtists.tsx @@ -16,10 +16,9 @@ export const ArtQuizExploreArtists = ({ ) return ( - { return }} diff --git a/src/app/Scenes/ArtQuiz/ArtQuizResults/ArtQuizResultsTabs/ArtQuizTrendingArtists.tsx b/src/app/Scenes/ArtQuiz/ArtQuizResults/ArtQuizResultsTabs/ArtQuizTrendingArtists.tsx index 60fee32d685..284277318f5 100644 --- a/src/app/Scenes/ArtQuiz/ArtQuizResults/ArtQuizResultsTabs/ArtQuizTrendingArtists.tsx +++ b/src/app/Scenes/ArtQuiz/ArtQuizResults/ArtQuizResultsTabs/ArtQuizTrendingArtists.tsx @@ -19,9 +19,8 @@ export const ArtQuizTrendingArtists = ({ const artists = extractNodes(viewerData?.curatedTrendingArtists) return ( - String(item?.internalID || index)} renderItem={({ item, index }) => { return diff --git a/src/app/Scenes/ArtQuiz/ArtQuizResults/ArtQuizResultsTabs/ArtQuizTrendingCollections.tsx b/src/app/Scenes/ArtQuiz/ArtQuizResults/ArtQuizResultsTabs/ArtQuizTrendingCollections.tsx index 5aeadf66c93..d7ea5bedc1b 100644 --- a/src/app/Scenes/ArtQuiz/ArtQuizResults/ArtQuizResultsTabs/ArtQuizTrendingCollections.tsx +++ b/src/app/Scenes/ArtQuiz/ArtQuizResults/ArtQuizResultsTabs/ArtQuizTrendingCollections.tsx @@ -18,9 +18,8 @@ export const ArtQuizTrendingCollections: React.FC String(item?.internalID || index)} renderItem={({ item, index }) => { return diff --git a/src/app/Scenes/Fair/Components/FairExhibitors.tsx b/src/app/Scenes/Fair/Components/FairExhibitors.tsx index be872cd9f3a..ebcf5100010 100644 --- a/src/app/Scenes/Fair/Components/FairExhibitors.tsx +++ b/src/app/Scenes/Fair/Components/FairExhibitors.tsx @@ -1,4 +1,5 @@ import { Box, Flex, Tabs, useSpace } from "@artsy/palette-mobile" +import { ListRenderItem } from "@shopify/flash-list" import { FairExhibitors_fair$data } from "__generated__/FairExhibitors_fair.graphql" import Spinner from "app/Components/Spinner" import { FAIR2_EXHIBITORS_PAGE_SIZE } from "app/Components/constants" @@ -8,7 +9,6 @@ import { extractNodes } from "app/utils/extractNodes" import { ExtractNodeType } from "app/utils/relayHelpers" import { renderWithPlaceholder } from "app/utils/renderWithPlaceholder" import React, { useCallback } from "react" -import { ListRenderItem } from "react-native" import { createPaginationContainer, graphql, QueryRenderer, RelayPaginationProp } from "react-relay" import { FairExhibitorRailQueryRenderer } from "./FairExhibitorRail" @@ -48,7 +48,7 @@ const FairExhibitors: React.FC = ({ fair, relay }) => { const keyExtractor = (item: FairShowArtworks) => String(item?.id) return ( - = ({ fair, relay }) => { ) : null } - // We want to limit the number of loaded windows to 5 because the items are pretty heavy - windowSize={5} // We are slowing down the scrolling intentionally because the screen is too heavy and scrolling // too fast leads to dropped frames decelerationRate={0.995} From 69b8fd3e60b44ed8e040bafc4849a0719376fd02 Mon Sep 17 00:00:00 2001 From: Mounir Dhahri Date: Tue, 3 Feb 2026 14:03:16 +0100 Subject: [PATCH 119/123] chore: separate queries --- .../Artist/ArtistAbout/ArtistAbout.tsx | 166 ++++++++++++------ .../__tests__/ArtistAbout.tests.tsx | 4 +- .../Artist/ArtistInsights/ArtistInsights.tsx | 105 ++++++++--- .../ArtistInsightsAuctionResults.tsx | 9 +- .../__tests__/ArtistInsights.tests.tsx | 4 +- src/app/Scenes/Artist/Artist.tsx | 66 ++++--- 6 files changed, 237 insertions(+), 117 deletions(-) diff --git a/src/app/Components/Artist/ArtistAbout/ArtistAbout.tsx b/src/app/Components/Artist/ArtistAbout/ArtistAbout.tsx index c7be510b710..ed2b15eb1a7 100644 --- a/src/app/Components/Artist/ArtistAbout/ArtistAbout.tsx +++ b/src/app/Components/Artist/ArtistAbout/ArtistAbout.tsx @@ -1,36 +1,40 @@ import { ContextModule, OwnerType } from "@artsy/cohesion" -import { Flex, Spacer, Tabs, useSpace } from "@artsy/palette-mobile" -import { ArtistAbout_artist$data } from "__generated__/ArtistAbout_artist.graphql" +import { Flex, Spacer, Spinner, Tabs, useSpace } from "@artsy/palette-mobile" +import { ArtistAboutQuery } from "__generated__/ArtistAboutQuery.graphql" +import { ArtistAbout_artist$key } from "__generated__/ArtistAbout_artist.graphql" import { Articles } from "app/Components/Artist/Articles/Articles" import { ArtistAboutEmpty } from "app/Components/Artist/ArtistAbout/ArtistAboutEmpty" import { ArtistAboutRelatedGenes } from "app/Components/Artist/ArtistAbout/ArtistAboutRelatedGenes" import { Biography, MAX_WIDTH_BIO } from "app/Components/Artist/Biography" import { RelatedArtistsRail } from "app/Components/Artist/RelatedArtistsRail" +import { LoadFailureView, LoadFailureViewProps } from "app/Components/LoadFailureView" import { SectionTitle } from "app/Components/SectionTitle" import { ArtistSeriesMoreSeriesFragmentContainer } from "app/Scenes/ArtistSeries/ArtistSeriesMoreSeries" import { extractNodes } from "app/utils/extractNodes" +import { withSuspense } from "app/utils/hooks/withSuspense" import { compact } from "lodash" -import { createFragmentContainer, graphql } from "react-relay" +import { graphql, useFragment, useLazyLoadQuery } from "react-relay" import { ArtistAboutShowsFragmentContainer } from "./ArtistAboutShows" import { ArtistCareerHighlights } from "./ArtistCareerHighlights" -interface Props { - artist: ArtistAbout_artist$data +interface ArtistAboutProps { + artist: ArtistAbout_artist$key } -export const ArtistAbout: React.FC = ({ artist }) => { +export const ArtistAbout: React.FC = ({ artist: artistProp }) => { const space = useSpace() + const artist = useFragment(artistAboutFragment, artistProp) const articles = extractNodes(artist.articlesConnection) const relatedArtists = extractNodes(artist.related?.artistsConnection) const relatedGenes = extractNodes(artist.related?.genes) const hasInsights = artist.hasArtistInsights.length > 0 - const hasArtistSeries = artist.hasArtistSeriesConnection?.totalCount ?? 0 > 0 - const hasShows = artist.hasArtistShows?.totalCount ?? 0 > 0 + const hasArtistSeries = (artist.hasArtistSeriesConnection?.totalCount ?? 0) > 0 + const hasShows = (artist.hasArtistShows?.totalCount ?? 0) > 0 const hasBiography = !!artist.hasBiographyBlurb?.text - const hasArticles = artist.counts?.articles ?? 0 > 0 - const hasRelatedArtists = artist.counts?.relatedArtists ?? 0 > 0 + const hasArticles = (artist.counts?.articles ?? 0) > 0 + const hasRelatedArtists = (artist.counts?.relatedArtists ?? 0) > 0 const hasRelatedGenes = relatedGenes.length > 0 const isDisplayable = @@ -107,56 +111,112 @@ export const ArtistAbout: React.FC = ({ artist }) => { ) } -export const ArtistAboutContainer = createFragmentContainer(ArtistAbout, { - artist: graphql` - fragment ArtistAbout_artist on Artist { - hasArtistSeriesConnection: artistSeriesConnection(first: 1) { - totalCount - } - hasBiographyBlurb: biographyBlurb(format: PLAIN, partnerBio: false) { - text - } - internalID - hasArtistInsights: insights { - entities - } - hasArtistShows: showsConnection(first: 1, sort: END_AT_ASC, status: "running") { - totalCount - } - slug - ...Biography_artist - ...ArtistSeriesMoreSeries_artist - ...Articles_artist - ...ArtistAboutShows_artist - ...ArtistCareerHighlights_artist - ...RelatedArtistsRailCell_artist - counts { - articles - relatedArtists - } - related { - artistsConnection(first: 12) { - edges { - node { - ...RelatedArtistsRail_artists - } - } - } - genes { - edges { - node { - ...ArtistAboutRelatedGenes_genes - } +const artistAboutFragment = graphql` + fragment ArtistAbout_artist on Artist { + hasArtistSeriesConnection: artistSeriesConnection(first: 1) { + totalCount + } + hasBiographyBlurb: biographyBlurb(format: PLAIN, partnerBio: false) { + text + } + internalID + hasArtistInsights: insights { + entities + } + hasArtistShows: showsConnection(first: 1, sort: END_AT_ASC, status: "running") { + totalCount + } + slug + ...Biography_artist + ...ArtistSeriesMoreSeries_artist + ...Articles_artist + ...ArtistAboutShows_artist + ...ArtistCareerHighlights_artist + ...RelatedArtistsRailCell_artist + counts { + articles + relatedArtists + } + related { + artistsConnection(first: 12) { + edges { + node { + ...RelatedArtistsRail_artists } } } - articlesConnection(first: 5) { + genes { edges { node { - ...Articles_articles + ...ArtistAboutRelatedGenes_genes } } } } - `, + articlesConnection(first: 5) { + edges { + node { + ...Articles_articles + } + } + } + } +` + +export const artistAboutQuery = graphql` + query ArtistAboutQuery($artistID: String!) { + artist(id: $artistID) { + ...ArtistAbout_artist + } + } +` + +interface ArtistAboutQueryRendererProps { + artistID: string +} + +export const ArtistAboutQueryRenderer = withSuspense({ + Component: ({ artistID }) => { + const data = useLazyLoadQuery(artistAboutQuery, { artistID }) + + if (!data.artist) { + return null + } + + return + }, + LoadingFallback: () => , + ErrorFallback: (fallbackProps) => , }) + +const ArtistAboutPlaceholder: React.FC = () => { + const space = useSpace() + + return ( + + + + + + ) +} + +const ArtistAboutError: React.FC = (fallbackProps) => { + const space = useSpace() + + return ( + + + + ) +} diff --git a/src/app/Components/Artist/ArtistAbout/__tests__/ArtistAbout.tests.tsx b/src/app/Components/Artist/ArtistAbout/__tests__/ArtistAbout.tests.tsx index 4119235a98d..021014a0893 100644 --- a/src/app/Components/Artist/ArtistAbout/__tests__/ArtistAbout.tests.tsx +++ b/src/app/Components/Artist/ArtistAbout/__tests__/ArtistAbout.tests.tsx @@ -1,6 +1,6 @@ import { screen } from "@testing-library/react-native" import { ArtistAboutTestsQuery } from "__generated__/ArtistAboutTestsQuery.graphql" -import { ArtistAboutContainer } from "app/Components/Artist/ArtistAbout/ArtistAbout" +import { ArtistAbout } from "app/Components/Artist/ArtistAbout/ArtistAbout" import { ArtistAboutShowsFragmentContainer } from "app/Components/Artist/ArtistAbout/ArtistAboutShows" import { Biography } from "app/Components/Artist/Biography" import { setupTestWrapper } from "app/utils/tests/setupTestWrapper" @@ -8,7 +8,7 @@ import { graphql } from "react-relay" describe("ArtistAbout", () => { const { renderWithRelay } = setupTestWrapper({ - Component: ({ artist }) => , + Component: ({ artist }) => , query: graphql` query ArtistAboutTestsQuery($artistID: String!) @relay_test_operation { artist(id: $artistID) { diff --git a/src/app/Components/Artist/ArtistInsights/ArtistInsights.tsx b/src/app/Components/Artist/ArtistInsights/ArtistInsights.tsx index 370d445d5d9..1e495977954 100644 --- a/src/app/Components/Artist/ArtistInsights/ArtistInsights.tsx +++ b/src/app/Components/Artist/ArtistInsights/ArtistInsights.tsx @@ -1,6 +1,7 @@ import { OwnerType } from "@artsy/cohesion" -import { Tabs, useSpace } from "@artsy/palette-mobile" -import { ArtistInsights_artist$data } from "__generated__/ArtistInsights_artist.graphql" +import { Flex, Spinner, Tabs, useSpace } from "@artsy/palette-mobile" +import { ArtistInsightsQuery } from "__generated__/ArtistInsightsQuery.graphql" +import { ArtistInsights_artist$key } from "__generated__/ArtistInsights_artist.graphql" import { ARTIST_HEADER_HEIGHT } from "app/Components/Artist/ArtistHeader" import { AnimatedArtworkFilterButton, @@ -9,27 +10,32 @@ import { } from "app/Components/ArtworkFilter" import { FilterArray } from "app/Components/ArtworkFilter/ArtworkFilterHelpers" import { ArtworkFiltersStoreProvider } from "app/Components/ArtworkFilter/ArtworkFilterStore" +import { LoadFailureView, LoadFailureViewProps } from "app/Components/LoadFailureView" +import { getRelayEnvironment } from "app/system/relay/defaultEnvironment" +import { withSuspense } from "app/utils/hooks/withSuspense" import { Schema } from "app/utils/track" import { screen } from "app/utils/track/helpers" import React, { useCallback, useEffect, useMemo, useRef, useState } from "react" import { LayoutChangeEvent, NativeScrollEvent, NativeSyntheticEvent } from "react-native" import { useFocusedTab } from "react-native-collapsible-tab-view" -import { RelayProp, createFragmentContainer, graphql } from "react-relay" +import { graphql, useFragment, useLazyLoadQuery } from "react-relay" import { useTracking } from "react-tracking" import { ArtistInsightsAuctionResultsPaginationContainer } from "./ArtistInsightsAuctionResults" import { MarketStatsQueryRenderer } from "./MarketStats" interface ArtistInsightsProps { - artist: ArtistInsights_artist$data - relay: RelayProp + artist: ArtistInsights_artist$key initialFilters?: FilterArray } const SCROLL_UP_TO_SHOW_THRESHOLD = 150 const FILTER_BUTTON_OFFSET = 50 -export const ArtistInsights: React.FC = (props) => { - const { artist, relay, initialFilters } = props +export const ArtistInsights: React.FC = ({ + artist: artistProp, + initialFilters, +}) => { + const artist = useFragment(artistInsightsFragment, artistProp) const space = useSpace() const tracking = useTracking() @@ -71,7 +77,7 @@ export const ArtistInsights: React.FC = (props) => { Component: () => ( ), }, @@ -89,7 +95,7 @@ export const ArtistInsights: React.FC = (props) => { ), }, ], - [artist, relay.environment, scrollToTop, initialFilters, auctionResultsYCoordinate.current] + [artist, scrollToTop, initialFilters, auctionResultsYCoordinate.current] ) const focusedTab = useFocusedTab() @@ -131,21 +137,78 @@ export const ArtistInsights: React.FC = (props) => { ) } -export const ArtistInsightsFragmentContainer = createFragmentContainer(ArtistInsights, { - artist: graphql` - fragment ArtistInsights_artist on Artist { - ...ArtistInsightsAuctionResults_artist - name - id - internalID - slug - statuses { - auctionLots - } +const artistInsightsFragment = graphql` + fragment ArtistInsights_artist on Artist { + ...ArtistInsightsAuctionResults_artist + name + id + internalID + slug + statuses { + auctionLots } - `, + } +` + +export const artistInsightsQuery = graphql` + query ArtistInsightsQuery($artistID: String!) { + artist(id: $artistID) { + ...ArtistInsights_artist + } + } +` + +interface ArtistInsightsQueryRendererProps { + artistID: string + initialFilters?: FilterArray +} + +export const ArtistInsightsQueryRenderer = withSuspense({ + Component: ({ artistID, initialFilters }) => { + const data = useLazyLoadQuery(artistInsightsQuery, { artistID }) + + if (!data.artist) { + return null + } + + return + }, + LoadingFallback: () => , + ErrorFallback: (fallbackProps) => , }) +const ArtistInsightsPlaceholder: React.FC = () => { + const space = useSpace() + + return ( + + + + + + ) +} + +const ArtistInsightsError: React.FC = (fallbackProps) => { + const space = useSpace() + + return ( + + + + ) +} + export const tracks = { openFilter: (id: string, slug: string) => { return { diff --git a/src/app/Components/Artist/ArtistInsights/ArtistInsightsAuctionResults.tsx b/src/app/Components/Artist/ArtistInsights/ArtistInsightsAuctionResults.tsx index 47be33e6f8b..dbf048696cd 100644 --- a/src/app/Components/Artist/ArtistInsights/ArtistInsightsAuctionResults.tsx +++ b/src/app/Components/Artist/ArtistInsights/ArtistInsightsAuctionResults.tsx @@ -1,5 +1,5 @@ import { ActionType, ContextModule, OwnerType, TappedInfoBubble } from "@artsy/cohesion" -import { Box, bullet, Flex, Separator, Spacer, Text } from "@artsy/palette-mobile" +import { Box, bullet, Flex, Separator, Spacer, Text, useSpace } from "@artsy/palette-mobile" import { ArtistInsightsAuctionResults_artist$data } from "__generated__/ArtistInsightsAuctionResults_artist.graphql" import { ArtistInsightsEmpty } from "app/Components/Artist/ArtistInsights/ArtistsInsightsEmpty" import { @@ -34,6 +34,7 @@ import { } from "react-native" import { createPaginationContainer, graphql, RelayPaginationProp } from "react-relay" import { useTracking } from "react-tracking" +import { space } from "styled-system" interface Props { artist: ArtistInsightsAuctionResults_artist$data @@ -52,6 +53,7 @@ const ArtistInsightsAuctionResults: React.FC = ({ onLayout, onScrollEndDragChange, }) => { + const space = useSpace() const tracking = useTracking() const { width: screenWidth, height: screenHeight } = useScreenDimensions() @@ -281,8 +283,9 @@ const ArtistInsightsAuctionResults: React.FC = ({ )} onScrollEndDrag={onScrollEndDragChange} + nestedScrollEnabled ItemSeparatorComponent={AuctionResultListSeparator} - style={{ width: screenWidth, left: -20 }} + style={{ width: screenWidth, left: -space(2), flexGrow: 1 }} onEndReached={loadMoreAuctionResults} ListFooterComponent={() => loadingMoreData ? ( @@ -291,7 +294,7 @@ const ArtistInsightsAuctionResults: React.FC = ({ ) : null } - contentContainerStyle={{ paddingBottom: 20 }} + contentContainerStyle={{ paddingBottom: space(2) }} /> ) : ( diff --git a/src/app/Components/Artist/ArtistInsights/__tests__/ArtistInsights.tests.tsx b/src/app/Components/Artist/ArtistInsights/__tests__/ArtistInsights.tests.tsx index d34c8a99a0a..e91cc0c78bc 100644 --- a/src/app/Components/Artist/ArtistInsights/__tests__/ArtistInsights.tests.tsx +++ b/src/app/Components/Artist/ArtistInsights/__tests__/ArtistInsights.tests.tsx @@ -1,5 +1,5 @@ import { ArtistInsightsTestsQuery } from "__generated__/ArtistInsightsTestsQuery.graphql" -import { ArtistInsightsFragmentContainer } from "app/Components/Artist/ArtistInsights/ArtistInsights" +import { ArtistInsights } from "app/Components/Artist/ArtistInsights/ArtistInsights" import { ArtistInsightsAuctionResultsPaginationContainer } from "app/Components/Artist/ArtistInsights/ArtistInsightsAuctionResults" import { flushPromiseQueue } from "app/utils/tests/flushPromiseQueue" import { renderWithWrappersLEGACY } from "app/utils/tests/renderWithWrappers" @@ -40,7 +40,7 @@ describe("ArtistInsights", () => { if (!props?.artist) { return null } - return + return }} /> ) diff --git a/src/app/Scenes/Artist/Artist.tsx b/src/app/Scenes/Artist/Artist.tsx index 987a77934bc..3c60627b67f 100644 --- a/src/app/Scenes/Artist/Artist.tsx +++ b/src/app/Scenes/Artist/Artist.tsx @@ -12,11 +12,17 @@ import { useRoute } from "@react-navigation/native" import { ArtistAboveTheFoldQuery } from "__generated__/ArtistAboveTheFoldQuery.graphql" import { FilterArtworksInput } from "__generated__/ArtistArtworks_artistRefetch.graphql" import { ArtistBelowTheFoldQuery } from "__generated__/ArtistBelowTheFoldQuery.graphql" -import { ArtistAboutContainer } from "app/Components/Artist/ArtistAbout/ArtistAbout" +import { + artistAboutQuery, + ArtistAboutQueryRenderer, +} from "app/Components/Artist/ArtistAbout/ArtistAbout" import { ArtistArtworksQueryRenderer } from "app/Components/Artist/ArtistArtworks/ArtistArtworks" import { ArtistHeader, useArtistHeaderImageDimensions } from "app/Components/Artist/ArtistHeader" import { ArtistHeaderNavRightQueryRenderer } from "app/Components/Artist/ArtistHeaderNavRight" -import { ArtistInsightsFragmentContainer } from "app/Components/Artist/ArtistInsights/ArtistInsights" +import { + artistInsightsQuery, + ArtistInsightsQueryRenderer, +} from "app/Components/Artist/ArtistInsights/ArtistInsights" import { FilterArray, filterArtworksParams, @@ -36,9 +42,9 @@ import { goBack } from "app/system/navigation/navigate" import { getRelayEnvironment } from "app/system/relay/defaultEnvironment" import { AboveTheFoldQueryRenderer } from "app/utils/AboveTheFoldQueryRenderer" import { KeyboardAvoidingContainer } from "app/utils/keyboard/KeyboardAvoidingContainer" +import { prefetchQuery } from "app/utils/queryPrefetching" import { ProvideScreenTracking, Schema } from "app/utils/track" import React, { useCallback, useEffect, useMemo } from "react" -import { ActivityIndicator, View } from "react-native" import { Environment, graphql } from "react-relay" const INITIAL_TAB = "Artworks" @@ -52,7 +58,6 @@ interface RouteParams { interface ArtistProps { artistAboveTheFold: NonNullable - artistBelowTheFold?: ArtistBelowTheFoldQuery["response"]["artist"] auctionResultsInitialFilters?: FilterArray environment?: Environment fetchCriteriaError: Error | null @@ -65,7 +70,6 @@ interface ArtistProps { export const Artist: React.FC = ({ artistAboveTheFold, - artistBelowTheFold, auctionResultsInitialFilters, fetchCriteriaError, initialTab = INITIAL_TAB, @@ -87,6 +91,18 @@ export const Artist: React.FC = ({ } }, [fetchCriteriaError]) + // Prefetch the About and Insights tab queries on mount + useEffect(() => { + prefetchQuery({ + query: artistAboutQuery, + variables: { artistID: artistAboveTheFold.internalID }, + }) + prefetchQuery({ + query: artistInsightsQuery, + variables: { artistID: artistAboveTheFold.internalID }, + }) + }, [artistAboveTheFold.internalID]) + const renderBelowTheHeaderComponent = useCallback( () => , [artistAboveTheFold] @@ -132,24 +148,16 @@ export const Artist: React.FC = ({ - {artistBelowTheFold ? ( - - ) : ( - - )} + - {artistBelowTheFold ? ( - - ) : ( - - )} + @@ -256,8 +264,9 @@ export const ArtistQueryRenderer: React.FC = ({ query: graphql` query ArtistBelowTheFoldQuery($artistID: String!) @cacheable { artist(id: $artistID) { - ...ArtistAbout_artist - ...ArtistInsights_artist + # Below-the-fold tabs (Insights, About) now have their own query renderers + # This query is kept minimal for backward compatibility + id } } `, @@ -270,14 +279,13 @@ export const ArtistQueryRenderer: React.FC = ({ renderPlaceholder: () => ( ), - renderComponent: ({ above, below }) => { + renderComponent: ({ above }) => { if (!above.artist) { throw new Error("no artist data") } return ( = ({ ) } -/** - * Be lazy and just have a simple loading spinner for the below-the-fold tabs - * (as opposed to nice fancy placeholder screens) since people are really - * unlikely to tap into them quick enough to see the loading state - * @param param0 - */ -const LoadingPage: React.FC<{}> = ({}) => { - return ( - - - - ) -} - const ArtistSkeleton: React.FC<{ verifiedRepresentativesCount?: number }> = ({ verifiedRepresentativesCount = 0, }) => { From 4c423b287b0f57febdd0839330011d65ef03d1a2 Mon Sep 17 00:00:00 2001 From: Mounir Dhahri Date: Tue, 3 Feb 2026 14:36:50 +0100 Subject: [PATCH 120/123] chore: improve artist screen architecture --- .../ArtistInsightsAuctionResults.tsx | 1 - .../__tests__/ArtistInsights.tests.tsx | 87 ++---- src/app/Scenes/Artist/Artist.tsx | 270 +++++++++--------- .../Scenes/Artist/__tests__/Artist.tests.tsx | 29 +- .../__tests__/ArtistSavedSearch.tests.tsx | 46 +-- .../cacheHeaderMiddlewareHelpers.tests.ts | 4 +- 6 files changed, 190 insertions(+), 247 deletions(-) diff --git a/src/app/Components/Artist/ArtistInsights/ArtistInsightsAuctionResults.tsx b/src/app/Components/Artist/ArtistInsights/ArtistInsightsAuctionResults.tsx index dbf048696cd..ff9df634ee5 100644 --- a/src/app/Components/Artist/ArtistInsights/ArtistInsightsAuctionResults.tsx +++ b/src/app/Components/Artist/ArtistInsights/ArtistInsightsAuctionResults.tsx @@ -34,7 +34,6 @@ import { } from "react-native" import { createPaginationContainer, graphql, RelayPaginationProp } from "react-relay" import { useTracking } from "react-tracking" -import { space } from "styled-system" interface Props { artist: ArtistInsightsAuctionResults_artist$data diff --git a/src/app/Components/Artist/ArtistInsights/__tests__/ArtistInsights.tests.tsx b/src/app/Components/Artist/ArtistInsights/__tests__/ArtistInsights.tests.tsx index e91cc0c78bc..794e369e8c1 100644 --- a/src/app/Components/Artist/ArtistInsights/__tests__/ArtistInsights.tests.tsx +++ b/src/app/Components/Artist/ArtistInsights/__tests__/ArtistInsights.tests.tsx @@ -1,13 +1,10 @@ +import { screen } from "@testing-library/react-native" import { ArtistInsightsTestsQuery } from "__generated__/ArtistInsightsTestsQuery.graphql" import { ArtistInsights } from "app/Components/Artist/ArtistInsights/ArtistInsights" import { ArtistInsightsAuctionResultsPaginationContainer } from "app/Components/Artist/ArtistInsights/ArtistInsightsAuctionResults" -import { flushPromiseQueue } from "app/utils/tests/flushPromiseQueue" -import { renderWithWrappersLEGACY } from "app/utils/tests/renderWithWrappers" -import { resolveMostRecentRelayOperation } from "app/utils/tests/resolveMostRecentRelayOperation" -import { graphql, QueryRenderer } from "react-relay" -import { act } from "react-test-renderer" +import { setupTestWrapper } from "app/utils/tests/setupTestWrapper" +import { graphql } from "react-relay" import { useTracking } from "react-tracking" -import { createMockEnvironment } from "relay-test-utils" jest.mock("react-native-collapsible-tab-view", () => { const getMockCollapsibleTabs = @@ -22,65 +19,43 @@ jest.mock("react-native-collapsible-tab-view", () => { const trackEvent = useTracking().trackEvent describe("ArtistInsights", () => { - let mockEnvironment: ReturnType - beforeEach(() => (mockEnvironment = createMockEnvironment())) - - const TestRenderer = () => ( - - environment={mockEnvironment} - query={graphql` - query ArtistInsightsTestsQuery @relay_test_operation { - artist(id: "some-id") { - ...ArtistInsights_artist - } - } - `} - variables={{}} - render={({ props }) => { - if (!props?.artist) { - return null + const { renderWithRelay } = setupTestWrapper({ + Component: ({ artist }) => , + query: graphql` + query ArtistInsightsTestsQuery @relay_test_operation { + artist(id: "some-id") { + ...ArtistInsights_artist } - return - }} - /> - ) - - it("renders list auction results", async () => { - const view = renderWithWrappersLEGACY() + } + `, + }) - await act(async () => { - mockEnvironment.mock.resolveMostRecentOperation(() => ({ - data: { - artist: { - internalID: "artist-id", - slug: "artist-slug", - statuses: { auctionLots: true }, - }, - }, - })) - await flushPromiseQueue() + it("renders list auction results", () => { + renderWithRelay({ + Artist: () => ({ + internalID: "artist-id", + slug: "artist-slug", + statuses: { auctionLots: true }, + }), }) - resolveMostRecentRelayOperation(mockEnvironment) - - // now safe to assert - const auctionResults = await view.root.findAllByType( - ArtistInsightsAuctionResultsPaginationContainer - ) - expect(auctionResults.length).toEqual(1) + expect( + screen.UNSAFE_queryAllByType(ArtistInsightsAuctionResultsPaginationContainer) + ).toHaveLength(1) }) - it("tracks an auction page view when artist insights is current tab", async () => { - renderWithWrappersLEGACY() - - resolveMostRecentRelayOperation(mockEnvironment) - - await flushPromiseQueue() + it("tracks an auction page view when artist insights is current tab", () => { + renderWithRelay({ + Artist: () => ({ + internalID: "artist-id", + slug: "artist-slug", + }), + }) expect(trackEvent).toHaveBeenCalledWith({ action: "screen", - context_screen_owner_id: "internalID-1", - context_screen_owner_slug: "slug-1", + context_screen_owner_id: "artist-id", + context_screen_owner_slug: "artist-slug", context_screen_owner_type: "artistAuctionResults", }) }) diff --git a/src/app/Scenes/Artist/Artist.tsx b/src/app/Scenes/Artist/Artist.tsx index 3c60627b67f..9be03ad9be5 100644 --- a/src/app/Scenes/Artist/Artist.tsx +++ b/src/app/Scenes/Artist/Artist.tsx @@ -9,9 +9,8 @@ import { Tabs, } from "@artsy/palette-mobile" import { useRoute } from "@react-navigation/native" -import { ArtistAboveTheFoldQuery } from "__generated__/ArtistAboveTheFoldQuery.graphql" import { FilterArtworksInput } from "__generated__/ArtistArtworks_artistRefetch.graphql" -import { ArtistBelowTheFoldQuery } from "__generated__/ArtistBelowTheFoldQuery.graphql" +import { ArtistQuery } from "__generated__/ArtistQuery.graphql" import { artistAboutQuery, ArtistAboutQueryRenderer, @@ -39,13 +38,12 @@ import { usePopoverMessage } from "app/Components/PopoverMessage/popoverMessageH import { SkeletonPill } from "app/Components/SkeletonPill/SkeletonPill" import { SearchCriteriaQueryRenderer } from "app/Scenes/Artist/SearchCriteria" import { goBack } from "app/system/navigation/navigate" -import { getRelayEnvironment } from "app/system/relay/defaultEnvironment" -import { AboveTheFoldQueryRenderer } from "app/utils/AboveTheFoldQueryRenderer" +import { withSuspense } from "app/utils/hooks/withSuspense" import { KeyboardAvoidingContainer } from "app/utils/keyboard/KeyboardAvoidingContainer" import { prefetchQuery } from "app/utils/queryPrefetching" import { ProvideScreenTracking, Schema } from "app/utils/track" import React, { useCallback, useEffect, useMemo } from "react" -import { Environment, graphql } from "react-relay" +import { graphql, useLazyLoadQuery } from "react-relay" const INITIAL_TAB = "Artworks" @@ -57,9 +55,8 @@ interface RouteParams { } interface ArtistProps { - artistAboveTheFold: NonNullable + artist: NonNullable auctionResultsInitialFilters?: FilterArray - environment?: Environment fetchCriteriaError: Error | null initialTab?: string predefinedFilters?: FilterArray @@ -69,7 +66,7 @@ interface ArtistProps { } export const Artist: React.FC = ({ - artistAboveTheFold, + artist, auctionResultsInitialFilters, fetchCriteriaError, initialTab = INITIAL_TAB, @@ -95,30 +92,30 @@ export const Artist: React.FC = ({ useEffect(() => { prefetchQuery({ query: artistAboutQuery, - variables: { artistID: artistAboveTheFold.internalID }, + variables: { artistID: artist.internalID }, }) prefetchQuery({ query: artistInsightsQuery, - variables: { artistID: artistAboveTheFold.internalID }, + variables: { artistID: artist.internalID }, }) - }, [artistAboveTheFold.internalID]) + }, [artist.internalID]) const renderBelowTheHeaderComponent = useCallback( - () => , - [artistAboveTheFold] + () => , + [artist] ) const artistHeaderRight = useMemo(() => { - return - }, [artistAboveTheFold]) + return + }, [artist]) return ( @@ -126,7 +123,7 @@ export const Artist: React.FC = ({ = ({ = ({ @@ -157,7 +154,7 @@ export const Artist: React.FC = ({ - + @@ -171,7 +168,6 @@ interface ArtistQueryRendererProps { alertID?: string artistID: string categories?: string[] - environment?: Environment initialTab?: string predefinedFilters?: FilterArray scrollToArtworksGrid?: boolean @@ -182,7 +178,7 @@ interface ArtistQueryRendererProps { } export const ArtistScreenQuery = graphql` - query ArtistAboveTheFoldQuery($artistID: String!) @cacheable { + query ArtistQuery($artistID: String!) @cacheable { artist(id: $artistID) { ...ArtistHeader_artist id @@ -201,113 +197,6 @@ export const defaultArtistVariables = { }), } -export const ArtistQueryRenderer: React.FC = ({ - alertID, - artistID, - categories, - environment, - initialTab, - predefinedFilters, - scrollToArtworksGrid = false, - search_criteria_id, - sizes, - verifiedRepresentativesCount, -}) => { - // exctact filter params from the query string. This is needed when - // the screen is opened via deeplink (/artist/kaws?attribution_class=..., for instance) - // to make sure the filters are applied correctly - const route = useRoute() - const routeParams = (route?.params as RouteParams)?.props || {} - const filters: FilterArray = [ - ...(predefinedFilters || []), - ...getFilterParamsFromRouteParams(routeParams), - ] - - return ( - ( - - ), - renderComponent: (searchCriteriaProps) => { - const { savedSearchCriteria, fetchCriteriaError } = searchCriteriaProps - const predefinedFilterParams = filterArtworksParams(filters ?? [], "artwork") - - let initialArtworksInput = { - ...defaultArtistVariables.input, - ...predefinedFilterParams, - } - - if (savedSearchCriteria) { - const preparedCriteria = getOnlyFilledSearchCriteriaValues(savedSearchCriteria) - - initialArtworksInput = { - ...initialArtworksInput, - ...preparedCriteria, - sort: "-published_at", - } - } - const input = prepareFilterArtworksParamsForInput(initialArtworksInput) - - return ( - - environment={environment || getRelayEnvironment()} - above={{ - query: ArtistScreenQuery, - variables: { - artistID, - }, - }} - below={{ - query: graphql` - query ArtistBelowTheFoldQuery($artistID: String!) @cacheable { - artist(id: $artistID) { - # Below-the-fold tabs (Insights, About) now have their own query renderers - # This query is kept minimal for backward compatibility - id - } - } - `, - variables: { artistID }, - }} - fallback={({ error }) => ( - - )} - render={{ - renderPlaceholder: () => ( - - ), - renderComponent: ({ above }) => { - if (!above.artist) { - throw new Error("no artist data") - } - return ( - - ) - }, - }} - /> - ) - }, - }} - /> - ) -} - const ArtistSkeleton: React.FC<{ verifiedRepresentativesCount?: number }> = ({ verifiedRepresentativesCount = 0, }) => { @@ -359,3 +248,124 @@ const ArtistSkeleton: React.FC<{ verifiedRepresentativesCount?: number }> = ({ ) } + +interface ArtistScreenProps { + artistID: string + categories?: string[] + initialTab?: string + predefinedFilters?: FilterArray + scrollToArtworksGrid: boolean + sizes?: string[] + searchCriteria: SearchCriteriaAttributes | null + fetchCriteriaError: Error | null + filters: FilterArray + verifiedRepresentativesCount?: number +} + +const ArtistScreen = withSuspense({ + Component: ({ + artistID, + categories, + initialTab, + predefinedFilters, + scrollToArtworksGrid, + sizes, + searchCriteria, + fetchCriteriaError, + filters, + }) => { + const data = useLazyLoadQuery(ArtistScreenQuery, { artistID }) + + if (!data.artist) { + return null + } + + const predefinedFilterParams = filterArtworksParams(filters ?? [], "artwork") + + let initialArtworksInput = { + ...defaultArtistVariables.input, + ...predefinedFilterParams, + } + + if (searchCriteria) { + const preparedCriteria = getOnlyFilledSearchCriteriaValues(searchCriteria) + + initialArtworksInput = { + ...initialArtworksInput, + ...preparedCriteria, + sort: "-published_at", + } + } + + const input = prepareFilterArtworksParamsForInput(initialArtworksInput) + + return ( + + ) + }, + LoadingFallback: ArtistSkeleton, + ErrorFallback: ({ error }) => ( + + ), +}) + +export const ArtistQueryRenderer: React.FC = ({ + alertID, + artistID, + categories, + initialTab, + predefinedFilters, + scrollToArtworksGrid = false, + search_criteria_id, + sizes, + verifiedRepresentativesCount, +}) => { + // extract filter params from the query string. This is needed when + // the screen is opened via deeplink (/artist/kaws?attribution_class=..., for instance) + // to make sure the filters are applied correctly + const route = useRoute() + const routeParams = (route?.params as RouteParams)?.props || {} + const filters: FilterArray = [ + ...(predefinedFilters || []), + ...getFilterParamsFromRouteParams(routeParams), + ] + + return ( + ( + + ), + renderComponent: ({ savedSearchCriteria, fetchCriteriaError }) => { + return ( + + ) + }, + }} + /> + ) +} diff --git a/src/app/Scenes/Artist/__tests__/Artist.tests.tsx b/src/app/Scenes/Artist/__tests__/Artist.tests.tsx index 2dab21c8fe1..db7f103dd63 100644 --- a/src/app/Scenes/Artist/__tests__/Artist.tests.tsx +++ b/src/app/Scenes/Artist/__tests__/Artist.tests.tsx @@ -1,6 +1,5 @@ import { act, screen } from "@testing-library/react-native" import { ArtistQueryRenderer } from "app/Scenes/Artist/Artist" -import { getRelayEnvironment } from "app/system/relay/defaultEnvironment" import { flushPromiseQueue } from "app/utils/tests/flushPromiseQueue" import { renderWithHookWrappersTL } from "app/utils/tests/renderWithWrappers" import { postEventToProviders } from "app/utils/track/providers" @@ -10,11 +9,7 @@ import { MockResolvers } from "relay-test-utils/lib/RelayMockPayloadGenerator" jest.unmock("react-tracking") -type ArtistQueries = - | "SearchCriteriaQuery" - | "ArtistAboveTheFoldQuery" - | "ArtistBelowTheFoldQuery" - | "MarketStatsQuery" +type ArtistQueries = "SearchCriteriaQuery" | "ArtistQuery" | "MarketStatsQuery" describe("Artist", () => { let mockEnvironment: ReturnType @@ -33,7 +28,7 @@ describe("Artist", () => { mockEnvironment.mock.resolveMostRecentOperation((operation) => { const result = MockPayloadGenerator.generate(operation, { ID({ path }) { - // need to make sure artist id is stable between above-and-below-the-fold queries to avoid cache weirdness + // need to make sure artist id is stable between queries to avoid cache weirdness if (isEqual(path, ["artist", "id"])) { return "artist-id" } @@ -46,31 +41,25 @@ describe("Artist", () => { } const TestWrapper = (props: Record) => ( - + ) it("should render all tabs", async () => { - renderWithHookWrappersTL(, getRelayEnvironment(), { includeNavigation: true }) + renderWithHookWrappersTL(, mockEnvironment, { includeNavigation: true }) - mockMostRecentOperation("ArtistAboveTheFoldQuery") - mockMostRecentOperation("ArtistBelowTheFoldQuery", { - ArtistInsight() { - return { entities: ["test"] } - }, - }) - mockMostRecentOperation("MarketStatsQuery") + mockMostRecentOperation("ArtistQuery") await flushPromiseQueue() expect(screen.getByText("Artworks")).toBeTruthy() - expect(screen.getByText("Insights")).toBeTruthy() - expect(screen.getByText("Overview")).toBeTruthy() + expect(screen.getByText("Auction Results")).toBeTruthy() + expect(screen.getByText("About")).toBeTruthy() }) it("tracks a page view", async () => { - renderWithHookWrappersTL(, getRelayEnvironment(), { includeNavigation: true }) + renderWithHookWrappersTL(, mockEnvironment, { includeNavigation: true }) - mockMostRecentOperation("ArtistAboveTheFoldQuery") + mockMostRecentOperation("ArtistQuery") await flushPromiseQueue() diff --git a/src/app/Scenes/Artist/__tests__/ArtistSavedSearch.tests.tsx b/src/app/Scenes/Artist/__tests__/ArtistSavedSearch.tests.tsx index 5aaa3ffed34..23a357ee10c 100644 --- a/src/app/Scenes/Artist/__tests__/ArtistSavedSearch.tests.tsx +++ b/src/app/Scenes/Artist/__tests__/ArtistSavedSearch.tests.tsx @@ -36,8 +36,7 @@ jest.mock("@react-navigation/native", () => { }) type ArtistQueries = - | "ArtistAboveTheFoldQuery" - | "ArtistBelowTheFoldQuery" + | "ArtistQuery" | "SearchCriteriaQuery" | "ArtistArtworksQuery" | "MarketStatsQuery" @@ -66,7 +65,7 @@ describe("Saved search banner on artist screen", () => { environment.mock.resolveMostRecentOperation((operation) => { const result = MockPayloadGenerator.generate(operation, { ID({ path }) { - // need to make sure artist id is stable between above-and-below-the-fold queries to avoid cache weirdness + // need to make sure artist id is stable between queries to avoid cache weirdness if (isEqual(path, ["artist", "id"])) { return "artist-id" } @@ -80,23 +79,16 @@ describe("Saved search banner on artist screen", () => { const getTree = (alertID?: string) => renderWithHookWrappersTL( - + , + environment ) it("should convert the criteria attributes to the filter params format", async () => { getTree("search-criteria-id") mockMostRecentOperation("SearchCriteriaQuery", MockSearchCriteriaQuery) - mockMostRecentOperation("ArtistAboveTheFoldQuery", MockArtistAboveTheFoldQuery) - mockMostRecentOperation("ArtistBelowTheFoldQuery", MockArtistBelowTheFoldQuery) - mockMostRecentOperation("MarketStatsQuery", MockMarketStatsQuery) + mockMostRecentOperation("ArtistQuery", MockArtistQuery) mockMostRecentOperation("ArtistArtworksQuery", MockArtistArtworksQuery) - mockMostRecentOperation("ArtistInsightsAuctionResultsQuery") await flushPromiseQueue() @@ -111,7 +103,7 @@ describe("Saved search banner on artist screen", () => { getTree("something") rejectMostRecentRelayOperation(environment, new Error()) - mockMostRecentOperation("ArtistAboveTheFoldQuery", MockArtistAboveTheFoldQuery) + mockMostRecentOperation("ArtistQuery", MockArtistQuery) await flushPromiseQueue() @@ -123,9 +115,7 @@ describe("Saved search banner on artist screen", () => { getTree("search-criteria-id") mockMostRecentOperation("SearchCriteriaQuery", MockSearchCriteriaQuery) - mockMostRecentOperation("ArtistAboveTheFoldQuery", MockArtistAboveTheFoldQuery) - mockMostRecentOperation("ArtistBelowTheFoldQuery", MockArtistBelowTheFoldQuery) - mockMostRecentOperation("MarketStatsQuery", MockMarketStatsQuery) + mockMostRecentOperation("ArtistQuery", MockArtistQuery) mockMostRecentOperation("ArtistArtworksQuery", MockArtistArtworksQuery) await flushPromiseQueue() @@ -153,7 +143,7 @@ const MockSearchCriteriaQuery: MockResolvers = { }, } -const MockArtistAboveTheFoldQuery: MockResolvers = { +const MockArtistQuery: MockResolvers = { Artist() { return { has_metadata: true, @@ -166,16 +156,6 @@ const MockArtistAboveTheFoldQuery: MockResolvers = { }, } -const MockArtistBelowTheFoldQuery: MockResolvers = { - Artist() { - return { - articles: [], - biographyBlurb: { text: "Artist biography" }, - insights: [], - } - }, -} - const MockArtistArtworksQuery: MockResolvers = { Artist() { return { @@ -252,13 +232,3 @@ const MockArtistArtworksQuery: MockResolvers = { } }, } - -const MockMarketStatsQuery: MockResolvers = { - Artist() { - return { - priceInsightsConnection: { - edges: [], - }, - } - }, -} diff --git a/src/app/system/relay/helpers/__tests__/cacheHeaderMiddlewareHelpers.tests.ts b/src/app/system/relay/helpers/__tests__/cacheHeaderMiddlewareHelpers.tests.ts index 026783fc6e4..a7054dc1946 100644 --- a/src/app/system/relay/helpers/__tests__/cacheHeaderMiddlewareHelpers.tests.ts +++ b/src/app/system/relay/helpers/__tests__/cacheHeaderMiddlewareHelpers.tests.ts @@ -41,7 +41,7 @@ describe(isRequestCacheable, () => { cacheConfig: {}, controller: {}, fetchOpts: { - body: '{"query":"query ArtistAboveTheFoldQuery(\\n $artistID: String!\\n $input: FilterArtworksInput\\n) @cacheable {\\n artist(id: $artistID) @principalField {\\n ...ArtistHeader_artist\\n ...ArtistArtworks_artist_2VV6jB\\n ...ArtistHeaderNavRight_artist\\n id\\n internalID\\n slug\\n href\\n name\\n coverArtwork {\\n image {\\n url(version: \\"larger\\")\\n }\\n id\\n }\\n }\\n}\\n\\nfragment ArtistArtworksFilterHeader_artist on Artist {\\n internalID\\n slug\\n}\\n\\nfragment ArtistArtworks_artist_2VV6jB on Artist {\\n ...ArtistArtworksFilterHeader_artist\\n id\\n slug\\n name\\n internalID\\n counts {\\n artworks\\n }\\n aggregations: filterArtworksConnection(first: 0, aggregations: [ARTIST_SERIES, COLOR, DIMENSION_RANGE, LOCATION_CITY, MAJOR_PERIOD, MATERIALS_TERMS, MEDIUM, PARTNER, PRICE_RANGE, SIMPLE_PRICE_HISTOGRAM]) {\\n aggregations {\\n slice\\n counts {\\n count\\n name\\n value\\n }\\n }\\n id\\n }\\n artworks: filterArtworksConnection(first: 10, input: $input) {\\n edges {\\n node {\\n id\\n slug\\n image(includeAll: false) {\\n aspectRatio\\n }\\n ...ArtworkGridItem_artwork_FOvjt\\n __typename\\n }\\n cursor\\n }\\n pageInfo {\\n endCursor\\n hasNextPage\\n }\\n id\\n }\\n statuses {\\n artworks\\n }\\n}\\n\\nfragment ArtistHeaderNavRight_artist on Artist {\\n isFollowed\\n counts {\\n follows\\n }\\n ...useFollowArtist_artist\\n}\\n\\nfragment ArtistHeader_artist on Artist {\\n slug\\n birthday\\n coverArtwork {\\n title\\n image {\\n blurhash\\n url(version: \\"larger\\")\\n }\\n id\\n }\\n internalID\\n name\\n nationality\\n verifiedRepresentatives {\\n partner {\\n internalID\\n name\\n href\\n profile {\\n icon {\\n url(version: \\"square140\\")\\n }\\n id\\n }\\n id\\n }\\n id\\n }\\n}\\n\\nfragment ArtworkAuctionTimer_collectorSignals on CollectorSignals {\\n auction {\\n onlineBiddingExtended\\n lotClosesAt\\n registrationEndsAt\\n }\\n}\\n\\nfragment ArtworkGridItem_artwork_FOvjt on Artwork {\\n ...CreateArtworkAlertModal_artwork\\n ...ContextMenuArtwork_artwork_XFsn3\\n availability\\n title\\n date\\n saleMessage\\n slug\\n artists(shallow: true) {\\n name\\n id\\n }\\n widthCm\\n heightCm\\n isHangable\\n id\\n internalID\\n isAcquireable\\n isBiddable\\n isInquireable\\n isOfferable\\n isSaved\\n isUnlisted\\n artistNames\\n href\\n sale {\\n isAuction\\n isClosed\\n displayTimelyAt\\n cascadingEndTimeIntervalMinutes\\n extendedBiddingPeriodMinutes\\n extendedBiddingIntervalMinutes\\n endAt\\n startAt\\n id\\n }\\n saleArtwork {\\n counts {\\n bidderPositions\\n }\\n formattedEndDateTime\\n currentBid {\\n display\\n }\\n lotID\\n lotLabel\\n endAt\\n extendedBiddingEndAt\\n id\\n }\\n partner {\\n name\\n id\\n }\\n image(includeAll: false) {\\n blurhash\\n url(version: \\"large\\")\\n aspectRatio\\n resized {\\n src\\n srcSet\\n width\\n height\\n }\\n }\\n collectorSignals {\\n partnerOffer {\\n isAvailable\\n endAt\\n priceWithDiscount {\\n display\\n }\\n id\\n }\\n auction {\\n lotWatcherCount\\n bidCount\\n liveBiddingStarted\\n lotClosesAt\\n }\\n primaryLabel\\n ...ArtworkAuctionTimer_collectorSignals\\n ...ArtworkSocialSignal_collectorSignals\\n }\\n ...useSaveArtworkToArtworkLists_artwork\\n}\\n\\nfragment ArtworkSocialSignal_collectorSignals on CollectorSignals {\\n increasedInterest\\n curatorsPick\\n}\\n\\nfragment ContextMenuArtworkPreviewCardImage_artwork_XFsn3 on Artwork {\\n contextMenuImage: image {\\n url(version: \\"large\\")\\n resized {\\n src\\n srcSet\\n width\\n height\\n }\\n }\\n}\\n\\nfragment ContextMenuArtworkPreviewCard_artwork_XFsn3 on Artwork {\\n ...ContextMenuArtworkPreviewCardImage_artwork_XFsn3\\n artistNames\\n date\\n title\\n sale {\\n isAuction\\n isClosed\\n endAt\\n id\\n }\\n saleMessage\\n saleArtwork {\\n counts {\\n bidderPositions\\n }\\n currentBid {\\n display\\n }\\n endAt\\n extendedBiddingEndAt\\n id\\n }\\n partner {\\n name\\n id\\n }\\n}\\n\\nfragment ContextMenuArtwork_artwork_XFsn3 on Artwork {\\n ...ContextMenuArtworkPreviewCard_artwork_XFsn3\\n ...useSaveArtworkToArtworkLists_artwork\\n title\\n href\\n artistNames\\n artists(shallow: true) {\\n name\\n id\\n }\\n slug\\n internalID\\n id\\n isHangable\\n contextMenuImage: image {\\n url(version: \\"large\\")\\n }\\n image(includeAll: false) {\\n url(version: \\"large\\")\\n }\\n sale {\\n isAuction\\n isClosed\\n id\\n }\\n heightCm\\n widthCm\\n}\\n\\nfragment CreateArtworkAlertModal_artwork on Artwork {\\n title\\n internalID\\n slug\\n isEligibleToCreateAlert\\n artistsArray: artists {\\n internalID\\n name\\n id\\n }\\n attributionClass {\\n internalID\\n id\\n }\\n mediumType {\\n filterGene {\\n slug\\n name\\n id\\n }\\n }\\n}\\n\\nfragment useFollowArtist_artist on Artist {\\n id\\n internalID\\n slug\\n isFollowed\\n counts {\\n follows\\n }\\n}\\n\\nfragment useSaveArtworkToArtworkLists_artwork on Artwork {\\n id\\n internalID\\n isInAuction\\n isSaved\\n slug\\n title\\n date\\n artistNames\\n preview: image {\\n url(version: \\"square\\")\\n }\\n customArtworkLists: collectionsConnection(first: 0, default: false, saves: true) {\\n totalCount\\n }\\n}\\n","variables":{"artistID":"nobuyoshi-araki","input":{"acquireable":false,"atAuction":false,"includeArtworksByFollowedArtists":false,"inquireableOnly":false,"medium":"*","offerable":false,"priceRange":"*-*","sort":"-decayed_merch"}}}', + body: '{"query":"query ArtistQuery(\\n $artistID: String!\\n $input: FilterArtworksInput\\n) @cacheable {\\n artist(id: $artistID) @principalField {\\n ...ArtistHeader_artist\\n ...ArtistArtworks_artist_2VV6jB\\n ...ArtistHeaderNavRight_artist\\n id\\n internalID\\n slug\\n href\\n name\\n coverArtwork {\\n image {\\n url(version: \\"larger\\")\\n }\\n id\\n }\\n }\\n}\\n\\nfragment ArtistArtworksFilterHeader_artist on Artist {\\n internalID\\n slug\\n}\\n\\nfragment ArtistArtworks_artist_2VV6jB on Artist {\\n ...ArtistArtworksFilterHeader_artist\\n id\\n slug\\n name\\n internalID\\n counts {\\n artworks\\n }\\n aggregations: filterArtworksConnection(first: 0, aggregations: [ARTIST_SERIES, COLOR, DIMENSION_RANGE, LOCATION_CITY, MAJOR_PERIOD, MATERIALS_TERMS, MEDIUM, PARTNER, PRICE_RANGE, SIMPLE_PRICE_HISTOGRAM]) {\\n aggregations {\\n slice\\n counts {\\n count\\n name\\n value\\n }\\n }\\n id\\n }\\n artworks: filterArtworksConnection(first: 10, input: $input) {\\n edges {\\n node {\\n id\\n slug\\n image(includeAll: false) {\\n aspectRatio\\n }\\n ...ArtworkGridItem_artwork_FOvjt\\n __typename\\n }\\n cursor\\n }\\n pageInfo {\\n endCursor\\n hasNextPage\\n }\\n id\\n }\\n statuses {\\n artworks\\n }\\n}\\n\\nfragment ArtistHeaderNavRight_artist on Artist {\\n isFollowed\\n counts {\\n follows\\n }\\n ...useFollowArtist_artist\\n}\\n\\nfragment ArtistHeader_artist on Artist {\\n slug\\n birthday\\n coverArtwork {\\n title\\n image {\\n blurhash\\n url(version: \\"larger\\")\\n }\\n id\\n }\\n internalID\\n name\\n nationality\\n verifiedRepresentatives {\\n partner {\\n internalID\\n name\\n href\\n profile {\\n icon {\\n url(version: \\"square140\\")\\n }\\n id\\n }\\n id\\n }\\n id\\n }\\n}\\n\\nfragment ArtworkAuctionTimer_collectorSignals on CollectorSignals {\\n auction {\\n onlineBiddingExtended\\n lotClosesAt\\n registrationEndsAt\\n }\\n}\\n\\nfragment ArtworkGridItem_artwork_FOvjt on Artwork {\\n ...CreateArtworkAlertModal_artwork\\n ...ContextMenuArtwork_artwork_XFsn3\\n availability\\n title\\n date\\n saleMessage\\n slug\\n artists(shallow: true) {\\n name\\n id\\n }\\n widthCm\\n heightCm\\n isHangable\\n id\\n internalID\\n isAcquireable\\n isBiddable\\n isInquireable\\n isOfferable\\n isSaved\\n isUnlisted\\n artistNames\\n href\\n sale {\\n isAuction\\n isClosed\\n displayTimelyAt\\n cascadingEndTimeIntervalMinutes\\n extendedBiddingPeriodMinutes\\n extendedBiddingIntervalMinutes\\n endAt\\n startAt\\n id\\n }\\n saleArtwork {\\n counts {\\n bidderPositions\\n }\\n formattedEndDateTime\\n currentBid {\\n display\\n }\\n lotID\\n lotLabel\\n endAt\\n extendedBiddingEndAt\\n id\\n }\\n partner {\\n name\\n id\\n }\\n image(includeAll: false) {\\n blurhash\\n url(version: \\"large\\")\\n aspectRatio\\n resized {\\n src\\n srcSet\\n width\\n height\\n }\\n }\\n collectorSignals {\\n partnerOffer {\\n isAvailable\\n endAt\\n priceWithDiscount {\\n display\\n }\\n id\\n }\\n auction {\\n lotWatcherCount\\n bidCount\\n liveBiddingStarted\\n lotClosesAt\\n }\\n primaryLabel\\n ...ArtworkAuctionTimer_collectorSignals\\n ...ArtworkSocialSignal_collectorSignals\\n }\\n ...useSaveArtworkToArtworkLists_artwork\\n}\\n\\nfragment ArtworkSocialSignal_collectorSignals on CollectorSignals {\\n increasedInterest\\n curatorsPick\\n}\\n\\nfragment ContextMenuArtworkPreviewCardImage_artwork_XFsn3 on Artwork {\\n contextMenuImage: image {\\n url(version: \\"large\\")\\n resized {\\n src\\n srcSet\\n width\\n height\\n }\\n }\\n}\\n\\nfragment ContextMenuArtworkPreviewCard_artwork_XFsn3 on Artwork {\\n ...ContextMenuArtworkPreviewCardImage_artwork_XFsn3\\n artistNames\\n date\\n title\\n sale {\\n isAuction\\n isClosed\\n endAt\\n id\\n }\\n saleMessage\\n saleArtwork {\\n counts {\\n bidderPositions\\n }\\n currentBid {\\n display\\n }\\n endAt\\n extendedBiddingEndAt\\n id\\n }\\n partner {\\n name\\n id\\n }\\n}\\n\\nfragment ContextMenuArtwork_artwork_XFsn3 on Artwork {\\n ...ContextMenuArtworkPreviewCard_artwork_XFsn3\\n ...useSaveArtworkToArtworkLists_artwork\\n title\\n href\\n artistNames\\n artists(shallow: true) {\\n name\\n id\\n }\\n slug\\n internalID\\n id\\n isHangable\\n contextMenuImage: image {\\n url(version: \\"large\\")\\n }\\n image(includeAll: false) {\\n url(version: \\"large\\")\\n }\\n sale {\\n isAuction\\n isClosed\\n id\\n }\\n heightCm\\n widthCm\\n}\\n\\nfragment CreateArtworkAlertModal_artwork on Artwork {\\n title\\n internalID\\n slug\\n isEligibleToCreateAlert\\n artistsArray: artists {\\n internalID\\n name\\n id\\n }\\n attributionClass {\\n internalID\\n id\\n }\\n mediumType {\\n filterGene {\\n slug\\n name\\n id\\n }\\n }\\n}\\n\\nfragment useFollowArtist_artist on Artist {\\n id\\n internalID\\n slug\\n isFollowed\\n counts {\\n follows\\n }\\n}\\n\\nfragment useSaveArtworkToArtworkLists_artwork on Artwork {\\n id\\n internalID\\n isInAuction\\n isSaved\\n slug\\n title\\n date\\n artistNames\\n preview: image {\\n url(version: \\"square\\")\\n }\\n customArtworkLists: collectionsConnection(first: 0, default: false, saves: true) {\\n totalCount\\n }\\n}\\n","variables":{"artistID":"nobuyoshi-araki","input":{"acquireable":false,"atAuction":false,"includeArtworksByFollowedArtists":false,"inquireableOnly":false,"medium":"*","offerable":false,"priceRange":"*-*","sort":"-decayed_merch"}}}', headers: { "Content-Type": "application/json", "User-Agent": "Artsy-Mobile ios Artsy-Mobile/8.53.0 Eigen/2022.05.11.13/8.53.0", @@ -57,7 +57,7 @@ describe(isRequestCacheable, () => { operation: { id: "xxx", metadata: {}, - name: "ArtistAboveTheFoldQuery", + name: "ArtistQuery", operationKind: "query", text: null, }, From f906255f38c129279b77336dff3476fa5c8c5c39 Mon Sep 17 00:00:00 2001 From: Mounir Dhahri Date: Tue, 3 Feb 2026 14:43:34 +0100 Subject: [PATCH 121/123] chore: make header scrollable --- src/app/Scenes/Artist/Artist.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/app/Scenes/Artist/Artist.tsx b/src/app/Scenes/Artist/Artist.tsx index 9be03ad9be5..bb74ec81356 100644 --- a/src/app/Scenes/Artist/Artist.tsx +++ b/src/app/Scenes/Artist/Artist.tsx @@ -124,6 +124,7 @@ export const Artist: React.FC = ({ disableKeyboardAvoidance initialTabName={initialTab} title={artist.name ?? ""} + allowHeaderOverscroll showLargeHeaderText={false} BelowTitleHeaderComponent={renderBelowTheHeaderComponent} headerProps={{ From cf33352cd6855c6bbe79b47dac9df043e2141b73 Mon Sep 17 00:00:00 2001 From: Mounir Dhahri Date: Wed, 4 Feb 2026 15:57:32 +0100 Subject: [PATCH 122/123] Revert "chore: improve artist screen architecture" This reverts commit 4c423b287b0f57febdd0839330011d65ef03d1a2. --- .../ArtistInsightsAuctionResults.tsx | 1 + .../__tests__/ArtistInsights.tests.tsx | 71 +++-- src/app/Scenes/Artist/Artist.tsx | 270 +++++++++--------- .../Scenes/Artist/__tests__/Artist.tests.tsx | 34 ++- .../__tests__/ArtistSavedSearch.tests.tsx | 57 +++- .../cacheHeaderMiddlewareHelpers.tests.ts | 4 +- 6 files changed, 252 insertions(+), 185 deletions(-) diff --git a/src/app/Components/Artist/ArtistInsights/ArtistInsightsAuctionResults.tsx b/src/app/Components/Artist/ArtistInsights/ArtistInsightsAuctionResults.tsx index ff9df634ee5..dbf048696cd 100644 --- a/src/app/Components/Artist/ArtistInsights/ArtistInsightsAuctionResults.tsx +++ b/src/app/Components/Artist/ArtistInsights/ArtistInsightsAuctionResults.tsx @@ -34,6 +34,7 @@ import { } from "react-native" import { createPaginationContainer, graphql, RelayPaginationProp } from "react-relay" import { useTracking } from "react-tracking" +import { space } from "styled-system" interface Props { artist: ArtistInsightsAuctionResults_artist$data diff --git a/src/app/Components/Artist/ArtistInsights/__tests__/ArtistInsights.tests.tsx b/src/app/Components/Artist/ArtistInsights/__tests__/ArtistInsights.tests.tsx index 794e369e8c1..2b11f08ceba 100644 --- a/src/app/Components/Artist/ArtistInsights/__tests__/ArtistInsights.tests.tsx +++ b/src/app/Components/Artist/ArtistInsights/__tests__/ArtistInsights.tests.tsx @@ -1,10 +1,12 @@ -import { screen } from "@testing-library/react-native" import { ArtistInsightsTestsQuery } from "__generated__/ArtistInsightsTestsQuery.graphql" import { ArtistInsights } from "app/Components/Artist/ArtistInsights/ArtistInsights" import { ArtistInsightsAuctionResultsPaginationContainer } from "app/Components/Artist/ArtistInsights/ArtistInsightsAuctionResults" -import { setupTestWrapper } from "app/utils/tests/setupTestWrapper" -import { graphql } from "react-relay" +import { flushPromiseQueue } from "app/utils/tests/flushPromiseQueue" +import { renderWithWrappersLEGACY } from "app/utils/tests/renderWithWrappers" +import { resolveMostRecentRelayOperation } from "app/utils/tests/resolveMostRecentRelayOperation" +import { graphql, QueryRenderer } from "react-relay" import { useTracking } from "react-tracking" +import { createMockEnvironment } from "relay-test-utils" jest.mock("react-native-collapsible-tab-view", () => { const getMockCollapsibleTabs = @@ -19,19 +21,33 @@ jest.mock("react-native-collapsible-tab-view", () => { const trackEvent = useTracking().trackEvent describe("ArtistInsights", () => { - const { renderWithRelay } = setupTestWrapper({ - Component: ({ artist }) => , - query: graphql` - query ArtistInsightsTestsQuery @relay_test_operation { - artist(id: "some-id") { - ...ArtistInsights_artist + let mockEnvironment: ReturnType + beforeEach(() => (mockEnvironment = createMockEnvironment())) + + const TestRenderer = () => ( + + environment={mockEnvironment} + query={graphql` + query ArtistInsightsTestsQuery @relay_test_operation { + artist(id: "some-id") { + ...ArtistInsights_artist + } } - } - `, - }) + `} + variables={{}} + render={({ props }) => { + if (!props?.artist) { + return null + } + return + }} + /> + ) - it("renders list auction results", () => { - renderWithRelay({ + it("renders list auction results", async () => { + const view = renderWithWrappersLEGACY() + + resolveMostRecentRelayOperation(mockEnvironment, { Artist: () => ({ internalID: "artist-id", slug: "artist-slug", @@ -39,23 +55,26 @@ describe("ArtistInsights", () => { }), }) - expect( - screen.UNSAFE_queryAllByType(ArtistInsightsAuctionResultsPaginationContainer) - ).toHaveLength(1) + await flushPromiseQueue() + + // now safe to assert + const auctionResults = view.root.findAllByType( + ArtistInsightsAuctionResultsPaginationContainer + ) + expect(auctionResults.length).toEqual(1) }) - it("tracks an auction page view when artist insights is current tab", () => { - renderWithRelay({ - Artist: () => ({ - internalID: "artist-id", - slug: "artist-slug", - }), - }) + it("tracks an auction page view when artist insights is current tab", async () => { + renderWithWrappersLEGACY() + + resolveMostRecentRelayOperation(mockEnvironment) + + await flushPromiseQueue() expect(trackEvent).toHaveBeenCalledWith({ action: "screen", - context_screen_owner_id: "artist-id", - context_screen_owner_slug: "artist-slug", + context_screen_owner_id: "internalID-1", + context_screen_owner_slug: "slug-1", context_screen_owner_type: "artistAuctionResults", }) }) diff --git a/src/app/Scenes/Artist/Artist.tsx b/src/app/Scenes/Artist/Artist.tsx index bb74ec81356..0ca48bda76d 100644 --- a/src/app/Scenes/Artist/Artist.tsx +++ b/src/app/Scenes/Artist/Artist.tsx @@ -9,8 +9,9 @@ import { Tabs, } from "@artsy/palette-mobile" import { useRoute } from "@react-navigation/native" +import { ArtistAboveTheFoldQuery } from "__generated__/ArtistAboveTheFoldQuery.graphql" import { FilterArtworksInput } from "__generated__/ArtistArtworks_artistRefetch.graphql" -import { ArtistQuery } from "__generated__/ArtistQuery.graphql" +import { ArtistBelowTheFoldQuery } from "__generated__/ArtistBelowTheFoldQuery.graphql" import { artistAboutQuery, ArtistAboutQueryRenderer, @@ -38,12 +39,13 @@ import { usePopoverMessage } from "app/Components/PopoverMessage/popoverMessageH import { SkeletonPill } from "app/Components/SkeletonPill/SkeletonPill" import { SearchCriteriaQueryRenderer } from "app/Scenes/Artist/SearchCriteria" import { goBack } from "app/system/navigation/navigate" -import { withSuspense } from "app/utils/hooks/withSuspense" +import { getRelayEnvironment } from "app/system/relay/defaultEnvironment" +import { AboveTheFoldQueryRenderer } from "app/utils/AboveTheFoldQueryRenderer" import { KeyboardAvoidingContainer } from "app/utils/keyboard/KeyboardAvoidingContainer" import { prefetchQuery } from "app/utils/queryPrefetching" import { ProvideScreenTracking, Schema } from "app/utils/track" import React, { useCallback, useEffect, useMemo } from "react" -import { graphql, useLazyLoadQuery } from "react-relay" +import { Environment, graphql } from "react-relay" const INITIAL_TAB = "Artworks" @@ -55,8 +57,9 @@ interface RouteParams { } interface ArtistProps { - artist: NonNullable + artistAboveTheFold: NonNullable auctionResultsInitialFilters?: FilterArray + environment?: Environment fetchCriteriaError: Error | null initialTab?: string predefinedFilters?: FilterArray @@ -66,7 +69,7 @@ interface ArtistProps { } export const Artist: React.FC = ({ - artist, + artistAboveTheFold, auctionResultsInitialFilters, fetchCriteriaError, initialTab = INITIAL_TAB, @@ -92,30 +95,30 @@ export const Artist: React.FC = ({ useEffect(() => { prefetchQuery({ query: artistAboutQuery, - variables: { artistID: artist.internalID }, + variables: { artistID: artistAboveTheFold.internalID }, }) prefetchQuery({ query: artistInsightsQuery, - variables: { artistID: artist.internalID }, + variables: { artistID: artistAboveTheFold.internalID }, }) - }, [artist.internalID]) + }, [artistAboveTheFold.internalID]) const renderBelowTheHeaderComponent = useCallback( - () => , - [artist] + () => , + [artistAboveTheFold] ) const artistHeaderRight = useMemo(() => { - return - }, [artist]) + return + }, [artistAboveTheFold]) return ( @@ -123,7 +126,7 @@ export const Artist: React.FC = ({ = ({ = ({ @@ -155,7 +158,7 @@ export const Artist: React.FC = ({ - + @@ -169,6 +172,7 @@ interface ArtistQueryRendererProps { alertID?: string artistID: string categories?: string[] + environment?: Environment initialTab?: string predefinedFilters?: FilterArray scrollToArtworksGrid?: boolean @@ -179,7 +183,7 @@ interface ArtistQueryRendererProps { } export const ArtistScreenQuery = graphql` - query ArtistQuery($artistID: String!) @cacheable { + query ArtistAboveTheFoldQuery($artistID: String!) @cacheable { artist(id: $artistID) { ...ArtistHeader_artist id @@ -198,6 +202,113 @@ export const defaultArtistVariables = { }), } +export const ArtistQueryRenderer: React.FC = ({ + alertID, + artistID, + categories, + environment, + initialTab, + predefinedFilters, + scrollToArtworksGrid = false, + search_criteria_id, + sizes, + verifiedRepresentativesCount, +}) => { + // exctact filter params from the query string. This is needed when + // the screen is opened via deeplink (/artist/kaws?attribution_class=..., for instance) + // to make sure the filters are applied correctly + const route = useRoute() + const routeParams = (route?.params as RouteParams)?.props || {} + const filters: FilterArray = [ + ...(predefinedFilters || []), + ...getFilterParamsFromRouteParams(routeParams), + ] + + return ( + ( + + ), + renderComponent: (searchCriteriaProps) => { + const { savedSearchCriteria, fetchCriteriaError } = searchCriteriaProps + const predefinedFilterParams = filterArtworksParams(filters ?? [], "artwork") + + let initialArtworksInput = { + ...defaultArtistVariables.input, + ...predefinedFilterParams, + } + + if (savedSearchCriteria) { + const preparedCriteria = getOnlyFilledSearchCriteriaValues(savedSearchCriteria) + + initialArtworksInput = { + ...initialArtworksInput, + ...preparedCriteria, + sort: "-published_at", + } + } + const input = prepareFilterArtworksParamsForInput(initialArtworksInput) + + return ( + + environment={environment || getRelayEnvironment()} + above={{ + query: ArtistScreenQuery, + variables: { + artistID, + }, + }} + below={{ + query: graphql` + query ArtistBelowTheFoldQuery($artistID: String!) @cacheable { + artist(id: $artistID) { + # Below-the-fold tabs (Insights, About) now have their own query renderers + # This query is kept minimal for backward compatibility + id + } + } + `, + variables: { artistID }, + }} + fallback={({ error }) => ( + + )} + render={{ + renderPlaceholder: () => ( + + ), + renderComponent: ({ above }) => { + if (!above.artist) { + throw new Error("no artist data") + } + return ( + + ) + }, + }} + /> + ) + }, + }} + /> + ) +} + const ArtistSkeleton: React.FC<{ verifiedRepresentativesCount?: number }> = ({ verifiedRepresentativesCount = 0, }) => { @@ -249,124 +360,3 @@ const ArtistSkeleton: React.FC<{ verifiedRepresentativesCount?: number }> = ({ ) } - -interface ArtistScreenProps { - artistID: string - categories?: string[] - initialTab?: string - predefinedFilters?: FilterArray - scrollToArtworksGrid: boolean - sizes?: string[] - searchCriteria: SearchCriteriaAttributes | null - fetchCriteriaError: Error | null - filters: FilterArray - verifiedRepresentativesCount?: number -} - -const ArtistScreen = withSuspense({ - Component: ({ - artistID, - categories, - initialTab, - predefinedFilters, - scrollToArtworksGrid, - sizes, - searchCriteria, - fetchCriteriaError, - filters, - }) => { - const data = useLazyLoadQuery(ArtistScreenQuery, { artistID }) - - if (!data.artist) { - return null - } - - const predefinedFilterParams = filterArtworksParams(filters ?? [], "artwork") - - let initialArtworksInput = { - ...defaultArtistVariables.input, - ...predefinedFilterParams, - } - - if (searchCriteria) { - const preparedCriteria = getOnlyFilledSearchCriteriaValues(searchCriteria) - - initialArtworksInput = { - ...initialArtworksInput, - ...preparedCriteria, - sort: "-published_at", - } - } - - const input = prepareFilterArtworksParamsForInput(initialArtworksInput) - - return ( - - ) - }, - LoadingFallback: ArtistSkeleton, - ErrorFallback: ({ error }) => ( - - ), -}) - -export const ArtistQueryRenderer: React.FC = ({ - alertID, - artistID, - categories, - initialTab, - predefinedFilters, - scrollToArtworksGrid = false, - search_criteria_id, - sizes, - verifiedRepresentativesCount, -}) => { - // extract filter params from the query string. This is needed when - // the screen is opened via deeplink (/artist/kaws?attribution_class=..., for instance) - // to make sure the filters are applied correctly - const route = useRoute() - const routeParams = (route?.params as RouteParams)?.props || {} - const filters: FilterArray = [ - ...(predefinedFilters || []), - ...getFilterParamsFromRouteParams(routeParams), - ] - - return ( - ( - - ), - renderComponent: ({ savedSearchCriteria, fetchCriteriaError }) => { - return ( - - ) - }, - }} - /> - ) -} diff --git a/src/app/Scenes/Artist/__tests__/Artist.tests.tsx b/src/app/Scenes/Artist/__tests__/Artist.tests.tsx index db7f103dd63..9cf76984c34 100644 --- a/src/app/Scenes/Artist/__tests__/Artist.tests.tsx +++ b/src/app/Scenes/Artist/__tests__/Artist.tests.tsx @@ -1,5 +1,6 @@ import { act, screen } from "@testing-library/react-native" import { ArtistQueryRenderer } from "app/Scenes/Artist/Artist" +import { getRelayEnvironment } from "app/system/relay/defaultEnvironment" import { flushPromiseQueue } from "app/utils/tests/flushPromiseQueue" import { renderWithHookWrappersTL } from "app/utils/tests/renderWithWrappers" import { postEventToProviders } from "app/utils/track/providers" @@ -9,7 +10,16 @@ import { MockResolvers } from "relay-test-utils/lib/RelayMockPayloadGenerator" jest.unmock("react-tracking") -type ArtistQueries = "SearchCriteriaQuery" | "ArtistQuery" | "MarketStatsQuery" +jest.mock("app/utils/queryPrefetching", () => ({ + usePrefetch: jest.fn(() => jest.fn()), + prefetchQuery: jest.fn(), +})) + +type ArtistQueries = + | "SearchCriteriaQuery" + | "ArtistAboveTheFoldQuery" + | "ArtistBelowTheFoldQuery" + | "MarketStatsQuery" describe("Artist", () => { let mockEnvironment: ReturnType @@ -28,7 +38,7 @@ describe("Artist", () => { mockEnvironment.mock.resolveMostRecentOperation((operation) => { const result = MockPayloadGenerator.generate(operation, { ID({ path }) { - // need to make sure artist id is stable between queries to avoid cache weirdness + // need to make sure artist id is stable between above-and-below-the-fold queries to avoid cache weirdness if (isEqual(path, ["artist", "id"])) { return "artist-id" } @@ -41,25 +51,31 @@ describe("Artist", () => { } const TestWrapper = (props: Record) => ( - + ) it("should render all tabs", async () => { - renderWithHookWrappersTL(, mockEnvironment, { includeNavigation: true }) + renderWithHookWrappersTL(, getRelayEnvironment(), { includeNavigation: true }) - mockMostRecentOperation("ArtistQuery") + mockMostRecentOperation("ArtistAboveTheFoldQuery") + mockMostRecentOperation("ArtistBelowTheFoldQuery", { + ArtistInsight() { + return { entities: ["test"] } + }, + }) + mockMostRecentOperation("MarketStatsQuery") await flushPromiseQueue() expect(screen.getByText("Artworks")).toBeTruthy() - expect(screen.getByText("Auction Results")).toBeTruthy() - expect(screen.getByText("About")).toBeTruthy() + expect(screen.getByText("Insights")).toBeTruthy() + expect(screen.getByText("Overview")).toBeTruthy() }) it("tracks a page view", async () => { - renderWithHookWrappersTL(, mockEnvironment, { includeNavigation: true }) + renderWithHookWrappersTL(, getRelayEnvironment(), { includeNavigation: true }) - mockMostRecentOperation("ArtistQuery") + mockMostRecentOperation("ArtistAboveTheFoldQuery") await flushPromiseQueue() diff --git a/src/app/Scenes/Artist/__tests__/ArtistSavedSearch.tests.tsx b/src/app/Scenes/Artist/__tests__/ArtistSavedSearch.tests.tsx index 23a357ee10c..5cfc9e98538 100644 --- a/src/app/Scenes/Artist/__tests__/ArtistSavedSearch.tests.tsx +++ b/src/app/Scenes/Artist/__tests__/ArtistSavedSearch.tests.tsx @@ -9,6 +9,11 @@ import { MockResolvers } from "relay-test-utils/lib/RelayMockPayloadGenerator" jest.unmock("react-tracking") +jest.mock("app/utils/queryPrefetching", () => ({ + usePrefetch: jest.fn(() => jest.fn()), + prefetchQuery: jest.fn(), +})) + const mockUseIsFocusedMock = jest.fn() const mockAddListener = jest.fn((event, callback) => { @@ -36,9 +41,12 @@ jest.mock("@react-navigation/native", () => { }) type ArtistQueries = - | "ArtistQuery" + | "ArtistAboveTheFoldQuery" + | "ArtistBelowTheFoldQuery" | "SearchCriteriaQuery" | "ArtistArtworksQuery" + | "ArtistAboutQuery" + | "ArtistInsightsQuery" | "MarketStatsQuery" | "ArtistInsightsAuctionResultsQuery" @@ -65,7 +73,7 @@ describe("Saved search banner on artist screen", () => { environment.mock.resolveMostRecentOperation((operation) => { const result = MockPayloadGenerator.generate(operation, { ID({ path }) { - // need to make sure artist id is stable between queries to avoid cache weirdness + // need to make sure artist id is stable between above-and-below-the-fold queries to avoid cache weirdness if (isEqual(path, ["artist", "id"])) { return "artist-id" } @@ -79,16 +87,25 @@ describe("Saved search banner on artist screen", () => { const getTree = (alertID?: string) => renderWithHookWrappersTL( - , - environment + ) it("should convert the criteria attributes to the filter params format", async () => { getTree("search-criteria-id") mockMostRecentOperation("SearchCriteriaQuery", MockSearchCriteriaQuery) - mockMostRecentOperation("ArtistQuery", MockArtistQuery) + mockMostRecentOperation("ArtistAboveTheFoldQuery", MockArtistAboveTheFoldQuery) + mockMostRecentOperation("ArtistBelowTheFoldQuery", MockArtistBelowTheFoldQuery) + mockMostRecentOperation("ArtistAboutQuery") + mockMostRecentOperation("ArtistInsightsQuery") mockMostRecentOperation("ArtistArtworksQuery", MockArtistArtworksQuery) + mockMostRecentOperation("MarketStatsQuery", MockMarketStatsQuery) + mockMostRecentOperation("ArtistInsightsAuctionResultsQuery") await flushPromiseQueue() @@ -103,7 +120,7 @@ describe("Saved search banner on artist screen", () => { getTree("something") rejectMostRecentRelayOperation(environment, new Error()) - mockMostRecentOperation("ArtistQuery", MockArtistQuery) + mockMostRecentOperation("ArtistAboveTheFoldQuery", MockArtistAboveTheFoldQuery) await flushPromiseQueue() @@ -115,8 +132,12 @@ describe("Saved search banner on artist screen", () => { getTree("search-criteria-id") mockMostRecentOperation("SearchCriteriaQuery", MockSearchCriteriaQuery) - mockMostRecentOperation("ArtistQuery", MockArtistQuery) + mockMostRecentOperation("ArtistAboveTheFoldQuery", MockArtistAboveTheFoldQuery) + mockMostRecentOperation("ArtistBelowTheFoldQuery", MockArtistBelowTheFoldQuery) + mockMostRecentOperation("ArtistAboutQuery") + mockMostRecentOperation("ArtistInsightsQuery") mockMostRecentOperation("ArtistArtworksQuery", MockArtistArtworksQuery) + mockMostRecentOperation("MarketStatsQuery", MockMarketStatsQuery) await flushPromiseQueue() @@ -143,7 +164,7 @@ const MockSearchCriteriaQuery: MockResolvers = { }, } -const MockArtistQuery: MockResolvers = { +const MockArtistAboveTheFoldQuery: MockResolvers = { Artist() { return { has_metadata: true, @@ -156,6 +177,16 @@ const MockArtistQuery: MockResolvers = { }, } +const MockArtistBelowTheFoldQuery: MockResolvers = { + Artist() { + return { + articles: [], + biographyBlurb: { text: "Artist biography" }, + insights: [], + } + }, +} + const MockArtistArtworksQuery: MockResolvers = { Artist() { return { @@ -232,3 +263,13 @@ const MockArtistArtworksQuery: MockResolvers = { } }, } + +const MockMarketStatsQuery: MockResolvers = { + Artist() { + return { + priceInsightsConnection: { + edges: [], + }, + } + }, +} diff --git a/src/app/system/relay/helpers/__tests__/cacheHeaderMiddlewareHelpers.tests.ts b/src/app/system/relay/helpers/__tests__/cacheHeaderMiddlewareHelpers.tests.ts index a7054dc1946..026783fc6e4 100644 --- a/src/app/system/relay/helpers/__tests__/cacheHeaderMiddlewareHelpers.tests.ts +++ b/src/app/system/relay/helpers/__tests__/cacheHeaderMiddlewareHelpers.tests.ts @@ -41,7 +41,7 @@ describe(isRequestCacheable, () => { cacheConfig: {}, controller: {}, fetchOpts: { - body: '{"query":"query ArtistQuery(\\n $artistID: String!\\n $input: FilterArtworksInput\\n) @cacheable {\\n artist(id: $artistID) @principalField {\\n ...ArtistHeader_artist\\n ...ArtistArtworks_artist_2VV6jB\\n ...ArtistHeaderNavRight_artist\\n id\\n internalID\\n slug\\n href\\n name\\n coverArtwork {\\n image {\\n url(version: \\"larger\\")\\n }\\n id\\n }\\n }\\n}\\n\\nfragment ArtistArtworksFilterHeader_artist on Artist {\\n internalID\\n slug\\n}\\n\\nfragment ArtistArtworks_artist_2VV6jB on Artist {\\n ...ArtistArtworksFilterHeader_artist\\n id\\n slug\\n name\\n internalID\\n counts {\\n artworks\\n }\\n aggregations: filterArtworksConnection(first: 0, aggregations: [ARTIST_SERIES, COLOR, DIMENSION_RANGE, LOCATION_CITY, MAJOR_PERIOD, MATERIALS_TERMS, MEDIUM, PARTNER, PRICE_RANGE, SIMPLE_PRICE_HISTOGRAM]) {\\n aggregations {\\n slice\\n counts {\\n count\\n name\\n value\\n }\\n }\\n id\\n }\\n artworks: filterArtworksConnection(first: 10, input: $input) {\\n edges {\\n node {\\n id\\n slug\\n image(includeAll: false) {\\n aspectRatio\\n }\\n ...ArtworkGridItem_artwork_FOvjt\\n __typename\\n }\\n cursor\\n }\\n pageInfo {\\n endCursor\\n hasNextPage\\n }\\n id\\n }\\n statuses {\\n artworks\\n }\\n}\\n\\nfragment ArtistHeaderNavRight_artist on Artist {\\n isFollowed\\n counts {\\n follows\\n }\\n ...useFollowArtist_artist\\n}\\n\\nfragment ArtistHeader_artist on Artist {\\n slug\\n birthday\\n coverArtwork {\\n title\\n image {\\n blurhash\\n url(version: \\"larger\\")\\n }\\n id\\n }\\n internalID\\n name\\n nationality\\n verifiedRepresentatives {\\n partner {\\n internalID\\n name\\n href\\n profile {\\n icon {\\n url(version: \\"square140\\")\\n }\\n id\\n }\\n id\\n }\\n id\\n }\\n}\\n\\nfragment ArtworkAuctionTimer_collectorSignals on CollectorSignals {\\n auction {\\n onlineBiddingExtended\\n lotClosesAt\\n registrationEndsAt\\n }\\n}\\n\\nfragment ArtworkGridItem_artwork_FOvjt on Artwork {\\n ...CreateArtworkAlertModal_artwork\\n ...ContextMenuArtwork_artwork_XFsn3\\n availability\\n title\\n date\\n saleMessage\\n slug\\n artists(shallow: true) {\\n name\\n id\\n }\\n widthCm\\n heightCm\\n isHangable\\n id\\n internalID\\n isAcquireable\\n isBiddable\\n isInquireable\\n isOfferable\\n isSaved\\n isUnlisted\\n artistNames\\n href\\n sale {\\n isAuction\\n isClosed\\n displayTimelyAt\\n cascadingEndTimeIntervalMinutes\\n extendedBiddingPeriodMinutes\\n extendedBiddingIntervalMinutes\\n endAt\\n startAt\\n id\\n }\\n saleArtwork {\\n counts {\\n bidderPositions\\n }\\n formattedEndDateTime\\n currentBid {\\n display\\n }\\n lotID\\n lotLabel\\n endAt\\n extendedBiddingEndAt\\n id\\n }\\n partner {\\n name\\n id\\n }\\n image(includeAll: false) {\\n blurhash\\n url(version: \\"large\\")\\n aspectRatio\\n resized {\\n src\\n srcSet\\n width\\n height\\n }\\n }\\n collectorSignals {\\n partnerOffer {\\n isAvailable\\n endAt\\n priceWithDiscount {\\n display\\n }\\n id\\n }\\n auction {\\n lotWatcherCount\\n bidCount\\n liveBiddingStarted\\n lotClosesAt\\n }\\n primaryLabel\\n ...ArtworkAuctionTimer_collectorSignals\\n ...ArtworkSocialSignal_collectorSignals\\n }\\n ...useSaveArtworkToArtworkLists_artwork\\n}\\n\\nfragment ArtworkSocialSignal_collectorSignals on CollectorSignals {\\n increasedInterest\\n curatorsPick\\n}\\n\\nfragment ContextMenuArtworkPreviewCardImage_artwork_XFsn3 on Artwork {\\n contextMenuImage: image {\\n url(version: \\"large\\")\\n resized {\\n src\\n srcSet\\n width\\n height\\n }\\n }\\n}\\n\\nfragment ContextMenuArtworkPreviewCard_artwork_XFsn3 on Artwork {\\n ...ContextMenuArtworkPreviewCardImage_artwork_XFsn3\\n artistNames\\n date\\n title\\n sale {\\n isAuction\\n isClosed\\n endAt\\n id\\n }\\n saleMessage\\n saleArtwork {\\n counts {\\n bidderPositions\\n }\\n currentBid {\\n display\\n }\\n endAt\\n extendedBiddingEndAt\\n id\\n }\\n partner {\\n name\\n id\\n }\\n}\\n\\nfragment ContextMenuArtwork_artwork_XFsn3 on Artwork {\\n ...ContextMenuArtworkPreviewCard_artwork_XFsn3\\n ...useSaveArtworkToArtworkLists_artwork\\n title\\n href\\n artistNames\\n artists(shallow: true) {\\n name\\n id\\n }\\n slug\\n internalID\\n id\\n isHangable\\n contextMenuImage: image {\\n url(version: \\"large\\")\\n }\\n image(includeAll: false) {\\n url(version: \\"large\\")\\n }\\n sale {\\n isAuction\\n isClosed\\n id\\n }\\n heightCm\\n widthCm\\n}\\n\\nfragment CreateArtworkAlertModal_artwork on Artwork {\\n title\\n internalID\\n slug\\n isEligibleToCreateAlert\\n artistsArray: artists {\\n internalID\\n name\\n id\\n }\\n attributionClass {\\n internalID\\n id\\n }\\n mediumType {\\n filterGene {\\n slug\\n name\\n id\\n }\\n }\\n}\\n\\nfragment useFollowArtist_artist on Artist {\\n id\\n internalID\\n slug\\n isFollowed\\n counts {\\n follows\\n }\\n}\\n\\nfragment useSaveArtworkToArtworkLists_artwork on Artwork {\\n id\\n internalID\\n isInAuction\\n isSaved\\n slug\\n title\\n date\\n artistNames\\n preview: image {\\n url(version: \\"square\\")\\n }\\n customArtworkLists: collectionsConnection(first: 0, default: false, saves: true) {\\n totalCount\\n }\\n}\\n","variables":{"artistID":"nobuyoshi-araki","input":{"acquireable":false,"atAuction":false,"includeArtworksByFollowedArtists":false,"inquireableOnly":false,"medium":"*","offerable":false,"priceRange":"*-*","sort":"-decayed_merch"}}}', + body: '{"query":"query ArtistAboveTheFoldQuery(\\n $artistID: String!\\n $input: FilterArtworksInput\\n) @cacheable {\\n artist(id: $artistID) @principalField {\\n ...ArtistHeader_artist\\n ...ArtistArtworks_artist_2VV6jB\\n ...ArtistHeaderNavRight_artist\\n id\\n internalID\\n slug\\n href\\n name\\n coverArtwork {\\n image {\\n url(version: \\"larger\\")\\n }\\n id\\n }\\n }\\n}\\n\\nfragment ArtistArtworksFilterHeader_artist on Artist {\\n internalID\\n slug\\n}\\n\\nfragment ArtistArtworks_artist_2VV6jB on Artist {\\n ...ArtistArtworksFilterHeader_artist\\n id\\n slug\\n name\\n internalID\\n counts {\\n artworks\\n }\\n aggregations: filterArtworksConnection(first: 0, aggregations: [ARTIST_SERIES, COLOR, DIMENSION_RANGE, LOCATION_CITY, MAJOR_PERIOD, MATERIALS_TERMS, MEDIUM, PARTNER, PRICE_RANGE, SIMPLE_PRICE_HISTOGRAM]) {\\n aggregations {\\n slice\\n counts {\\n count\\n name\\n value\\n }\\n }\\n id\\n }\\n artworks: filterArtworksConnection(first: 10, input: $input) {\\n edges {\\n node {\\n id\\n slug\\n image(includeAll: false) {\\n aspectRatio\\n }\\n ...ArtworkGridItem_artwork_FOvjt\\n __typename\\n }\\n cursor\\n }\\n pageInfo {\\n endCursor\\n hasNextPage\\n }\\n id\\n }\\n statuses {\\n artworks\\n }\\n}\\n\\nfragment ArtistHeaderNavRight_artist on Artist {\\n isFollowed\\n counts {\\n follows\\n }\\n ...useFollowArtist_artist\\n}\\n\\nfragment ArtistHeader_artist on Artist {\\n slug\\n birthday\\n coverArtwork {\\n title\\n image {\\n blurhash\\n url(version: \\"larger\\")\\n }\\n id\\n }\\n internalID\\n name\\n nationality\\n verifiedRepresentatives {\\n partner {\\n internalID\\n name\\n href\\n profile {\\n icon {\\n url(version: \\"square140\\")\\n }\\n id\\n }\\n id\\n }\\n id\\n }\\n}\\n\\nfragment ArtworkAuctionTimer_collectorSignals on CollectorSignals {\\n auction {\\n onlineBiddingExtended\\n lotClosesAt\\n registrationEndsAt\\n }\\n}\\n\\nfragment ArtworkGridItem_artwork_FOvjt on Artwork {\\n ...CreateArtworkAlertModal_artwork\\n ...ContextMenuArtwork_artwork_XFsn3\\n availability\\n title\\n date\\n saleMessage\\n slug\\n artists(shallow: true) {\\n name\\n id\\n }\\n widthCm\\n heightCm\\n isHangable\\n id\\n internalID\\n isAcquireable\\n isBiddable\\n isInquireable\\n isOfferable\\n isSaved\\n isUnlisted\\n artistNames\\n href\\n sale {\\n isAuction\\n isClosed\\n displayTimelyAt\\n cascadingEndTimeIntervalMinutes\\n extendedBiddingPeriodMinutes\\n extendedBiddingIntervalMinutes\\n endAt\\n startAt\\n id\\n }\\n saleArtwork {\\n counts {\\n bidderPositions\\n }\\n formattedEndDateTime\\n currentBid {\\n display\\n }\\n lotID\\n lotLabel\\n endAt\\n extendedBiddingEndAt\\n id\\n }\\n partner {\\n name\\n id\\n }\\n image(includeAll: false) {\\n blurhash\\n url(version: \\"large\\")\\n aspectRatio\\n resized {\\n src\\n srcSet\\n width\\n height\\n }\\n }\\n collectorSignals {\\n partnerOffer {\\n isAvailable\\n endAt\\n priceWithDiscount {\\n display\\n }\\n id\\n }\\n auction {\\n lotWatcherCount\\n bidCount\\n liveBiddingStarted\\n lotClosesAt\\n }\\n primaryLabel\\n ...ArtworkAuctionTimer_collectorSignals\\n ...ArtworkSocialSignal_collectorSignals\\n }\\n ...useSaveArtworkToArtworkLists_artwork\\n}\\n\\nfragment ArtworkSocialSignal_collectorSignals on CollectorSignals {\\n increasedInterest\\n curatorsPick\\n}\\n\\nfragment ContextMenuArtworkPreviewCardImage_artwork_XFsn3 on Artwork {\\n contextMenuImage: image {\\n url(version: \\"large\\")\\n resized {\\n src\\n srcSet\\n width\\n height\\n }\\n }\\n}\\n\\nfragment ContextMenuArtworkPreviewCard_artwork_XFsn3 on Artwork {\\n ...ContextMenuArtworkPreviewCardImage_artwork_XFsn3\\n artistNames\\n date\\n title\\n sale {\\n isAuction\\n isClosed\\n endAt\\n id\\n }\\n saleMessage\\n saleArtwork {\\n counts {\\n bidderPositions\\n }\\n currentBid {\\n display\\n }\\n endAt\\n extendedBiddingEndAt\\n id\\n }\\n partner {\\n name\\n id\\n }\\n}\\n\\nfragment ContextMenuArtwork_artwork_XFsn3 on Artwork {\\n ...ContextMenuArtworkPreviewCard_artwork_XFsn3\\n ...useSaveArtworkToArtworkLists_artwork\\n title\\n href\\n artistNames\\n artists(shallow: true) {\\n name\\n id\\n }\\n slug\\n internalID\\n id\\n isHangable\\n contextMenuImage: image {\\n url(version: \\"large\\")\\n }\\n image(includeAll: false) {\\n url(version: \\"large\\")\\n }\\n sale {\\n isAuction\\n isClosed\\n id\\n }\\n heightCm\\n widthCm\\n}\\n\\nfragment CreateArtworkAlertModal_artwork on Artwork {\\n title\\n internalID\\n slug\\n isEligibleToCreateAlert\\n artistsArray: artists {\\n internalID\\n name\\n id\\n }\\n attributionClass {\\n internalID\\n id\\n }\\n mediumType {\\n filterGene {\\n slug\\n name\\n id\\n }\\n }\\n}\\n\\nfragment useFollowArtist_artist on Artist {\\n id\\n internalID\\n slug\\n isFollowed\\n counts {\\n follows\\n }\\n}\\n\\nfragment useSaveArtworkToArtworkLists_artwork on Artwork {\\n id\\n internalID\\n isInAuction\\n isSaved\\n slug\\n title\\n date\\n artistNames\\n preview: image {\\n url(version: \\"square\\")\\n }\\n customArtworkLists: collectionsConnection(first: 0, default: false, saves: true) {\\n totalCount\\n }\\n}\\n","variables":{"artistID":"nobuyoshi-araki","input":{"acquireable":false,"atAuction":false,"includeArtworksByFollowedArtists":false,"inquireableOnly":false,"medium":"*","offerable":false,"priceRange":"*-*","sort":"-decayed_merch"}}}', headers: { "Content-Type": "application/json", "User-Agent": "Artsy-Mobile ios Artsy-Mobile/8.53.0 Eigen/2022.05.11.13/8.53.0", @@ -57,7 +57,7 @@ describe(isRequestCacheable, () => { operation: { id: "xxx", metadata: {}, - name: "ArtistQuery", + name: "ArtistAboveTheFoldQuery", operationKind: "query", text: null, }, From 3e9b20d9535bd0d4811f376a22603b0562abe98b Mon Sep 17 00:00:00 2001 From: Mounir Dhahri Date: Thu, 5 Feb 2026 11:36:25 +0100 Subject: [PATCH 123/123] fix: broken tests --- .../Artist/ArtistInsights/ArtistInsightsAuctionResults.tsx | 1 - src/app/Scenes/Artist/__tests__/Artist.tests.tsx | 3 ++- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app/Components/Artist/ArtistInsights/ArtistInsightsAuctionResults.tsx b/src/app/Components/Artist/ArtistInsights/ArtistInsightsAuctionResults.tsx index dbf048696cd..ff9df634ee5 100644 --- a/src/app/Components/Artist/ArtistInsights/ArtistInsightsAuctionResults.tsx +++ b/src/app/Components/Artist/ArtistInsights/ArtistInsightsAuctionResults.tsx @@ -34,7 +34,6 @@ import { } from "react-native" import { createPaginationContainer, graphql, RelayPaginationProp } from "react-relay" import { useTracking } from "react-tracking" -import { space } from "styled-system" interface Props { artist: ArtistInsightsAuctionResults_artist$data diff --git a/src/app/Scenes/Artist/__tests__/Artist.tests.tsx b/src/app/Scenes/Artist/__tests__/Artist.tests.tsx index 9cf76984c34..0495ba5b470 100644 --- a/src/app/Scenes/Artist/__tests__/Artist.tests.tsx +++ b/src/app/Scenes/Artist/__tests__/Artist.tests.tsx @@ -20,6 +20,7 @@ type ArtistQueries = | "ArtistAboveTheFoldQuery" | "ArtistBelowTheFoldQuery" | "MarketStatsQuery" + | "ArtistAboutQuery" describe("Artist", () => { let mockEnvironment: ReturnType @@ -63,7 +64,7 @@ describe("Artist", () => { return { entities: ["test"] } }, }) - mockMostRecentOperation("MarketStatsQuery") + mockMostRecentOperation("ArtistAboutQuery") await flushPromiseQueue()