Skip to content

Commit 51fc156

Browse files
Merge pull request Expensify#80454 from TaduJR/fix-Animation-Many-Pages-The-displayed-animation-cannot-be-stopped-or-paused
fix: Animation: Many Pages: The displayed animation cannot be stopped or paused
2 parents 272d224 + d28fe05 commit 51fc156

24 files changed

Lines changed: 467 additions & 126 deletions

File tree

assets/images/product-illustrations/upgrade-rocket.svg

Lines changed: 1 addition & 0 deletions
Loading

src/components/BankAccountVerificationView.tsx

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import useBottomSafeSafeAreaPaddingStyle from '@hooks/useBottomSafeSafeAreaPaddi
44
import {useMemoizedLazyIllustrations} from '@hooks/useLazyAsset';
55
import useLocalize from '@hooks/useLocalize';
66
import useThemeStyles from '@hooks/useThemeStyles';
7+
import Accessibility from '@libs/Accessibility';
78
import Navigation from '@navigation/Navigation';
89
import variables from '@styles/variables';
910
import CONST from '@src/CONST';
@@ -24,7 +25,8 @@ type BankAccountVerificationViewProps = {
2425
function BankAccountVerificationView({verificationState, children, onVerifiedButtonPress, verifiedButtonText, verifiedTitle, verifiedSubtitle}: BankAccountVerificationViewProps) {
2526
const {translate} = useLocalize();
2627
const styles = useThemeStyles();
27-
const illustrations = useMemoizedLazyIllustrations(['Puzzle']);
28+
const isReduceMotionEnabled = Accessibility.useReducedMotion();
29+
const illustrations = useMemoizedLazyIllustrations(['Puzzle', 'Fireworks']);
2830
const bottomSafeAreaPaddingStyle = useBottomSafeSafeAreaPaddingStyle({addBottomSafeAreaPadding: true});
2931

3032
if (!verificationState) {
@@ -69,14 +71,25 @@ function BankAccountVerificationView({verificationState, children, onVerifiedBut
6971
case CONST.EXPENSIFY_CARD.VERIFICATION_STATE.VERIFIED:
7072
return (
7173
<>
72-
<BlockingView
73-
title={verifiedTitle ?? translate('workspace.expensifyCard.bankAccountVerified')}
74-
subtitle={verifiedSubtitle ?? translate('workspace.expensifyCard.bankAccountVerifiedDescription')}
75-
animation={LottieAnimations.Fireworks}
76-
animationStyles={styles.loadingVBAAnimation}
77-
animationWebStyle={styles.loadingVBAAnimationWeb}
78-
subtitleStyle={styles.textLabelSupporting}
79-
/>
74+
{isReduceMotionEnabled ? (
75+
<BlockingView
76+
title={verifiedTitle ?? translate('workspace.expensifyCard.bankAccountVerified')}
77+
subtitle={verifiedSubtitle ?? translate('workspace.expensifyCard.bankAccountVerifiedDescription')}
78+
icon={illustrations.Fireworks}
79+
iconWidth={Number(styles.loadingVBAAnimation.width)}
80+
iconHeight={Number(styles.loadingVBAAnimation.height)}
81+
subtitleStyle={styles.textLabelSupporting}
82+
/>
83+
) : (
84+
<BlockingView
85+
title={verifiedTitle ?? translate('workspace.expensifyCard.bankAccountVerified')}
86+
subtitle={verifiedSubtitle ?? translate('workspace.expensifyCard.bankAccountVerifiedDescription')}
87+
animation={LottieAnimations.Fireworks}
88+
animationStyles={styles.loadingVBAAnimation}
89+
animationWebStyle={styles.loadingVBAAnimationWeb}
90+
subtitleStyle={styles.textLabelSupporting}
91+
/>
92+
)}
8093
<Button
8194
success
8295
large

src/components/ConfirmationPage.tsx

Lines changed: 39 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
import React from 'react';
22
import type {StyleProp, TextStyle, ViewStyle} from 'react-native';
33
import {StyleSheet, View} from 'react-native';
4+
import {useMemoizedLazyIllustrations} from '@hooks/useLazyAsset';
45
import useThemeStyles from '@hooks/useThemeStyles';
6+
import Accessibility from '@libs/Accessibility';
57
import isIllustrationLottieAnimation from '@libs/isIllustrationLottieAnimation';
68
import type IconAsset from '@src/types/utils/IconAsset';
79
import Button from './Button';
@@ -93,30 +95,48 @@ function ConfirmationPage({
9395
innerContainerStyle,
9496
}: ConfirmationPageProps) {
9597
const styles = useThemeStyles();
98+
const isReduceMotionEnabled = Accessibility.useReducedMotion();
99+
const illustrations = useMemoizedLazyIllustrations(['Fireworks']);
96100
const isLottie = isIllustrationLottieAnimation(illustration);
101+
const shouldShowStaticFallback = isLottie && isReduceMotionEnabled && illustration === LottieAnimations.Fireworks;
97102

98103
return (
99104
<View style={[styles.flex1, containerStyle]}>
100105
<View style={[styles.screenCenteredContainer, styles.alignItemsCenter, innerContainerStyle]}>
101-
{isLottie ? (
102-
<Lottie
103-
source={illustration}
104-
autoPlay
105-
loop
106-
style={[styles.confirmationAnimation, illustrationStyle]}
107-
webStyle={{
108-
width: (StyleSheet.flatten(illustrationStyle)?.width as number) ?? styles.confirmationAnimation.width,
109-
height: (StyleSheet.flatten(illustrationStyle)?.height as number) ?? styles.confirmationAnimation.height,
110-
}}
111-
/>
112-
) : (
113-
<View style={[styles.confirmationAnimation, illustrationStyle]}>
114-
<ImageSVG
115-
src={illustration}
116-
contentFit="contain"
117-
/>
118-
</View>
119-
)}
106+
{(() => {
107+
if (shouldShowStaticFallback) {
108+
return (
109+
<View style={[styles.confirmationAnimation, illustrationStyle]}>
110+
<ImageSVG
111+
src={illustrations.Fireworks}
112+
contentFit="contain"
113+
/>
114+
</View>
115+
);
116+
}
117+
if (isLottie) {
118+
return (
119+
<Lottie
120+
source={illustration}
121+
autoPlay
122+
loop
123+
style={[styles.confirmationAnimation, illustrationStyle]}
124+
webStyle={{
125+
width: (StyleSheet.flatten(illustrationStyle)?.width as number) ?? styles.confirmationAnimation.width,
126+
height: (StyleSheet.flatten(illustrationStyle)?.height as number) ?? styles.confirmationAnimation.height,
127+
}}
128+
/>
129+
);
130+
}
131+
return (
132+
<View style={[styles.confirmationAnimation, illustrationStyle]}>
133+
<ImageSVG
134+
src={illustration}
135+
contentFit="contain"
136+
/>
137+
</View>
138+
);
139+
})()}
120140
<Text style={[styles.textHeadline, styles.textAlignCenter, styles.mv2, headingStyle]}>{heading}</Text>
121141
{!!descriptionComponent && descriptionComponent}
122142
{!!description && <Text style={[styles.textAlignCenter, descriptionStyle, styles.w100]}>{description}</Text>}

src/components/FeatureTrainingModal.tsx

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,14 @@ import type {ImageResizeMode, ImageSourcePropType, LayoutChangeEvent, ScrollView
77
import {GestureHandlerRootView} from 'react-native-gesture-handler';
88
import type {MergeExclusive} from 'type-fest';
99
import useKeyboardState from '@hooks/useKeyboardState';
10+
import {useMemoizedLazyIllustrations} from '@hooks/useLazyAsset';
1011
import useLocalize from '@hooks/useLocalize';
1112
import useNetwork from '@hooks/useNetwork';
1213
import useResponsiveLayout from '@hooks/useResponsiveLayout';
1314
import useSafeAreaInsets from '@hooks/useSafeAreaInsets';
1415
import useStyleUtils from '@hooks/useStyleUtils';
1516
import useThemeStyles from '@hooks/useThemeStyles';
17+
import Accessibility from '@libs/Accessibility';
1618
import Log from '@libs/Log';
1719
import Navigation from '@libs/Navigation/Navigation';
1820
import variables from '@styles/variables';
@@ -205,6 +207,8 @@ function FeatureTrainingModal({
205207
const styles = useThemeStyles();
206208
const StyleUtils = useStyleUtils();
207209
const {translate} = useLocalize();
210+
const isReduceMotionEnabled = Accessibility.useReducedMotion();
211+
const illustrations = useMemoizedLazyIllustrations(['Hands']);
208212
const {onboardingIsMediumOrLargerScreenWidth} = useResponsiveLayout();
209213
const [isModalVisible, setIsModalVisible] = useState(false);
210214
const [willShowAgain, setWillShowAgain] = useState(true);
@@ -301,13 +305,20 @@ function FeatureTrainingModal({
301305
)}
302306
{((!videoURL && !image) || (!!videoURL && videoStatus === 'animation')) && (
303307
<View style={[styles.flex1, styles.alignItemsCenter, styles.justifyContentCenter, !!videoURL && {aspectRatio}, animationStyle]}>
304-
<Lottie
305-
source={animation ?? LottieAnimations.Hands}
306-
style={styles.h100}
307-
webStyle={shouldUseNarrowLayout ? styles.h100 : undefined}
308-
autoPlay
309-
loop
310-
/>
308+
{isReduceMotionEnabled && (animation ?? LottieAnimations.Hands) === LottieAnimations.Hands ? (
309+
<ImageSVG
310+
src={illustrations.Hands}
311+
style={styles.h100}
312+
/>
313+
) : (
314+
<Lottie
315+
source={animation ?? LottieAnimations.Hands}
316+
style={styles.h100}
317+
webStyle={shouldUseNarrowLayout ? styles.h100 : undefined}
318+
autoPlay
319+
loop
320+
/>
321+
)}
311322
</View>
312323
)}
313324
</View>
@@ -332,6 +343,8 @@ function FeatureTrainingModal({
332343
animationStyle,
333344
animation,
334345
shouldUseNarrowLayout,
346+
isReduceMotionEnabled,
347+
illustrations.Hands,
335348
]);
336349

337350
const toggleWillShowAgain = useCallback(() => setWillShowAgain((prevWillShowAgain) => !prevWillShowAgain), []);

src/components/Icon/Illustrations.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import LaptopWithSecondScreenX from '@assets/images/laptop-with-second-screen-x.
77
import PendingTravel from '@assets/images/pending-travel.svg';
88
import EmptyStateTravel from '@assets/images/product-illustrations/emptystate__travel.svg';
99
import Fireworks from '@assets/images/product-illustrations/fireworks.svg';
10+
import UpgradeRocket from '@assets/images/product-illustrations/upgrade-rocket.svg';
1011
import Puzzle from '@assets/images/simple-illustrations/emptystate__puzzlepieces.svg';
1112
import Abacus from '@assets/images/simple-illustrations/simple-illustration__abacus.svg';
1213
import Alert from '@assets/images/simple-illustrations/simple-illustration__alert.svg';
@@ -100,4 +101,5 @@ export {
100101
TravelCVV,
101102
ThumbsUpStars,
102103
TurtleInShell,
104+
UpgradeRocket,
103105
};

src/components/Icon/chunks/illustrations.chunk.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ import TiltedCoinExpensify from '@assets/images/product-illustrations/tilted-coi
8686
import ToddBehindCloud from '@assets/images/product-illustrations/todd-behind-cloud.svg';
8787
import ToddInCar from '@assets/images/product-illustrations/todd-in-car.svg';
8888
import ToddWithPhones from '@assets/images/product-illustrations/todd-with-phones.svg';
89+
import UpgradeRocket from '@assets/images/product-illustrations/upgrade-rocket.svg';
8990
import WorkspaceScene from '@assets/images/product-illustrations/workspace-scene.svg';
9091
import ReceiptStack from '@assets/images/receipt-upload.svg';
9192
import RunningTurtle from '@assets/images/running-turtle.svg';
@@ -276,6 +277,7 @@ const Illustrations = {
276277
ToddInCar,
277278
ToddWithPhones,
278279
WorkspaceScene,
280+
UpgradeRocket,
279281

280282
// Educational Illustrations
281283
MultiScan,

src/components/Lottie/index.tsx

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,11 @@ import type {AnimationObject, LottieViewProps} from 'lottie-react-native';
33
import LottieView from 'lottie-react-native';
44
import React, {useContext, useEffect, useRef, useState} from 'react';
55
import {InteractionManager, View} from 'react-native';
6-
import {useReducedMotion} from 'react-native-reanimated';
76
import type DotLottieAnimation from '@components/LottieAnimations/types';
87
import useAppState from '@hooks/useAppState';
98
import useNetwork from '@hooks/useNetwork';
109
import useThemeStyles from '@hooks/useThemeStyles';
10+
import Accessibility from '@libs/Accessibility';
1111
import {getBrowser, isMobile} from '@libs/Browser';
1212
import isSideModalNavigator from '@libs/Navigation/helpers/isSideModalNavigator';
1313
import CONST from '@src/CONST';
@@ -24,7 +24,7 @@ function Lottie({source, webStyle, shouldLoadAfterInteractions, ...props}: Props
2424
const {splashScreenState} = useSplashScreenState();
2525
const styles = useThemeStyles();
2626
const [isError, setIsError] = React.useState(false);
27-
const isReducedMotionEnabled = useReducedMotion();
27+
const isReduceMotionEnabled = Accessibility.useReducedMotion();
2828

2929
useNetwork({onReconnect: () => setIsError(false)});
3030

@@ -64,12 +64,12 @@ function Lottie({source, webStyle, shouldLoadAfterInteractions, ...props}: Props
6464
}
6565
const unsubscribeNavigationFocus = navigator.addListener('focus', () => {
6666
setHasNavigatedAway(false);
67-
if (!isReducedMotionEnabled) {
67+
if (!isReduceMotionEnabled) {
6868
animationRef.current?.play();
6969
}
7070
});
7171
return unsubscribeNavigationFocus;
72-
}, [browser, navigationContainerRef, navigator, isReducedMotionEnabled]);
72+
}, [browser, navigationContainerRef, navigator, isReduceMotionEnabled]);
7373

7474
useEffect(() => {
7575
if (!browser || !navigationContainerRef || !navigator) {
@@ -118,13 +118,12 @@ function Lottie({source, webStyle, shouldLoadAfterInteractions, ...props}: Props
118118
<LottieView
119119
// eslint-disable-next-line react/jsx-props-no-spreading
120120
{...props}
121-
autoPlay={isReducedMotionEnabled ? false : props.autoPlay}
122-
loop={isReducedMotionEnabled ? false : props.loop}
123121
source={animationFile}
124122
key={`${hasNavigatedAway}`}
125123
ref={(newRef) => {
126124
animationRef.current = newRef;
127125
}}
126+
autoPlay={!isReduceMotionEnabled}
128127
style={[aspectRatioStyle, props.style]}
129128
webStyle={{...aspectRatioStyle, ...webStyle}}
130129
onAnimationFailure={() => setIsError(true)}

0 commit comments

Comments
 (0)