diff --git a/app/screens/onboarding/footer_buttons.tsx b/app/screens/onboarding/footer_buttons.tsx index 47e41ad58..0d5ab9494 100644 --- a/app/screens/onboarding/footer_buttons.tsx +++ b/app/screens/onboarding/footer_buttons.tsx @@ -4,7 +4,7 @@ import React, {useEffect} from 'react'; import {Pressable, useWindowDimensions, View} from 'react-native'; import Button from 'react-native-button'; -import Animated, {useAnimatedStyle, useSharedValue, withTiming} from 'react-native-reanimated'; +import Animated, {interpolate, useAnimatedStyle, useSharedValue, withTiming} from 'react-native-reanimated'; import CompassIcon from '@app/components/compass_icon'; import FormattedText from '@app/components/formatted_text'; @@ -14,9 +14,11 @@ import {makeStyleSheetFromTheme} from '@utils/theme'; type Props = { theme: Theme; isLastSlide: boolean; + lastSlideIndex: number; nextSlideHandler: any; signInHandler: any; - + currentIndex: number; + scrollX: Animated.SharedValue; }; const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({ @@ -38,29 +40,40 @@ const FooterButtons = ({ nextSlideHandler, signInHandler, isLastSlide, + lastSlideIndex, + currentIndex, + scrollX, }: Props) => { const {width} = useWindowDimensions(); const styles = getStyleSheet(theme); + const BUTTON_SIZE = 80; - const scaledWidth = useSharedValue(80); + // keep in mind penultimate and ultimate slides to run buttons animations + const isPenultimateSlide = currentIndex === (lastSlideIndex - 1); + const needToAnimate = isLastSlide || isPenultimateSlide; - const transform = useAnimatedStyle(() => { - return { - width: scaledWidth.value, - }; + const resizeStyle = useAnimatedStyle(() => { + const interpolatedWidth = interpolate( + scrollX.value, + [(currentIndex - 1) * width, currentIndex * width, (currentIndex + 1) * width], + [BUTTON_SIZE, isLastSlide ? width * 0.8 : BUTTON_SIZE, width * 0.8], + ); + + return {width: needToAnimate ? interpolatedWidth : BUTTON_SIZE}; }); - useEffect(() => { - console.log('** footer buttons rerender', isLastSlide); - }, []); + const opacityTextStyle = useAnimatedStyle(() => { + const interpolatedScale = interpolate( + scrollX.value, + [(currentIndex - 1) * width, currentIndex * width, (currentIndex + 1) * width], + [isPenultimateSlide ? 1 : 0, 1, 0], + ); - useEffect(() => { - console.log('** footer buttons rerender', isLastSlide); - scaledWidth.value = withTiming(isLastSlide ? ((width * 80) / 100) : 80, {duration: 100}); - }, [isLastSlide]); + return {opacity: needToAnimate ? interpolatedScale : 1}; + }); let mainButtonText = ( - + - + ); let mainButtonAction = nextSlideHandler; if (isLastSlide) { mainButtonText = ( - + + + ); mainButtonAction = signInHandler; } @@ -91,7 +106,7 @@ const FooterButtons = ({ mainButtonAction()} - style={[styles.button, buttonBackgroundStyle(theme, 'm', 'primary', 'default'), transform]} + style={[styles.button, buttonBackgroundStyle(theme, 'm', 'primary', 'default'), resizeStyle]} > {mainButtonText} diff --git a/app/screens/onboarding/index.tsx b/app/screens/onboarding/index.tsx index 40af623ae..9752ef298 100644 --- a/app/screens/onboarding/index.tsx +++ b/app/screens/onboarding/index.tsx @@ -51,12 +51,12 @@ const Onboarding = ({ setIsLastSlide(!isLastSlide); }; - const transform = useAnimatedStyle(() => { - const duration = Platform.OS === 'android' ? 250 : 350; - return { - transform: [{translateX: withTiming(scrollX.value, {duration})}], - }; - }, []); + // const transform = useAnimatedStyle(() => { + // const duration = Platform.OS === 'android' ? 250 : 350; + // return { + // transform: [{translateX: withTiming(scrollX.value, {duration})}], + // }; + // }, []); const renderSlide = useCallback(({item, index}: ListRenderItemInfo) => { return ( @@ -76,7 +76,7 @@ const Onboarding = ({ const handleScroll = useAnimatedScrollHandler(({contentOffset: {x}}) => { const calculatedIndex = Math.round(x / width); - + scrollX.value = x; if (calculatedIndex !== currentIndex.value) { currentIndex.value = calculatedIndex; runOnJS(toogleIsLastSlideValue)(calculatedIndex === lastSlideIndex); @@ -91,7 +91,7 @@ const Onboarding = ({ diff --git a/app/screens/onboarding/paginator.tsx b/app/screens/onboarding/paginator.tsx index 0351a3c5f..5480f659c 100644 --- a/app/screens/onboarding/paginator.tsx +++ b/app/screens/onboarding/paginator.tsx @@ -3,7 +3,7 @@ import React from 'react'; import {View, useWindowDimensions, TouchableOpacity} from 'react-native'; -import Animated from 'react-native-reanimated'; +import Animated, {interpolate, useAnimatedStyle} from 'react-native-reanimated'; import {makeStyleSheetFromTheme} from '@utils/theme'; @@ -23,6 +23,7 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({ backgroundColor: theme.buttonBg, marginHorizontal: DOT_SIZE / 2, width: DOT_SIZE / 2, + opacity: 0.25, }, outerDot: { height: DOT_SIZE, @@ -32,6 +33,7 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({ marginTop: -4, position: 'absolute', width: DOT_SIZE, + opacity: 0.15, }, button: { marginTop: 5, @@ -44,47 +46,19 @@ const Paginator = ({ scrollX, moveToSlide, }: Props) => { - const styles = getStyleSheet(theme); - const {width} = useWindowDimensions(); - return ( {data.map((item: any, i: number) => { - // const inputRange = [(i - 1) * width, i * width, (i + 1) * width]; - - // const opacity = scrollX.interpolate({ - // inputRange, - // outputRange: [0.25, 1, 0.25], - // extrapolate: 'clamp', - // }); - - // const opacityOuterDot = scrollX.interpolate({ - // inputRange, - // outputRange: [0, 0.15, 0], - // extrapolate: 'clamp', - // }); - return ( - moveToSlide(i)} + - - - + theme={theme} + moveToSlide={moveToSlide} + index={i} + scrollX={scrollX} + /> ); })} @@ -92,4 +66,54 @@ const Paginator = ({ ); }; +type DotProps = { + item: any; + index: number; + scrollX: Animated.SharedValue; + theme: Theme; + moveToSlide: any; +}; + +const Dot = ({item, index, scrollX, theme, moveToSlide}: DotProps) => { + const {width} = useWindowDimensions(); + const styles = getStyleSheet(theme); + const inputRange = [(index - 1) * width, index * width, (index + 1) * width]; + + const dotOpacity = useAnimatedStyle(() => { + const opacity = interpolate( + scrollX.value, + inputRange, + [0.25, 1, 0.25], + ); + + return {opacity}; + }); + + const outerDotOpacity = useAnimatedStyle(() => { + const opacity = interpolate( + scrollX.value, + inputRange, + [0, 0.15, 0], + ); + + return {opacity}; + }); + + return ( + moveToSlide(index)} + key={item.id} + > + + + + ); +}; + export default Paginator;