/* * Copyright (c) 2019 - 2020 Arnaud Vergnet. * * This file is part of Campus INSAT. * * Campus INSAT is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Campus INSAT is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Campus INSAT. If not, see . */ import React, { useEffect, useRef, useState } from 'react'; import { Portal } from 'react-native-paper'; import * as Animatable from 'react-native-animatable'; import { BackHandler, Dimensions, StyleSheet, TouchableWithoutFeedback, View, } from 'react-native'; import Mascot from './Mascot'; import GENERAL_STYLES from '../../constants/Styles'; import MascotSpeechBubble, { MascotSpeechBubbleProps, } from './MascotSpeechBubble'; import { useMountEffect } from '../../utils/customHooks'; import { useRoute } from '@react-navigation/core'; import { useShouldShowMascot } from '../../context/preferencesContext'; type PropsType = MascotSpeechBubbleProps & { emotion: number; visible?: boolean; }; const styles = StyleSheet.create({ background: { position: 'absolute', backgroundColor: 'rgba(0,0,0,0.7)', width: '100%', height: '100%', }, container: { marginTop: -80, width: '100%', }, }); const MASCOT_SIZE = Dimensions.get('window').height / 6; const BUBBLE_HEIGHT = Dimensions.get('window').height / 3; /** * Component used to display a popup with the mascot. */ function MascotPopup(props: PropsType) { const route = useRoute(); const { shouldShow, setShouldShow } = useShouldShowMascot(route.name); const isVisible = () => { if (props.visible !== undefined) { return props.visible; } else { return shouldShow; } }; const [shouldRenderDialog, setShouldRenderDialog] = useState(isVisible()); const [dialogVisible, setDialogVisible] = useState(isVisible()); const lastVisibleProps = useRef(props.visible); const lastVisibleState = useRef(dialogVisible); useMountEffect(() => { BackHandler.addEventListener('hardwareBackPress', onBackButtonPressAndroid); }); useEffect(() => { if (props.visible && !dialogVisible) { setShouldRenderDialog(true); setDialogVisible(true); } else if ( lastVisibleProps.current !== props.visible || (!dialogVisible && dialogVisible !== lastVisibleState.current) ) { setDialogVisible(false); setTimeout(onAnimationEnd, 400); } lastVisibleProps.current = props.visible; lastVisibleState.current = dialogVisible; }, [props.visible, dialogVisible]); const onAnimationEnd = () => { setShouldRenderDialog(false); }; const onBackButtonPressAndroid = (): boolean => { if (dialogVisible) { const { cancel } = props.buttons; const { action } = props.buttons; if (cancel) { onDismiss(cancel.onPress); } else if (action) { onDismiss(action.onPress); } else { onDismiss(); } return true; } return false; }; const getSpeechBubble = () => { return ( ); }; const getMascot = () => { return ( ); }; const getBackground = () => { return ( { onDismiss(props.buttons.cancel?.onPress); }} > ); }; const onDismiss = (callback?: () => void) => { setShouldShow(false); setDialogVisible(false); if (callback) { callback(); } }; if (shouldRenderDialog) { return ( {getBackground()} {getMascot()} {getSpeechBubble()} ); } return null; } export default MascotPopup;