From 2f24762bd75974c1f0887e1f9c446cc3510d9aec Mon Sep 17 00:00:00 2001 From: Jack Nam <30609178+thienlnam@users.noreply.github.com> Date: Mon, 29 Apr 2024 14:22:08 -0700 Subject: [PATCH] Merge pull request #41176 from Expensify/revert-40369-fix-39841 Revert "fix-39841: Finetune animation durations" (cherry picked from commit 6c35ad7298aec681dfc711d4ec5dc5c7890250aa) --- src/CONST.ts | 9 +-- .../config.native.ts | 5 ++ src/hooks/useAnimatedHighlightStyle/config.ts | 8 +++ src/hooks/useAnimatedHighlightStyle/index.ts | 69 +++++-------------- src/libs/actions/Policy.ts | 45 ++++++++---- 5 files changed, 63 insertions(+), 73 deletions(-) create mode 100644 src/hooks/useAnimatedHighlightStyle/config.native.ts create mode 100644 src/hooks/useAnimatedHighlightStyle/config.ts diff --git a/src/CONST.ts b/src/CONST.ts index 57f255e777e1..16f06abd69f7 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -80,13 +80,8 @@ const CONST = { // Note: Group and Self-DM excluded as these are not tied to a Workspace WORKSPACE_ROOM_TYPES: [chatTypes.POLICY_ADMINS, chatTypes.POLICY_ANNOUNCE, chatTypes.DOMAIN_ALL, chatTypes.POLICY_ROOM, chatTypes.POLICY_EXPENSE_CHAT], ANDROID_PACKAGE_NAME, - WORKSPACE_ENABLE_FEATURE_REDIRECT_DELAY: 100, - ANIMATED_HIGHLIGHT_ENTRY_DELAY: 50, - ANIMATED_HIGHLIGHT_ENTRY_DURATION: 300, - ANIMATED_HIGHLIGHT_START_DELAY: 10, - ANIMATED_HIGHLIGHT_START_DURATION: 300, - ANIMATED_HIGHLIGHT_END_DELAY: 800, - ANIMATED_HIGHLIGHT_END_DURATION: 2000, + ANIMATED_HIGHLIGHT_DELAY: 500, + ANIMATED_HIGHLIGHT_DURATION: 500, ANIMATED_TRANSITION: 300, ANIMATED_TRANSITION_FROM_VALUE: 100, ANIMATION_IN_TIMING: 100, diff --git a/src/hooks/useAnimatedHighlightStyle/config.native.ts b/src/hooks/useAnimatedHighlightStyle/config.native.ts new file mode 100644 index 000000000000..a62d3a33039e --- /dev/null +++ b/src/hooks/useAnimatedHighlightStyle/config.native.ts @@ -0,0 +1,5 @@ +const DELAY_FACTOR = 1.85; + +export default {}; + +export {DELAY_FACTOR}; diff --git a/src/hooks/useAnimatedHighlightStyle/config.ts b/src/hooks/useAnimatedHighlightStyle/config.ts new file mode 100644 index 000000000000..6010c8c33aa7 --- /dev/null +++ b/src/hooks/useAnimatedHighlightStyle/config.ts @@ -0,0 +1,8 @@ +import {isMobile} from '@libs/Browser'; + +// It takes varying amount of time to navigate to a new page on mobile and desktop +// This variable takes that into account +const DELAY_FACTOR = isMobile() ? 1 : 0.2; +export default {}; + +export {DELAY_FACTOR}; diff --git a/src/hooks/useAnimatedHighlightStyle/index.ts b/src/hooks/useAnimatedHighlightStyle/index.ts index 4f934fee7652..e438bd2473fa 100644 --- a/src/hooks/useAnimatedHighlightStyle/index.ts +++ b/src/hooks/useAnimatedHighlightStyle/index.ts @@ -1,9 +1,9 @@ import React from 'react'; import {InteractionManager} from 'react-native'; import {Easing, interpolate, interpolateColor, runOnJS, useAnimatedStyle, useSharedValue, withDelay, withSequence, withTiming} from 'react-native-reanimated'; -import useScreenWrapperTranstionStatus from '@hooks/useScreenWrapperTransitionStatus'; import useTheme from '@hooks/useTheme'; import CONST from '@src/CONST'; +import {DELAY_FACTOR} from './config'; type Props = { /** Border radius of the wrapper */ @@ -12,26 +12,14 @@ type Props = { /** Height of the item that is to be faded */ height: number; - /** Delay before the highlighted item enters */ - itemEnterDelay?: number; - - /** Duration in which the item enters */ - itemEnterDuration?: number; - - /** Delay before the item starts to get highlighted */ - highlightStartDelay?: number; - - /** Duration in which the item gets fully highlighted */ - highlightStartDuration?: number; - - /** Delay before the item starts to get un-highlighted */ - highlightEndDelay?: number; - - /** Duration in which the item gets fully un-highlighted */ - highlightEndDuration?: number; - /** Whether the item should be highlighted */ shouldHighlight: boolean; + + /** Duration of the highlight animation */ + highlightDuration?: number; + + /** Delay before the highlight animation starts */ + delay?: number; }; /** @@ -40,60 +28,37 @@ type Props = { export default function useAnimatedHighlightStyle({ borderRadius, shouldHighlight, - itemEnterDelay = CONST.ANIMATED_HIGHLIGHT_ENTRY_DELAY, - itemEnterDuration = CONST.ANIMATED_HIGHLIGHT_ENTRY_DURATION, - highlightStartDelay = CONST.ANIMATED_HIGHLIGHT_START_DELAY, - highlightStartDuration = CONST.ANIMATED_HIGHLIGHT_START_DURATION, - highlightEndDelay = CONST.ANIMATED_HIGHLIGHT_END_DELAY, - highlightEndDuration = CONST.ANIMATED_HIGHLIGHT_END_DURATION, + highlightDuration = CONST.ANIMATED_HIGHLIGHT_DURATION, + delay = CONST.ANIMATED_HIGHLIGHT_DELAY, height, }: Props) { + const actualDelay = delay * DELAY_FACTOR; const repeatableProgress = useSharedValue(0); const nonRepeatableProgress = useSharedValue(shouldHighlight ? 0 : 1); - const {didScreenTransitionEnd} = useScreenWrapperTranstionStatus(); const theme = useTheme(); const highlightBackgroundStyle = useAnimatedStyle(() => ({ - backgroundColor: interpolateColor(repeatableProgress.value, [0, 1], [theme.appBG, theme.border]), + backgroundColor: interpolateColor(repeatableProgress.value, [0, 1], ['rgba(0, 0, 0, 0)', theme.border]), height: interpolate(nonRepeatableProgress.value, [0, 1], [0, height]), opacity: interpolate(nonRepeatableProgress.value, [0, 1], [0, 1]), borderRadius, })); React.useEffect(() => { - if (!shouldHighlight || !didScreenTransitionEnd) { + if (!shouldHighlight) { return; } InteractionManager.runAfterInteractions(() => { runOnJS(() => { - nonRepeatableProgress.value = withDelay( - itemEnterDelay, - withTiming(1, {duration: itemEnterDuration, easing: Easing.inOut(Easing.ease)}, (finished) => { - if (!finished) { - return; - } - - repeatableProgress.value = withSequence( - withDelay(highlightStartDelay, withTiming(1, {duration: highlightStartDuration, easing: Easing.inOut(Easing.ease)})), - withDelay(highlightEndDelay, withTiming(0, {duration: highlightEndDuration, easing: Easing.inOut(Easing.ease)})), - ); - }), + nonRepeatableProgress.value = withDelay(actualDelay, withTiming(1, {duration: highlightDuration, easing: Easing.inOut(Easing.ease)})); + repeatableProgress.value = withSequence( + withDelay(actualDelay, withTiming(1, {duration: highlightDuration, easing: Easing.inOut(Easing.ease)})), + withDelay(actualDelay, withTiming(0, {duration: highlightDuration, easing: Easing.inOut(Easing.ease)})), ); })(); }); - }, [ - didScreenTransitionEnd, - shouldHighlight, - itemEnterDelay, - itemEnterDuration, - highlightStartDelay, - highlightStartDuration, - highlightEndDelay, - highlightEndDuration, - repeatableProgress, - nonRepeatableProgress, - ]); + }, [shouldHighlight, highlightDuration, actualDelay, repeatableProgress, nonRepeatableProgress]); return highlightBackgroundStyle; } diff --git a/src/libs/actions/Policy.ts b/src/libs/actions/Policy.ts index 6d457f150fe6..c9f62a7a75cf 100644 --- a/src/libs/actions/Policy.ts +++ b/src/libs/actions/Policy.ts @@ -71,6 +71,7 @@ import * as TransactionUtils from '@libs/TransactionUtils'; import type {PolicySelector} from '@pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; +import type {Route} from '@src/ROUTES'; import ROUTES from '@src/ROUTES'; import type { InvitedEmailsToAccountIDs, @@ -3832,10 +3833,26 @@ function openPolicyDistanceRatesPage(policyID?: string) { API.read(READ_COMMANDS.OPEN_POLICY_DISTANCE_RATES_PAGE, params); } -function navigateWhenEnableFeature(policyID: string) { - setTimeout(() => { - Navigation.navigate(ROUTES.WORKSPACE_INITIAL.getRoute(policyID)); - }, CONST.WORKSPACE_ENABLE_FEATURE_REDIRECT_DELAY); +function navigateWhenEnableFeature(policyID: string, featureRoute: Route) { + const isNarrowLayout = getIsNarrowLayout(); + if (isNarrowLayout) { + setTimeout(() => { + Navigation.navigate(ROUTES.WORKSPACE_INITIAL.getRoute(policyID)); + }, 1000); + return; + } + + /** + * The app needs to set a navigation action to the microtask queue, it guarantees to execute Onyx.update first, then the navigation action. + * More details - https://github.com/Expensify/App/issues/37785#issuecomment-1989056726. + */ + new Promise((resolve) => { + resolve(); + }).then(() => { + requestAnimationFrame(() => { + Navigation.navigate(featureRoute); + }); + }); } function enablePolicyCategories(policyID: string, enabled: boolean) { @@ -3881,8 +3898,8 @@ function enablePolicyCategories(policyID: string, enabled: boolean) { API.write(WRITE_COMMANDS.ENABLE_POLICY_CATEGORIES, parameters, onyxData); - if (enabled && getIsNarrowLayout()) { - navigateWhenEnableFeature(policyID); + if (enabled) { + navigateWhenEnableFeature(policyID, ROUTES.WORKSPACE_CATEGORIES.getRoute(policyID)); } } @@ -3973,8 +3990,8 @@ function enablePolicyDistanceRates(policyID: string, enabled: boolean) { API.write(WRITE_COMMANDS.ENABLE_POLICY_DISTANCE_RATES, parameters, onyxData); - if (enabled && getIsNarrowLayout()) { - navigateWhenEnableFeature(policyID); + if (enabled) { + navigateWhenEnableFeature(policyID, ROUTES.WORKSPACE_DISTANCE_RATES.getRoute(policyID)); } } @@ -4065,8 +4082,8 @@ function enablePolicyTags(policyID: string, enabled: boolean) { API.write(WRITE_COMMANDS.ENABLE_POLICY_TAGS, parameters, onyxData); - if (enabled && getIsNarrowLayout()) { - navigateWhenEnableFeature(policyID); + if (enabled) { + navigateWhenEnableFeature(policyID, ROUTES.WORKSPACE_TAGS.getRoute(policyID)); } } @@ -4178,8 +4195,8 @@ function enablePolicyTaxes(policyID: string, enabled: boolean) { } API.write(WRITE_COMMANDS.ENABLE_POLICY_TAXES, parameters, onyxData); - if (enabled && getIsNarrowLayout()) { - navigateWhenEnableFeature(policyID); + if (enabled) { + navigateWhenEnableFeature(policyID, ROUTES.WORKSPACE_TAXES.getRoute(policyID)); } } @@ -4269,8 +4286,8 @@ function enablePolicyWorkflows(policyID: string, enabled: boolean) { API.write(WRITE_COMMANDS.ENABLE_POLICY_WORKFLOWS, parameters, onyxData); - if (enabled && getIsNarrowLayout()) { - navigateWhenEnableFeature(policyID); + if (enabled) { + navigateWhenEnableFeature(policyID, ROUTES.WORKSPACE_WORKFLOWS.getRoute(policyID)); } }