diff --git a/HACKS.md b/HACKS.md index d7660b796b9..bfe0063aeef 100644 --- a/HACKS.md +++ b/HACKS.md @@ -50,7 +50,7 @@ Doesn't really need to be removed but can be if view hierarchy issue is fixed in We have a modal for showing a loading state and a onDismiss call that optionally displays an alert message, on iOS 14 we came across an issue where the alert was not displaying because when onDismiss was called the LoadingModal was still in the view hierarchy. The delay is a workaround. -# android Input placeholder measuring hack +## android Input placeholder measuring hack #### When can we remove this: @@ -62,7 +62,7 @@ As you can see in the PR and issue, android doesn't use ellipsis on the placehol We added a workaround on Input, to accept an array of placeholders, from longest to shortest, so that android can measure which one fits in the TextInput as placeholder, and it uses that. When android can handle a long placeholder and use ellipsis or if we don't use long placeholders anymore, this can go. -# `react-native-screens` fragment crash on open from background on Android +## `react-native-screens` fragment crash on open from background on Android #### When can we remove this: @@ -87,7 +87,7 @@ I wasn't the one to add this file, so I don't have all the context, but I do kno The latest change I did was add the `ThemeContext` in there, because the version of styled-components we use has that, but the types are not exposing that, so I had to manually add it there. -# `react-native-push-notification` Requiring unknown module on ios +## `react-native-push-notification` Requiring unknown module on ios #### When can we remove this: @@ -99,7 +99,7 @@ This is happening because react-native-push-notification requires @react-native- adding this dependency at this time because it is unnecessary and we do not use react-native-push-notification on iOS. Also, we do not want unnecessary conflicts between our native push notification implementation and @react-native-community/push-notification-ios's. -# `PropsStore` pass functions as props inside navigate() on iOS +## `PropsStore` pass functions as props inside navigate() on iOS #### When can we remove this: @@ -113,7 +113,7 @@ See what can be converted: https://github.com/facebook/react-native/blob/main/Re PropsStore allows us to temporarily hold on the props and reinject them back into the destination view or module. -# `ORStackView` patch (add UIKit import) +## `ORStackView` patch (add UIKit import) #### When can we remove this: @@ -123,7 +123,7 @@ Once we remove ORStackView or the upstream repo adds the import. May want to pro The Pod does not compile when imported as is without hack due to missing symbols from UIKit. -# `Map` manual prop update in `PageWrapper` +## `Map` manual prop update in `PageWrapper` #### When can we remove this: @@ -135,7 +135,7 @@ If it is still an issue with old native navigation gone this can either be remov City Guide is a mixture of native components and react components, prop updates from the native side are not updating the component on the react native side without this manual check and update. See the PR here for the change in the AppRegistry: https://github.com/artsy/eigen/pull/6348 -# `React-Native-Image-Crop-Picker` App restarting when photo is taken. Fix is in `ArtsyNativeModule.clearCache`. +## `React-Native-Image-Crop-Picker` App restarting when photo is taken. Fix is in `ArtsyNativeModule.clearCache`. #### When can we remove this: @@ -285,3 +285,14 @@ After updates to both/either react native react-native-collapsible-tab-view. Rem #### Explanation/Context: After upgrading to react native 0.75 screens like my collection using this library stopped rendering on Android. This was fixed with a patch that added some style changes to the components from the package. + +## patch-pacakge for react-native-reanimated + +#### When can we remove this: + +When we can update the reanimated flatlist CellRendererComponent or it's style, or when this PR gets merged: +https://github.com/software-mansion/react-native-reanimated/pull/6573 + +#### Explanation/Context: + +In the HomeView Tasks, we want to update the FlatList's `CellRendererComponent` to update the `zIndex` of the rendered elements so they can be on top of each other, and to animate them we need to use Reanimated's FlatList, but it doesn't support updating the `CellRendererComponent` prop since they have their own implementation, so we added this patch to update the style of the component in Reanimated's FlatList. diff --git a/patches/react-native-reanimated+3.16.3.patch b/patches/react-native-reanimated+3.16.3.patch new file mode 100644 index 00000000000..87872ae985a --- /dev/null +++ b/patches/react-native-reanimated+3.16.3.patch @@ -0,0 +1,135 @@ +diff --git a/node_modules/react-native-reanimated/lib/typescript/component/FlatList.d.ts b/node_modules/react-native-reanimated/lib/typescript/component/FlatList.d.ts +index a427011..9244d1b 100644 +--- a/node_modules/react-native-reanimated/lib/typescript/component/FlatList.d.ts ++++ b/node_modules/react-native-reanimated/lib/typescript/component/FlatList.d.ts +@@ -1,7 +1,7 @@ + import React from 'react'; +-import type { FlatListProps } from 'react-native'; ++import type { FlatListProps, StyleProp, ViewStyle } from 'react-native'; + import { FlatList } from 'react-native'; +-import type { ILayoutAnimationBuilder } from '../layoutReanimation/animationBuilder/commonTypes'; ++import type { AnimatedStyle, ILayoutAnimationBuilder } from '../commonTypes'; + import type { AnimatedProps } from '../helperTypes'; + declare const AnimatedFlatList: React.ComponentClass>, any>; + interface ReanimatedFlatListPropsWithLayout extends AnimatedProps> { +@@ -18,6 +18,14 @@ interface ReanimatedFlatListPropsWithLayout extends AnimatedProps>> | (({ item, index, }: { ++ item: T; ++ index: number; ++ }) => StyleProp>>) | undefined; + } + export type FlatListPropsWithLayout = ReanimatedFlatListPropsWithLayout; + interface AnimatedFlatListComplement extends FlatList { +diff --git a/node_modules/react-native-reanimated/lib/typescript/component/FlatList.d.ts.map b/node_modules/react-native-reanimated/lib/typescript/component/FlatList.d.ts.map +index afc2283..0c3ac1f 100644 +--- a/node_modules/react-native-reanimated/lib/typescript/component/FlatList.d.ts.map ++++ b/node_modules/react-native-reanimated/lib/typescript/component/FlatList.d.ts.map +@@ -1 +1 @@ +-{"version":3,"file":"FlatList.d.ts","sourceRoot":"","sources":["../../../src/component/FlatList.tsx"],"names":[],"mappings":"AACA,OAAO,KAA6B,MAAM,OAAO,CAAC;AAClD,OAAO,KAAK,EACV,aAAa,EAId,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAGxC,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,mDAAmD,CAAC;AAGjG,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAEpD,QAAA,MAAM,gBAAgB,0FAAoC,CAAC;AA4B3D,UAAU,iCAAiC,CAAC,CAAC,CAC3C,SAAQ,aAAa,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;IACvC;;;;OAIG;IACH,mBAAmB,CAAC,EAAE,uBAAuB,CAAC;IAC9C;;;OAGG;IACH,6BAA6B,CAAC,EAAE,OAAO,CAAC;IACxC,gFAAgF;IAChF,qBAAqB,CAAC,EAAE,KAAK,CAAC;CAC/B;AAED,MAAM,MAAM,uBAAuB,CAAC,CAAC,IAAI,iCAAiC,CAAC,CAAC,CAAC,CAAC;AAI9E,UAAU,0BAA0B,CAAC,CAAC,CAAE,SAAQ,QAAQ,CAAC,CAAC,CAAC;IACzD,OAAO,IAAI,QAAQ,CAAC,CAAC,CAAC,CAAC;CACxB;AAgDD,eAAO,MAAM,kBAAkB;;MAQ1B,MAAM,YAAY,CAAC;AAExB,MAAM,MAAM,kBAAkB,CAAC,CAAC,IAAI,OAAO,gBAAgB,GACzD,0BAA0B,CAAC,CAAC,CAAC,CAAC"} +\ No newline at end of file ++{"version":3,"file":"FlatList.d.ts","sourceRoot":"","sources":["../../../src/component/FlatList.tsx"],"names":[],"mappings":"AACA,OAAO,KAA6B,MAAM,OAAO,CAAC;AAClD,OAAO,KAAK,EACV,aAAa,EAEb,SAAS,EACT,SAAS,EACV,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAGxC,OAAO,KAAK,EAAE,aAAa,EAAE,uBAAuB,EAAE,MAAM,gBAAgB,CAAC;AAE7E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAEpD,QAAA,MAAM,gBAAgB,0FAAoC,CAAC;AAyC3D,UAAU,iCAAiC,CAAC,CAAC,CAC3C,SAAQ,aAAa,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;IACvC;;;;OAIG;IACH,mBAAmB,CAAC,EAAE,uBAAuB,CAAC;IAC9C;;;OAGG;IACH,6BAA6B,CAAC,EAAE,OAAO,CAAC;IACxC,gFAAgF;IAChF,qBAAqB,CAAC,EAAE,KAAK,CAAC;IAC9B;;;OAGG;IACH,0BAA0B,CAAC,EACvB,SAAS,CAAC,aAAa,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,CAAC,GAC9C,CAAC,CAAC,EACA,IAAI,EACJ,KAAK,GACN,EAAE;QACD,IAAI,EAAE,CAAC,CAAC;QACR,KAAK,EAAE,MAAM,CAAC;KACf,KAAK,SAAS,CAAC,aAAa,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,GACrD,SAAS,CAAC;CACf;AAED,MAAM,MAAM,uBAAuB,CAAC,CAAC,IAAI,iCAAiC,CAAC,CAAC,CAAC,CAAC;AAI9E,UAAU,0BAA0B,CAAC,CAAC,CAAE,SAAQ,QAAQ,CAAC,CAAC,CAAC;IACzD,OAAO,IAAI,QAAQ,CAAC,CAAC,CAAC,CAAC;CACxB;AA2DD,eAAO,MAAM,kBAAkB;;MAQ1B,MAAM,YAAY,CAAC;AAExB,MAAM,MAAM,kBAAkB,CAAC,CAAC,IAAI,OAAO,gBAAgB,GACzD,0BAA0B,CAAC,CAAC,CAAC,CAAC"} +\ No newline at end of file +diff --git a/node_modules/react-native-reanimated/src/component/FlatList.tsx b/node_modules/react-native-reanimated/src/component/FlatList.tsx +index c886b0d..67b5ca5 100644 +--- a/node_modules/react-native-reanimated/src/component/FlatList.tsx ++++ b/node_modules/react-native-reanimated/src/component/FlatList.tsx +@@ -16,7 +16,9 @@ import type { AnimatedProps } from '../helperTypes'; + + const AnimatedFlatList = createAnimatedComponent(FlatList); + +-interface CellRendererComponentProps { ++interface CellRendererComponentProps { ++ index: number; ++ item: ItemT; + onLayout?: ((event: LayoutChangeEvent) => void) | undefined; + children: React.ReactNode; + style?: StyleProp>; +@@ -25,6 +27,9 @@ interface CellRendererComponentProps { + const createCellRendererComponent = ( + itemLayoutAnimationRef?: React.MutableRefObject< + ILayoutAnimationBuilder | undefined ++ >, ++ cellRendererComponentStyleRef?: React.MutableRefObject< ++ ReanimatedFlatListPropsWithLayout['CellRendererComponentStyle'] + > + ) => { + const CellRendererComponent = (props: CellRendererComponentProps) => { +@@ -33,7 +38,15 @@ const createCellRendererComponent = ( + // TODO TYPESCRIPT This is temporary cast is to get rid of .d.ts file. + layout={itemLayoutAnimationRef?.current as any} + onLayout={props.onLayout} +- style={props.style}> ++ style={[ ++ props.style, ++ typeof cellRendererComponentStyleRef?.current === 'function' ++ ? cellRendererComponentStyleRef?.current({ ++ index: props.index, ++ item: props.item, ++ }) ++ : cellRendererComponentStyleRef?.current, ++ ]}> + {props.children} + + ); +@@ -57,6 +70,20 @@ interface ReanimatedFlatListPropsWithLayout + skipEnteringExitingAnimations?: boolean; + /** Property `CellRendererComponent` is not supported in `Animated.FlatList`. */ + CellRendererComponent?: never; ++ /** ++ * Either animated view styles or a function that receives the item to be ++ * rendered and its index and returns animated view styles. ++ */ ++ CellRendererComponentStyle: ++ | StyleProp>> ++ | (({ ++ item, ++ index, ++ }: { ++ item: T; ++ index: number; ++ }) => StyleProp>>) ++ | undefined; + } + + export type FlatListPropsWithLayout = ReanimatedFlatListPropsWithLayout; +@@ -73,8 +100,12 @@ const FlatListForwardRefRender = function ( + props: ReanimatedFlatListPropsWithLayout, + ref: React.ForwardedRef + ) { +- const { itemLayoutAnimation, skipEnteringExitingAnimations, ...restProps } = +- props; ++ const { ++ itemLayoutAnimation, ++ skipEnteringExitingAnimations, ++ CellRendererComponentStyle, ++ ...restProps ++ } = props; + + // Set default scrollEventThrottle, because user expects + // to have continuous scroll events and +@@ -88,9 +119,16 @@ const FlatListForwardRefRender = function ( + const itemLayoutAnimationRef = useRef(itemLayoutAnimation); + itemLayoutAnimationRef.current = itemLayoutAnimation; + ++ const cellRendererComponentStyleRef = useRef(CellRendererComponentStyle); ++ cellRendererComponentStyleRef.current = CellRendererComponentStyle; ++ + const CellRendererComponent = React.useMemo( +- () => createCellRendererComponent(itemLayoutAnimationRef), +- [itemLayoutAnimationRef] ++ () => ++ createCellRendererComponent( ++ itemLayoutAnimationRef, ++ cellRendererComponentStyleRef ++ ), ++ [itemLayoutAnimationRef, CellRendererComponentStyle] + ); + + const animatedFlatList = ( diff --git a/src/app/Scenes/HomeView/Sections/HomeViewSectionTasks.tsx b/src/app/Scenes/HomeView/Sections/HomeViewSectionTasks.tsx index 71404958592..e9fbe2f800c 100644 --- a/src/app/Scenes/HomeView/Sections/HomeViewSectionTasks.tsx +++ b/src/app/Scenes/HomeView/Sections/HomeViewSectionTasks.tsx @@ -2,7 +2,6 @@ import { ContextModule } from "@artsy/cohesion" import { ArrowDownIcon, ArrowUpIcon, - Box, Flex, FlexProps, Skeleton, @@ -27,10 +26,15 @@ import { NoFallback, withSuspense } from "app/utils/hooks/withSuspense" import { ExtractNodeType } from "app/utils/relayHelpers" import { AnimatePresence, MotiView } from "moti" import { memo, RefObject, useCallback, useEffect, useMemo, useRef, useState } from "react" -import { CellRendererProps, InteractionManager, ListRenderItem } from "react-native" -import { FlatList } from "react-native-gesture-handler" +import { InteractionManager, ListRenderItem, Platform } from "react-native" import { SwipeableMethods } from "react-native-gesture-handler/ReanimatedSwipeable" -import { Easing } from "react-native-reanimated" +import Animated, { + Easing, + FadeOut, + LinearTransition, + useAnimatedStyle, + withTiming, +} from "react-native-reanimated" import { graphql, useFragment, useLazyLoadQuery } from "react-relay" import { usePrevious } from "react-use" @@ -39,6 +43,8 @@ const MAX_NUMBER_OF_TASKS = 10 // Height of each task + seperator const TASK_CARD_HEIGHT = 92 +const IS_ANDROID = Platform.OS === "android" + type Task = ExtractNodeType interface HomeViewSectionTasksProps extends FlexProps { @@ -71,6 +77,10 @@ export const HomeViewSectionTasks: React.FC = ({ const displayTaskStack = filteredTasks.length > 1 && !showAll const HeaderIconComponent = showAll ? ArrowUpIcon : ArrowDownIcon + // TODO: remove this when this reanimated issue gets fixed + // https://github.com/software-mansion/react-native-reanimated/issues/5728 + const [flatlistHeight, setFlatlistHeight] = useState(undefined) + const task = tasks?.[0] // adding the find-saved-artwork onboarding key to prevent overlap @@ -122,8 +132,8 @@ export const HomeViewSectionTasks: React.FC = ({ }) } - const renderCell = useCallback(({ index, ...rest }: CellRendererProps) => { - return + const getCellZIndex = useCallback(({ index }: { index: number }) => { + return { zIndex: -index } }, []) const renderItem = useCallback>( @@ -185,11 +195,19 @@ export const HomeViewSectionTasks: React.FC = ({ - { + if (IS_ANDROID) { + setFlatlistHeight(event.nativeEvent.layout.height) + } + }} + style={IS_ANDROID ? { height: flatlistHeight } : {}} + contentContainerStyle={IS_ANDROID ? { flex: 1, height: flatlistHeight } : {}} + itemLayoutAnimation={LinearTransition} scrollEnabled={false} data={filteredTasks} keyExtractor={(item) => item.internalID} - CellRendererComponent={renderCell} + CellRendererComponentStyle={getCellZIndex} ItemSeparatorComponent={() => } renderItem={renderItem} /> @@ -268,23 +286,24 @@ const TaskItem = ({ } } + const animatedStyle = useAnimatedStyle(() => { + return { + transform: [{ scaleX: withTiming(scaleX) }, { translateY: withTiming(translateY) }], + opacity: withTiming(opacity), + } + }) + return ( - - - onClearTask(task)} - onPress={displayTaskStack ? () => setShowAll((prev) => !prev) : undefined} - ref={taskRef} - onOpenTask={onOpenTask} - task={task} - /> - - + + onClearTask(task)} + onPress={displayTaskStack ? () => setShowAll((prev) => !prev) : undefined} + ref={taskRef} + onOpenTask={onOpenTask} + task={task} + /> + ) }