diff --git a/app/screens/onboarding/footer_buttons.tsx b/app/screens/onboarding/footer_buttons.tsx index a9160bf9b..726df2637 100644 --- a/app/screens/onboarding/footer_buttons.tsx +++ b/app/screens/onboarding/footer_buttons.tsx @@ -3,8 +3,7 @@ import React from 'react'; import {Pressable, useWindowDimensions, View} from 'react-native'; -import Button from 'react-native-button'; -import Animated, {interpolate, useAnimatedStyle} from 'react-native-reanimated'; +import Animated, {Extrapolate, interpolate, useAnimatedStyle} from 'react-native-reanimated'; import CompassIcon from '@app/components/compass_icon'; import FormattedText from '@app/components/formatted_text'; @@ -58,6 +57,7 @@ const FooterButtons = ({ scrollX.value, inputRange, [BUTTON_SIZE, isLastSlide ? width * 0.8 : BUTTON_SIZE, width * 0.8], + Extrapolate.CLAMP, ); return {width: needToAnimate ? interpolatedWidth : BUTTON_SIZE}; @@ -68,6 +68,7 @@ const FooterButtons = ({ scrollX.value, inputRange, [isPenultimateSlide ? 1 : 0, 1, 0], + Extrapolate.CLAMP, ); return {opacity: needToAnimate ? interpolatedScale : 1}; @@ -78,6 +79,7 @@ const FooterButtons = ({ scrollX.value, inputRange, [1, (isLastSlide ? 0 : 1), 0], + Extrapolate.CLAMP, ); return {opacity: needToAnimate ? interpolatedScale : 1}; diff --git a/app/screens/onboarding/index.tsx b/app/screens/onboarding/index.tsx index 7f7019101..8591d65f6 100644 --- a/app/screens/onboarding/index.tsx +++ b/app/screens/onboarding/index.tsx @@ -93,7 +93,7 @@ const Onboarding = ({ showsHorizontalScrollIndicator={false} pagingEnabled={true} bounces={false} - onMomentumScrollEnd={handleScroll} + onScroll={handleScroll} ref={slidesRef} > {slidesData.map((item, index) => { diff --git a/app/screens/onboarding/slide.tsx b/app/screens/onboarding/slide.tsx index 49f330bea..09bbc206e 100644 --- a/app/screens/onboarding/slide.tsx +++ b/app/screens/onboarding/slide.tsx @@ -1,9 +1,9 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import React from 'react'; +import React, { useEffect, useState } from 'react'; import {View, useWindowDimensions} from 'react-native'; -import Animated, {Extrapolate, interpolate, useAnimatedStyle} from 'react-native-reanimated'; +import Animated, {Extrapolate, interpolate, useAnimatedStyle, useSharedValue, withTiming} from 'react-native-reanimated'; import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme'; import {typography} from '@utils/typography'; @@ -31,6 +31,10 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({ fontFirstTitle: { fontSize: 66, }, + firstSlideInitialPosition: { + left: 200, + opacity: 0, + }, description: { fontWeight: '400', fontSize: 16, @@ -56,8 +60,59 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({ const SlideItem = ({theme, item, scrollX, index}: Props) => { const {width} = useWindowDimensions(); const styles = getStyleSheet(theme); + const FIRST_SLIDE = 0; const SvgImg = item.image; + /** + * Code used to animate the first image load + */ + const FIRST_LOAD_ELEMENTS_POSITION = 400; + const [firstLoad, setFirstLoad] = useState(true); + + const initialImagePosition = useSharedValue(FIRST_LOAD_ELEMENTS_POSITION); + const initialTitlePosition = useSharedValue(FIRST_LOAD_ELEMENTS_POSITION); + const initialDescriptionPosition = useSharedValue(FIRST_LOAD_ELEMENTS_POSITION); + + const initialElementsOpacity = useSharedValue(0); + + useEffect(() => { + if (index === FIRST_SLIDE) { + initialImagePosition.value = withTiming(0, {duration: 1000}); + initialTitlePosition.value = withTiming(0, {duration: 1250}); + initialDescriptionPosition.value = withTiming(0, {duration: 1500}); + + initialElementsOpacity.value = withTiming(1, {duration: 1500}); + setFirstLoad(false); + } + }, []); + + const translateFirstImageOnLoad = useAnimatedStyle(() => { + return { + transform: [{ + translateX: initialImagePosition.value, + }], + opacity: initialElementsOpacity.value, + }; + }); + + const translateFirstTitleOnLoad = useAnimatedStyle(() => { + return { + transform: [{ + translateX: initialTitlePosition.value, + }], + opacity: initialElementsOpacity.value, + }; + }); + + const translateFirstDescriptionOnLoad = useAnimatedStyle(() => { + return { + transform: [{ + translateX: initialDescriptionPosition.value, + }], + opacity: initialElementsOpacity.value, + }; + });// end of code for animating first image load + const inputRange = [(index - 1) * width, index * width, (index + 1) * width]; const translateImage = useAnimatedStyle(() => { @@ -119,7 +174,11 @@ const SlideItem = ({theme, item, scrollX, index}: Props) => { return ( { {item.title} {item.description}