From e4dc8dbbfe17f7a30e15a695da15547373f0e4f7 Mon Sep 17 00:00:00 2001 From: Rajat Dabade Date: Wed, 23 Oct 2024 16:17:37 +0530 Subject: [PATCH] =?UTF-8?q?MM-59973:=20fix=20the=20emoji=20count=200=20iss?= =?UTF-8?q?ue=20when=20archive=20and=20unarchive=20chan=E2=80=A6=20(#8146)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * MM-59973: fix the emoji count 0 issue when archive and unarchive channels * ref to null and initialing it * refactor: added a safe condition * refactor code * more clean up * clean-ups * index to tosting as a key to component * refactor code * fix: (MM-59973) emoji count 0 update (#8256) * reversed from all useMemo to useMemo + useEffect * tried to include everything into useMemo was an anti-pattern * moved back to useMemo + useEffect * previousNumber and animateToNumber comparison has some flaw when dealing with difference length between the two * simple fix * fix more silly mistakes * move _previousNumberString to constant * Test: increase timeout-minutes to 120 for e2e test * reverted the timeout-minutes back to 40 --------- Co-authored-by: Rahim Rahman Co-authored-by: Mattermost Build --- app/components/animated_number/index.tsx | 141 +++++++++++++---------- 1 file changed, 82 insertions(+), 59 deletions(-) diff --git a/app/components/animated_number/index.tsx b/app/components/animated_number/index.tsx index 6b15b439a..3b8ee973f 100644 --- a/app/components/animated_number/index.tsx +++ b/app/components/animated_number/index.tsx @@ -1,14 +1,14 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import React, {useCallback, useMemo} from 'react'; +import React, {useCallback, useEffect, useMemo, useState} from 'react'; import {Animated, Easing, type LayoutChangeEvent, type StyleProp, Text, type TextStyle, View} from 'react-native'; interface Props { animateToNumber: number; fontStyle?: StyleProp; animationDuration?: number; - easing?: ((input: number) => number) | undefined; + easing?: number; } const NUMBERS = Array(10).fill(null).map((_, i) => i); @@ -24,46 +24,73 @@ const usePrevious = (value: number) => { const AnimatedNumber = ({ animateToNumber, - animationDuration, + animationDuration = 1400, fontStyle, - easing, + easing = 1.2, }: Props) => { - const prevNumber = usePrevious(animateToNumber); + const previousNumber = usePrevious(animateToNumber); + const [numberHeight, setNumberHeight] = useState(0); + const animateToNumberString = String(Math.abs(animateToNumber)); - const prevNumberString = String(Math.abs(prevNumber)); - const numberStringToDigitsArray = Array.from(animateToNumberString, Number); - const prevNumberersArr = Array.from(prevNumberString, Number); + const previousNumberString = useMemo(() => { + // comparing previousNumber and animateToNumber gets trickier when the number of digits changes and the length differs. + // By padding the previousNumber with 0s, or slicing the previousNumber to match the length of animateToNumber + // we can compare them digit by digit + const _previousNumberString = String(Math.abs(previousNumber)).padStart( + animateToNumberString.length, + '0', + ); - const [numberHeight, setNumberHeight] = React.useState(0); - const animations = useMemo(() => numberStringToDigitsArray.map((__, index) => { - if (typeof prevNumberersArr[index] !== 'number') { - return new Animated.Value(0); + if (_previousNumberString.length > animateToNumberString.length) { + _previousNumberString.slice(_previousNumberString.length - animateToNumberString.length); } - const animationHeight = -1 * (numberHeight * prevNumberersArr[index]); - return new Animated.Value(animationHeight); - }), [numberStringToDigitsArray]); + return _previousNumberString; + }, [animateToNumberString, previousNumber]); + + const animations = useMemo(() => { + const animateToNumberArray = Array.from(animateToNumberString, Number); + + if (!numberHeight) { + return animateToNumberArray.map(() => new Animated.Value(0)); + } + + const previousNumberArray = Array.from(previousNumberString, Number); + + return animateToNumberArray.map((_, index) => { + const useDigit = previousNumberArray[index] === animateToNumberArray[index] ? animateToNumberArray[index] : previousNumberArray[index]; + + return new Animated.Value(-1 * (numberHeight * useDigit)); + }); + }, [animateToNumberString, numberHeight, previousNumberString]); + + useEffect(() => { + if (!numberHeight) { + return; + } + + const animateToNumberArray = Array.from(animateToNumberString, Number); + animations.forEach((animation, index) => { + Animated.timing(animation, { + toValue: -1 * (numberHeight * animateToNumberArray[index]), + duration: animationDuration, + useNativeDriver: true, + easing: Easing.elastic(easing), + }).start(); + }); + }, [ + animateToNumberString, + animationDuration, + animations, + easing, + numberHeight, + ]); const setButtonLayout = useCallback((e: LayoutChangeEvent) => { setNumberHeight(e.nativeEvent.layout.height); }, []); - React.useEffect(() => { - animations.forEach((animation, index) => { - Animated.timing(animation, { - toValue: -1 * (numberHeight * numberStringToDigitsArray[index]), - duration: animationDuration || 1400, - useNativeDriver: true, - easing: easing || Easing.elastic(1.2), - }).start(); - }); - }, [animateToNumber, animationDuration, fontStyle, numberHeight]); - - const getTranslateY = (index: number) => { - return animations[index]; - }; - return ( <> {numberHeight !== 0 && ( @@ -71,37 +98,33 @@ const AnimatedNumber = ({ {animateToNumber < 0 && ( {'-'} )} - {numberStringToDigitsArray.map((n, index) => { - return ( - - ( + + - {NUMBERS.map((number, i) => ( - - - {number} - - - ))} - - - ); - })} + ], + }} + > + {NUMBERS.map((number, i) => ( + + + {number} + + + ))} + + + ))} )} {numberHeight === 0 &&