/* * 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 * as React from 'react'; import { Avatar, Button, Card, Paragraph, Portal, withTheme, } from 'react-native-paper'; import * as Animatable from 'react-native-animatable'; import { BackHandler, Dimensions, ScrollView, TouchableWithoutFeedback, View, } from 'react-native'; import Mascot from './Mascot'; import SpeechArrow from './SpeechArrow'; import AsyncStorageManager from '../../managers/AsyncStorageManager'; type PropsType = { theme: ReactNativePaper.Theme; icon: string; title: string; message: string; buttons: { action?: { message: string; icon?: string; color?: string; onPress?: () => void; }; cancel?: { message: string; icon?: string; color?: string; onPress?: () => void; }; }; emotion: number; visible?: boolean; prefKey?: string; }; type StateType = { shouldRenderDialog: boolean; // Used to stop rendering after hide animation dialogVisible: boolean; }; /** * Component used to display a popup with the mascot. */ class MascotPopup extends React.Component { mascotSize: number; windowWidth: number; windowHeight: number; constructor(props: PropsType) { super(props); this.windowWidth = Dimensions.get('window').width; this.windowHeight = Dimensions.get('window').height; this.mascotSize = Dimensions.get('window').height / 6; if (props.visible != null) { this.state = { shouldRenderDialog: props.visible, dialogVisible: props.visible, }; } else if (props.prefKey != null) { const visible = AsyncStorageManager.getBool(props.prefKey); this.state = { shouldRenderDialog: visible, dialogVisible: visible, }; } else { this.state = { shouldRenderDialog: false, dialogVisible: false, }; } } componentDidMount() { BackHandler.addEventListener( 'hardwareBackPress', this.onBackButtonPressAndroid, ); } shouldComponentUpdate(nextProps: PropsType, nextState: StateType): boolean { const {props, state} = this; if (nextProps.visible) { this.state.shouldRenderDialog = true; this.state.dialogVisible = true; } else if ( nextProps.visible !== props.visible || (!nextState.dialogVisible && nextState.dialogVisible !== state.dialogVisible) ) { this.state.dialogVisible = false; setTimeout(this.onAnimationEnd, 300); } return true; } onAnimationEnd = () => { this.setState({ shouldRenderDialog: false, }); }; onBackButtonPressAndroid = (): boolean => { const {state, props} = this; if (state.dialogVisible) { const {cancel} = props.buttons; const {action} = props.buttons; if (cancel) { this.onDismiss(cancel.onPress); } else if (action) { this.onDismiss(action.onPress); } else { this.onDismiss(); } return true; } return false; }; getSpeechBubble() { const {state, props} = this; return ( ( ) : undefined } /> {props.message} {this.getButtons()} ); } getMascot() { const {props, state} = this; return ( ); } getButtons() { const {props} = this; const {action} = props.buttons; const {cancel} = props.buttons; return ( {action != null ? ( ) : null} {cancel != null ? ( ) : null} ); } getBackground() { const {props, state} = this; return ( { this.onDismiss(props.buttons.cancel?.onPress); }}> ); } onDismiss = (callback?: () => void) => { const {prefKey} = this.props; if (prefKey != null) { AsyncStorageManager.set(prefKey, false); this.setState({dialogVisible: false}); } if (callback != null) { callback(); } }; render() { const {shouldRenderDialog} = this.state; if (shouldRenderDialog) { return ( {this.getBackground()} {this.getMascot()} {this.getSpeechBubble()} ); } return null; } } export default withTheme(MascotPopup);