From d921da0e9dffe3a3c8e15189d696fbddab7a253d Mon Sep 17 00:00:00 2001 From: Pablo Velez Vidal Date: Thu, 3 Nov 2022 13:41:16 +0100 Subject: [PATCH] add types and translate to texts --- app/screens/onboarding/footer_buttons.tsx | 25 +++++--- app/screens/onboarding/index.tsx | 11 ++-- app/screens/onboarding/paginator.tsx | 46 +++++++-------- app/screens/onboarding/slide.tsx | 10 +++- app/screens/onboarding/slides_data.ts | 69 ++++++++++++++--------- 5 files changed, 93 insertions(+), 68 deletions(-) diff --git a/app/screens/onboarding/footer_buttons.tsx b/app/screens/onboarding/footer_buttons.tsx index 00821a62b..a9160bf9b 100644 --- a/app/screens/onboarding/footer_buttons.tsx +++ b/app/screens/onboarding/footer_buttons.tsx @@ -15,8 +15,8 @@ type Props = { theme: Theme; isLastSlide: boolean; lastSlideIndex: number; - nextSlideHandler: any; - signInHandler: any; + nextSlideHandler: () => void; + signInHandler: () => void; currentIndex: number; scrollX: Animated.SharedValue; }; @@ -51,11 +51,12 @@ const FooterButtons = ({ // keep in mind penultimate and ultimate slides to run buttons animations const isPenultimateSlide = currentIndex === (lastSlideIndex - 1); const needToAnimate = isLastSlide || isPenultimateSlide; + const inputRange = [(currentIndex - 1) * width, currentIndex * width, (currentIndex + 1) * width]; const resizeStyle = useAnimatedStyle(() => { const interpolatedWidth = interpolate( scrollX.value, - [(currentIndex - 1) * width, currentIndex * width, (currentIndex + 1) * width], + inputRange, [BUTTON_SIZE, isLastSlide ? width * 0.8 : BUTTON_SIZE, width * 0.8], ); @@ -65,13 +66,23 @@ const FooterButtons = ({ const opacityTextStyle = useAnimatedStyle(() => { const interpolatedScale = interpolate( scrollX.value, - [(currentIndex - 1) * width, currentIndex * width, (currentIndex + 1) * width], + inputRange, [isPenultimateSlide ? 1 : 0, 1, 0], ); return {opacity: needToAnimate ? interpolatedScale : 1}; }); + const opacitySignInButton = useAnimatedStyle(() => { + const interpolatedScale = interpolate( + scrollX.value, + inputRange, + [1, (isLastSlide ? 0 : 1), 0], + ); + + return {opacity: needToAnimate ? interpolatedScale : 1}; + }); + let mainButtonText = ( {mainButtonText} - + ); }; diff --git a/app/screens/onboarding/index.tsx b/app/screens/onboarding/index.tsx index 22968573a..7f7019101 100644 --- a/app/screens/onboarding/index.tsx +++ b/app/screens/onboarding/index.tsx @@ -2,8 +2,8 @@ // See LICENSE.txt for license information. import React, {useCallback, useState} from 'react'; -import {View, ListRenderItemInfo, useWindowDimensions, Platform, SafeAreaView} from 'react-native'; -import Animated, {runOnJS, useAnimatedRef, useAnimatedScrollHandler, useAnimatedStyle, useSharedValue, withTiming} from 'react-native-reanimated'; +import {View, ListRenderItemInfo, useWindowDimensions, SafeAreaView} from 'react-native'; +import Animated, {runOnJS, useAnimatedRef, useAnimatedScrollHandler, useSharedValue} from 'react-native-reanimated'; import Background from '@screens/background'; import {makeStyleSheetFromTheme} from '@utils/theme'; @@ -11,7 +11,7 @@ import {makeStyleSheetFromTheme} from '@utils/theme'; import FooterButtons from './footer_buttons'; import Paginator from './paginator'; import SlideItem from './slide'; -import slidesData from './slides_data'; +import useSlidesData, {OnboardingItem} from './slides_data'; import type {LaunchProps} from '@typings/launch'; @@ -27,6 +27,7 @@ const Onboarding = ({ const {width} = useWindowDimensions(); const styles = getStyleSheet(theme); const [isLastSlide, setIsLastSlide] = useState(false); + const slidesData = useSlidesData().slidesData; const lastSlideIndex = slidesData.length - 1; const slidesRef = useAnimatedRef(); const currentIndex = useSharedValue(0); @@ -51,7 +52,7 @@ const Onboarding = ({ setIsLastSlide(!isLastSlide); }; - const renderSlide = useCallback(({item, index}: ListRenderItemInfo) => { + const renderSlide = useCallback(({item, index}: ListRenderItemInfo) => { return ( {slidesData.map((item, index) => { - return renderSlide({item, index} as ListRenderItemInfo); + return renderSlide({item, index} as ListRenderItemInfo); })} ; - moveToSlide: any; + moveToSlide: (slideIndexToMove: number) => void; }; const DOT_SIZE = 16; @@ -44,9 +46,6 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({ width: DOT_SIZE, opacity: 0.15, }, - button: { - marginTop: 5, - }, })); const Paginator = ({ @@ -56,34 +55,31 @@ const Paginator = ({ moveToSlide, }: Props) => { return ( - - - {data.map((item: any, i: number) => { - return ( - - ); - })} - + + {data.map((item: OnboardingItem, index: number) => { + return ( + + ); + })} ); }; type DotProps = { - item: any; index: number; scrollX: Animated.SharedValue; theme: Theme; - moveToSlide: any; + moveToSlide: (slideIndexToMove: number) => void; }; -const Dot = ({item, index, scrollX, theme, moveToSlide}: DotProps) => { +// this has to be extracted as a component since the useAnimatedStyle hook cant be used inside a loop +const Dot = ({index, scrollX, theme, moveToSlide}: DotProps) => { const {width} = useWindowDimensions(); const styles = getStyleSheet(theme); const inputRange = [(index - 1) * width, index * width, (index + 1) * width]; @@ -111,19 +107,15 @@ const Dot = ({item, index, scrollX, theme, moveToSlide}: DotProps) => { return ( moveToSlide(index)} - key={item.id} > ); diff --git a/app/screens/onboarding/slide.tsx b/app/screens/onboarding/slide.tsx index 8ace39a5b..49f330bea 100644 --- a/app/screens/onboarding/slide.tsx +++ b/app/screens/onboarding/slide.tsx @@ -3,13 +3,15 @@ import React from 'react'; import {View, useWindowDimensions} from 'react-native'; -import Animated, {interpolate, useAnimatedStyle} from 'react-native-reanimated'; +import Animated, {Extrapolate, interpolate, useAnimatedStyle} from 'react-native-reanimated'; import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme'; import {typography} from '@utils/typography'; +import {OnboardingItem} from './slides_data'; + type Props = { - item: any; + item: OnboardingItem; theme: Theme; scrollX: Animated.SharedValue; index: number; @@ -63,6 +65,7 @@ const SlideItem = ({theme, item, scrollX, index}: Props) => { scrollX.value, inputRange, [width * 2, 0, -width * 2], + Extrapolate.CLAMP, ); return { @@ -77,6 +80,7 @@ const SlideItem = ({theme, item, scrollX, index}: Props) => { scrollX.value, inputRange, [width * 0.6, 0, -width * 0.6], + Extrapolate.CLAMP, ); return { @@ -91,6 +95,7 @@ const SlideItem = ({theme, item, scrollX, index}: Props) => { scrollX.value, inputRange, [width * 0.2, 0, -width * 0.2], + Extrapolate.CLAMP, ); return { @@ -105,6 +110,7 @@ const SlideItem = ({theme, item, scrollX, index}: Props) => { scrollX.value, inputRange, [0.2, 1, 0.2], + Extrapolate.CLAMP, ); return {opacity: opacityInterpolate}; diff --git a/app/screens/onboarding/slides_data.ts b/app/screens/onboarding/slides_data.ts index 331dbc858..52f55916b 100644 --- a/app/screens/onboarding/slides_data.ts +++ b/app/screens/onboarding/slides_data.ts @@ -1,30 +1,45 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -// pablo - translate each text. turn svgs into react components? -export default [ - { - id: '1', - title: 'Welcome', - description: 'Mattermost is an open source platform for developer collaboration. Secure, flexible, and integrated with your tools.', - image: require('./illustrations/chat.svg').default, - }, - { - id: '2', - title: 'Collaborate in real-time', - description: 'Persistent channels, direct messaging, and file sharing works seamlessly so you can stay connected, wherever you are.', - image: require('./illustrations/team_communication.svg').default, - }, - { - id: '3', - title: 'Start secure audio calls instantly', - description: 'When typing isn’t fast enough, switch from channel-based chat to secure audio calls with a single tap.', - image: require('./illustrations/calls.svg').default, - }, - { - id: '4', - title: 'Integrate with tools you love', - description: 'Go beyond chat with tightly-integratedproduct solutions matched to common development processes.', - image: require('./illustrations/integrations.svg').default, - }, -]; +import {useIntl} from 'react-intl'; + +export type OnboardingItem = { + id: string; + title: string; + description: string; + image: string; +} +const useSalidesData = () => { + const intl = useIntl(); + + const slidesData: OnboardingItem[] = [ + { + id: '1', + title: intl.formatMessage({id: 'onboarding_screen.welcome', defaultMessage: 'Welcome'}), + description: intl.formatMessage({id: 'onboaring.welcome_description', defaultMessage: 'Mattermost is an open source platform for developer collaboration. Secure, flexible, and integrated with your tools.'}), + image: require('./illustrations/chat.svg').default, + }, + { + id: '2', + title: intl.formatMessage({id: 'onboarding.realtime_collaboration', defaultMessage: 'Collaborate in real-time'}), + description: intl.formatMessage({id: 'onboarding.realtime_collaboration_description', defaultMessage: 'Persistent channels, direct messaging, and file sharing works seamlessly so you can stay connected, wherever you are.'}), + image: require('./illustrations/team_communication.svg').default, + }, + { + id: '3', + title: intl.formatMessage({id: 'onboarding.calls', defaultMessage: 'Start secure audio calls instantly'}), + description: intl.formatMessage({id: 'onboarding.calls_description', defaultMessage: 'When typing isn’t fast enough, switch from channel-based chat to secure audio calls with a single tap.'}), + image: require('./illustrations/calls.svg').default, + }, + { + id: '4', + title: intl.formatMessage({id: 'onboarding.integrations', defaultMessage: 'Integrate with tools you love'}), + description: intl.formatMessage({id: 'onboarding.integrations_description', defaultMessage: 'Go beyond chat with tightly-integratedproduct solutions matched to common development processes.'}), + image: require('./illustrations/integrations.svg').default, + }, + ]; + + return {slidesData}; +}; + +export default useSalidesData;