/* * 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 * as Animatable from 'react-native-animatable'; import { Image, StyleSheet, TouchableWithoutFeedback, View, ViewStyle, } from 'react-native'; import { AnimatableProperties } from 'react-native-animatable'; export type AnimatableViewRefType = { current: null | (typeof Animatable.View & View); }; type PropsType = { emotion?: MASCOT_STYLE; animated?: boolean; style?: ViewStyle; entryAnimation?: AnimatableProperties; loopAnimation?: AnimatableProperties; onPress?: null | ((viewRef: AnimatableViewRefType) => void); onLongPress?: null | ((viewRef: AnimatableViewRefType) => void); }; type StateType = { currentEmotion: MASCOT_STYLE; }; const MASCOT_IMAGE = require('../../../assets/mascot/mascot.png'); const MASCOT_EYES_NORMAL = require('../../../assets/mascot/mascot_eyes_normal.png'); const MASCOT_EYES_GIRLY = require('../../../assets/mascot/mascot_eyes_girly.png'); const MASCOT_EYES_CUTE = require('../../../assets/mascot/mascot_eyes_cute.png'); const MASCOT_EYES_WINK = require('../../../assets/mascot/mascot_eyes_wink.png'); const MASCOT_EYES_HEART = require('../../../assets/mascot/mascot_eyes_heart.png'); const MASCOT_EYES_ANGRY = require('../../../assets/mascot/mascot_eyes_angry.png'); const MASCOT_GLASSES = require('../../../assets/mascot/mascot_glasses.png'); const MASCOT_SUNGLASSES = require('../../../assets/mascot/mascot_sunglasses.png'); enum EYE_STYLE { NORMAL, GIRLY, CUTE, WINK, HEART, ANGRY, } enum GLASSES_STYLE { NORMAL, COOl, } export enum MASCOT_STYLE { NORMAL, HAPPY, GIRLY, WINK, CUTE, INTELLO, LOVE, COOL, ANGRY, RANDOM = 999, } const styles = StyleSheet.create({ container: { aspectRatio: 1, }, mascot: { width: '100%', height: '100%', }, glassesImage: { position: 'absolute', top: '15%', left: 0, width: '100%', height: '100%', }, eyesImage: { position: 'absolute', top: '15%', width: '100%', height: '100%', }, eyesContainer: { position: 'absolute', width: '100%', height: '100%', }, }); class Mascot extends React.Component { static defaultProps = { emotion: MASCOT_STYLE.NORMAL, animated: false, style: null, entryAnimation: { useNativeDriver: true, animation: 'rubberBand', duration: 2000, }, loopAnimation: { useNativeDriver: true, animation: 'swing', duration: 2000, iterationDelay: 250, iterationCount: 'infinite', }, onPress: null, onLongPress: null, }; viewRef: AnimatableViewRefType; eyeList: { [key in EYE_STYLE]: number }; glassesList: { [key in GLASSES_STYLE]: number }; onPress: (viewRef: AnimatableViewRefType) => void; onLongPress: (viewRef: AnimatableViewRefType) => void; initialEmotion: number; constructor(props: PropsType) { super(props); this.viewRef = React.createRef(); this.eyeList = { [EYE_STYLE.NORMAL]: MASCOT_EYES_NORMAL, [EYE_STYLE.GIRLY]: MASCOT_EYES_GIRLY, [EYE_STYLE.CUTE]: MASCOT_EYES_CUTE, [EYE_STYLE.WINK]: MASCOT_EYES_WINK, [EYE_STYLE.HEART]: MASCOT_EYES_HEART, [EYE_STYLE.ANGRY]: MASCOT_EYES_ANGRY, }; this.glassesList = { [GLASSES_STYLE.NORMAL]: MASCOT_GLASSES, [GLASSES_STYLE.COOl]: MASCOT_SUNGLASSES, }; this.initialEmotion = props.emotion ? props.emotion : Mascot.defaultProps.emotion; if (this.initialEmotion === MASCOT_STYLE.RANDOM) { this.initialEmotion = Math.floor(Math.random() * MASCOT_STYLE.ANGRY) + 1; } this.state = { currentEmotion: this.initialEmotion, }; if (props.onPress == null) { this.onPress = (viewRef: AnimatableViewRefType) => { const ref = viewRef.current; if (ref && ref.rubberBand) { this.setState({ currentEmotion: MASCOT_STYLE.LOVE }); ref.rubberBand(1500).then(() => { this.setState({ currentEmotion: this.initialEmotion }); }); } }; } else { this.onPress = props.onPress; } if (props.onLongPress == null) { this.onLongPress = (viewRef: AnimatableViewRefType) => { const ref = viewRef.current; if (ref && ref.tada) { this.setState({ currentEmotion: MASCOT_STYLE.ANGRY }); ref.tada(1000).then(() => { this.setState({ currentEmotion: this.initialEmotion }); }); } }; } else { this.onLongPress = props.onLongPress; } } getGlasses(style: GLASSES_STYLE) { const glasses = this.glassesList[style]; return ( ); } getEye(style: EYE_STYLE, isRight: boolean, rotation: string = '0deg') { const eye = this.eyeList[style]; const left = isRight ? '-11%' : '11%'; return ( ); } getEyes(emotion: MASCOT_STYLE) { const final = []; final.push(); if (emotion === MASCOT_STYLE.CUTE) { final.push(this.getEye(EYE_STYLE.CUTE, true)); final.push(this.getEye(EYE_STYLE.CUTE, false)); } else if (emotion === MASCOT_STYLE.GIRLY) { final.push(this.getEye(EYE_STYLE.GIRLY, true)); final.push(this.getEye(EYE_STYLE.GIRLY, false)); } else if (emotion === MASCOT_STYLE.HAPPY) { final.push(this.getEye(EYE_STYLE.WINK, true)); final.push(this.getEye(EYE_STYLE.WINK, false)); } else if (emotion === MASCOT_STYLE.WINK) { final.push(this.getEye(EYE_STYLE.WINK, true)); final.push(this.getEye(EYE_STYLE.NORMAL, false)); } else if (emotion === MASCOT_STYLE.LOVE) { final.push(this.getEye(EYE_STYLE.HEART, true)); final.push(this.getEye(EYE_STYLE.HEART, false)); } else if (emotion === MASCOT_STYLE.ANGRY) { final.push(this.getEye(EYE_STYLE.ANGRY, true)); final.push(this.getEye(EYE_STYLE.ANGRY, false, '180deg')); } else if (emotion === MASCOT_STYLE.COOL) { final.push(this.getGlasses(GLASSES_STYLE.COOl)); } else { final.push(this.getEye(EYE_STYLE.NORMAL, true)); final.push(this.getEye(EYE_STYLE.NORMAL, false)); } if (emotion === MASCOT_STYLE.INTELLO) { // Needs to have normal eyes behind the glasses final.push(this.getGlasses(GLASSES_STYLE.NORMAL)); } final.push(); return final; } render() { const { props, state } = this; const entryAnimation = props.animated ? props.entryAnimation : null; const loopAnimation = props.animated ? props.loopAnimation : null; return ( { this.onPress(this.viewRef); }} onLongPress={() => { this.onLongPress(this.viewRef); }} > {this.getEyes(state.currentEmotion)} ); } } export default Mascot;