mattermost-mobile/app/screens/onboarding/index.tsx
Lucas Reis d38bf60050
Disable Animations when Accessibility configuration is to remove it (#8743)
* feat: add support for reduced motion in BottomSheet and TabBar components

* fix: remove reduceMotion option from animation timing in login, onboarding, and server screens

* feat: integrate reduced motion support to the entire app and switch accordingly

* feat: positions the Login screen differently if animations are disabled

* fix: remove mock implementation of useReducedMotion in react-native-reanimated

* revert login screen

* fix: remove unused effect that resets translateX value in LoginOptions

* feat: add reduced motion support to ForgotPassword screen and reset translateX on LoginOptions mount

* feat: integrate reduced motion support in Onboarding and Slide components

* feat: add reduced motion support to MFA and SSO screens

* feat: update ReducedMotionConfig to use system preference in withServerDatabase

* refactor: remove ReducedMotionConfig from withServerDatabase component

* feat: remove reduced motion configuration from screens and adjust animations accordingly

* feat: integrate reduced motion handling in Server component animations

* feat: enhance BottomSheet animation with reduced motion support and update test setup for react-native-reanimated

* fix: update channel list row snapshots with collapsable and animated props

* test: update react-native-reanimated mock setup for improved testing

* fix: enhance react-native-reanimated mock to support reduced motion and prevent default call

* fix: refactor animationConfigs to use useMemo for improved performance and clarity

* feat: implement screen transition animation hook and integrate it into ForgotPassword screen

* fix: refactor LoginOptions to utilize useScreenTransitionAnimation for improved animation handling

* refactor: streamline MFA component by removing unused imports and integrating useScreenTransitionAnimation for enhanced transitions

* refactor: simplify Onboarding component by removing unused imports and integrating useScreenTransitionAnimation for smoother transitions

* refactor: enhance useScreenTransitionAnimation hook to support animated transitions and integrate it into Server component

* refactor: replace custom animation logic with useScreenTransitionAnimation in SSO component for improved transition handling
2025-06-26 11:25:48 +02:00

160 lines
5.1 KiB
TypeScript

// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React, {useCallback, useEffect, useRef} from 'react';
import {
View,
useWindowDimensions,
SafeAreaView,
ScrollView,
StyleSheet,
type NativeSyntheticEvent,
type NativeScrollEvent,
BackHandler,
} from 'react-native';
import Animated, {useDerivedValue, useSharedValue} from 'react-native-reanimated';
import {storeOnboardingViewedValue} from '@actions/app/global';
import {Screens} from '@constants';
import {useScreenTransitionAnimation} from '@hooks/screen_transition_animation';
import SecurityManager from '@managers/security_manager';
import Background from '@screens/background';
import {goToScreen, loginAnimationOptions} from '@screens/navigation';
import FooterButtons from './footer_buttons';
import Paginator from './paginator';
import SlideItem from './slide';
import useSlidesData from './slides_data';
import type {LaunchProps} from '@typings/launch';
import type {AvailableScreens} from '@typings/screens/navigation';
interface OnboardingProps extends LaunchProps {
componentId: AvailableScreens;
theme: Theme;
}
const styles = StyleSheet.create({
onBoardingContainer: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
verticalAlign: 'top',
},
scrollContainer: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
},
});
const AnimatedSafeArea = Animated.createAnimatedComponent(SafeAreaView);
const Onboarding = ({
componentId,
theme,
...props
}: OnboardingProps) => {
const {width} = useWindowDimensions();
const {slidesData} = useSlidesData();
const LAST_SLIDE_INDEX = slidesData.length - 1;
const slidesRef = useRef<ScrollView>(null);
const scrollX = useSharedValue(0);
const currentIndex = useDerivedValue(() => Math.round(scrollX.value / width));
const moveToSlide = useCallback((slideIndexToMove: number) => {
slidesRef.current?.scrollTo({
x: (slideIndexToMove * width),
animated: true,
});
}, [width]);
const signInHandler = useCallback(() => {
// mark the onboarding as already viewed
storeOnboardingViewedValue();
goToScreen(Screens.SERVER, '', {animated: true, theme, ...props}, loginAnimationOptions());
}, []);
const nextSlide = useCallback(() => {
const nextSlideIndex = currentIndex.value + 1;
if (slidesRef.current && currentIndex.value < LAST_SLIDE_INDEX) {
moveToSlide(nextSlideIndex);
} else if (slidesRef.current && currentIndex.value === LAST_SLIDE_INDEX) {
signInHandler();
}
}, [currentIndex, moveToSlide, signInHandler]);
const scrollHandler = useCallback((event: NativeSyntheticEvent<NativeScrollEvent>) => {
scrollX.value = event.nativeEvent.contentOffset.x;
}, []);
const animatedStyles = useScreenTransitionAnimation(Screens.ONBOARDING);
useEffect(() => {
const listener = BackHandler.addEventListener('hardwareBackPress', () => {
if (!currentIndex.value) {
return false;
}
moveToSlide(currentIndex.value - 1);
return true;
});
return () => listener.remove();
}, []);
return (
<View
style={styles.onBoardingContainer}
testID='onboarding.screen'
nativeID={SecurityManager.getShieldScreenId(componentId, false, true)}
>
<Background theme={theme}/>
<AnimatedSafeArea
style={[styles.scrollContainer, animatedStyles]}
key={'onboarding_content'}
>
<ScrollView
scrollEventThrottle={16}
horizontal={true}
showsHorizontalScrollIndicator={false}
pagingEnabled={true}
bounces={false}
onScroll={scrollHandler}
ref={slidesRef}
>
{slidesData.map((item, index) => {
return (
<SlideItem
item={item}
theme={theme}
scrollX={scrollX}
index={index}
key={`key-${index.toString()}`}
lastSlideIndex={LAST_SLIDE_INDEX}
/>
);
})}
</ScrollView>
<Paginator
dataLength={slidesData.length}
theme={theme}
scrollX={scrollX}
moveToSlide={moveToSlide}
/>
<FooterButtons
theme={theme}
nextSlideHandler={nextSlide}
signInHandler={signInHandler}
scrollX={scrollX}
lastSlideIndex={LAST_SLIDE_INDEX}
/>
</AnimatedSafeArea>
</View>
);
};
export default Onboarding;