diff --git a/HACKS.md b/HACKS.md index b51f73a7cbc..d78104ad3b0 100644 --- a/HACKS.md +++ b/HACKS.md @@ -411,3 +411,14 @@ https://github.com/fastlane/fastlane/pull/22025 We want to be able to promote past android builds to prod because we are creating betas often and a release candidate may not be the latest. The developer APIs for google play only return the latest release and fastlane verifies that a release exists before allowing promotion. We added custom logic to work around this. + +## react-native-gesture-handler/ReanimatedSwipeable patch + +#### When we can remove this: + +When this pr is released in a new version of react-native-gesture-handler and we upgrade to it: +https://github.com/software-mansion/react-native-gesture-handler/pull/3149 + +#### Explanation/Context: + +We want to be able to open the swipeable view using the `openRight` function, but it doesn't seem to be working as expected. This patch is a workaround to make it work. diff --git a/patches/react-native-gesture-handler+2.19.0.patch b/patches/react-native-gesture-handler+2.19.0.patch new file mode 100644 index 00000000000..91ac25b069f --- /dev/null +++ b/patches/react-native-gesture-handler+2.19.0.patch @@ -0,0 +1,13 @@ +diff --git a/node_modules/react-native-gesture-handler/src/components/ReanimatedSwipeable.tsx b/node_modules/react-native-gesture-handler/src/components/ReanimatedSwipeable.tsx +index 40e760c..9e226a2 100644 +--- a/node_modules/react-native-gesture-handler/src/components/ReanimatedSwipeable.tsx ++++ b/node_modules/react-native-gesture-handler/src/components/ReanimatedSwipeable.tsx +@@ -444,7 +444,7 @@ const Swipeable = forwardRef( + openRight() { + 'worklet'; + rightWidth.value = rowWidth.value - rightOffset.value; +- animateRow(calculateCurrentOffset(), -rightWidth.value); ++ animateRow(calculateCurrentOffset(), -(rowWidth.value - rightOffset.value)); + }, + reset() { + 'worklet'; diff --git a/src/app/Components/Swipeable/Swipeable.tsx b/src/app/Components/Swipeable/Swipeable.tsx index 3cb5705ced4..406fbfefb53 100644 --- a/src/app/Components/Swipeable/Swipeable.tsx +++ b/src/app/Components/Swipeable/Swipeable.tsx @@ -2,7 +2,7 @@ import { Color, Flex, Touchable, useColor } from "@artsy/palette-mobile" import { forwardRef, useRef } from "react" import ReanimatedSwipeable, { SwipeableMethods, - SwipeableRef, + SwipeableProps, } from "react-native-gesture-handler/ReanimatedSwipeable" import Animated, { runOnJS, @@ -14,13 +14,11 @@ import Animated, { const FRICTION = 1.2 const SWIPE_TO_INTERACT_THRESHOLD = 80 -export interface SwipeableProps { - children: React.ReactNode +export interface SwipeableComponentProps extends SwipeableProps { actionOnPress?: () => void actionOnSwipe?: () => void actionComponent: React.ReactNode actionBackground?: Color - swipeableProps?: SwipeableProps enabled?: boolean /** * The width of the action component. We need to set it to make the swipeable animation.\ @@ -29,7 +27,7 @@ export interface SwipeableProps { actionComponentWidth: number } -export const Swipeable = forwardRef((props: SwipeableProps, swipeableRef: SwipeableRef) => { +export const Swipeable = forwardRef((props, ref) => { const { children, actionOnPress, @@ -38,7 +36,7 @@ export const Swipeable = forwardRef((props: SwipeableProps, swipeableRef: Swipea actionComponentWidth, actionBackground = "red100", enabled = true, - swipeableProps, + ...restProps } = props const color = useColor() @@ -111,11 +109,11 @@ export const Swipeable = forwardRef((props: SwipeableProps, swipeableRef: Swipea > {children} diff --git a/src/app/Components/Tasks/Task.tsx b/src/app/Components/Tasks/Task.tsx index bf935533102..70212a1b3ac 100644 --- a/src/app/Components/Tasks/Task.tsx +++ b/src/app/Components/Tasks/Task.tsx @@ -6,9 +6,9 @@ import { useHomeViewTracking } from "app/Scenes/HomeView/useHomeViewTracking" import { navigate } from "app/system/navigation/navigate" import { useAcknowledgeTask } from "app/utils/mutations/useAcknowledgeTask" import { useDismissTask } from "app/utils/mutations/useDismissTask" -import { useRef } from "react" +import { forwardRef } from "react" import { PixelRatio } from "react-native" -import { SwipeableMethods } from "react-native-gesture-handler/lib/typescript/components/ReanimatedSwipeable" +import { SwipeableMethods } from "react-native-gesture-handler/ReanimatedSwipeable" import { graphql, useFragment } from "react-relay" const TASK_IMAGE_SIZE = 60 @@ -19,84 +19,79 @@ interface TaskProps { onPress?: () => void task: Task_task$key } -export const Task: React.FC = ({ - disableSwipeable, - onClearTask, - onPress, - ...restProps -}) => { - const { tappedNotification, tappedClearNotification } = useHomeViewTracking() - const { submitMutation: dismissTask } = useDismissTask() - const { submitMutation: acknowledgeTask } = useAcknowledgeTask() - const fontScale = PixelRatio.getFontScale() +export const Task = forwardRef( + ({ disableSwipeable, onClearTask, onPress, ...restProps }, ref) => { + const { tappedNotification, tappedClearNotification } = useHomeViewTracking() + const { submitMutation: dismissTask } = useDismissTask() + const { submitMutation: acknowledgeTask } = useAcknowledgeTask() + const fontScale = PixelRatio.getFontScale() - const task = useFragment(taskFragment, restProps.task) + const task = useFragment(taskFragment, restProps.task) - const handlePressTask = () => { - if (onPress) { - onPress() - return - } - - acknowledgeTask({ variables: { taskID: task.internalID } }) - tappedNotification(ContextModule.actNow, task.actionLink, task.internalID, task.taskType) - onClearTask() + const handlePressTask = () => { + if (onPress) { + onPress() + return + } - navigate(task.actionLink) - } + acknowledgeTask({ variables: { taskID: task.internalID } }) + tappedNotification(ContextModule.actNow, task.actionLink, task.internalID, task.taskType) + onClearTask() - const handleClearTask = async () => { - dismissTask({ variables: { taskID: task.internalID } }) - tappedClearNotification(ContextModule.actNow, task.actionLink, task.internalID, task.taskType) - onClearTask() - } + navigate(task.actionLink) + } - const swipeableRef = useRef(null) + const handleClearTask = async () => { + dismissTask({ variables: { taskID: task.internalID } }) + tappedClearNotification(ContextModule.actNow, task.actionLink, task.internalID, task.taskType) + onClearTask() + } - return ( - - Clear - - } - actionComponentWidth={80 * fontScale} - actionOnPress={handleClearTask} - actionOnSwipe={handleClearTask} - enabled={!disableSwipeable} - ref={swipeableRef} - > - - - - - - + return ( + + Clear + + } + actionComponentWidth={80 * fontScale} + actionOnPress={handleClearTask} + actionOnSwipe={handleClearTask} + enabled={!disableSwipeable} + > + + + + + + - - - {task.title} - + + + {task.title} + - - {task.message} - + + {task.message} + + - - - - - ) -} + + + + ) + } +) const taskFragment = graphql` fragment Task_task on Task { diff --git a/src/app/Scenes/HomeView/Sections/HomeViewSectionTasks.tsx b/src/app/Scenes/HomeView/Sections/HomeViewSectionTasks.tsx index 052a6955937..125d8ed8fdf 100644 --- a/src/app/Scenes/HomeView/Sections/HomeViewSectionTasks.tsx +++ b/src/app/Scenes/HomeView/Sections/HomeViewSectionTasks.tsx @@ -6,10 +6,12 @@ import { SectionTitle } from "app/Components/SectionTitle" import { Task } from "app/Components/Tasks/Task" import { HomeViewSectionSentinel } from "app/Scenes/HomeView/Components/HomeViewSectionSentinel" import { SectionSharedProps } from "app/Scenes/HomeView/Sections/Section" +import { GlobalStore } from "app/store/GlobalStore" import { extractNodes } from "app/utils/extractNodes" import { NoFallback, withSuspense } from "app/utils/hooks/withSuspense" -import { useState } from "react" -import { LayoutAnimation } from "react-native" +import { useEffect, useRef, useState } from "react" +import { InteractionManager, LayoutAnimation } from "react-native" +import { SwipeableMethods } from "react-native-gesture-handler/ReanimatedSwipeable" import { graphql, useFragment, useLazyLoadQuery } from "react-relay" interface HomeViewSectionTasksProps extends FlexProps { @@ -26,21 +28,49 @@ export const HomeViewSectionTasks: React.FC = ({ const tasks = extractNodes(section.tasksConnection) + const swipeableRef = useRef(null) + const { + isDismissed, + sessionState: { isReady }, + } = GlobalStore.useAppState((state) => state.progressiveOnboarding) + const { dismiss } = GlobalStore.actions.progressiveOnboarding + + // adding the find-saved-artwork onboarding key to prevent overlap + const shouldStartOnboardingAnimation = + isReady && !isDismissed("act-now-tasks").status && !!isDismissed("find-saved-artwork").status + // In the future, we may want to show multiple tasks const task = tasks?.[0] const [displayTask, setDisplayTask] = useState(true) + useEffect(() => { + if (shouldStartOnboardingAnimation) { + startOnboardingAnimation() + } + }, [shouldStartOnboardingAnimation]) + + if (!task || !displayTask) { + return null + } + + const startOnboardingAnimation = () => { + InteractionManager.runAfterInteractions(() => { + swipeableRef.current?.openRight() + }).then(() => { + setTimeout(() => { + swipeableRef.current?.close() + dismiss("act-now-tasks") + }, 1500) + }) + } + const handleClearTask = () => { LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut) setDisplayTask(false) } - if (!task || !displayTask) { - return null - } - return ( @@ -48,7 +78,7 @@ export const HomeViewSectionTasks: React.FC = ({ - +