Improved mascot style management

This commit is contained in:
Arnaud Vergnet 2020-07-20 16:36:16 +02:00
parent de41a57930
commit 0ed3122dcf
6 changed files with 119 additions and 102 deletions

View file

@ -3,9 +3,10 @@
import * as React from 'react'; import * as React from 'react';
import * as Animatable from "react-native-animatable"; import * as Animatable from "react-native-animatable";
import {Image, TouchableWithoutFeedback, View} from "react-native"; import {Image, TouchableWithoutFeedback, View} from "react-native";
import type {ViewStyle} from "react-native/Libraries/StyleSheet/StyleSheet";
type Props = { type Props = {
size: number, style?: ViewStyle,
emotion: number, emotion: number,
animated: boolean, animated: boolean,
entryAnimation: Animatable.AnimatableProperties | null, entryAnimation: Animatable.AnimatableProperties | null,
@ -116,9 +117,10 @@ class Mascot extends React.Component<Props, State> {
if (this.props.onPress == null) { if (this.props.onPress == null) {
this.onPress = (viewRef: AnimatableViewRef) => { this.onPress = (viewRef: AnimatableViewRef) => {
if (viewRef.current != null) { let ref = viewRef.current;
if (ref != null) {
this.setState({currentEmotion: MASCOT_STYLE.LOVE}); this.setState({currentEmotion: MASCOT_STYLE.LOVE});
viewRef.current.rubberBand(1500).then(() => { ref.rubberBand(1500).then(() => {
this.setState({currentEmotion: this.initialEmotion}); this.setState({currentEmotion: this.initialEmotion});
}); });
@ -130,9 +132,10 @@ class Mascot extends React.Component<Props, State> {
if (this.props.onLongPress == null) { if (this.props.onLongPress == null) {
this.onLongPress = (viewRef: AnimatableViewRef) => { this.onLongPress = (viewRef: AnimatableViewRef) => {
if (viewRef.current != null) { let ref = viewRef.current;
if (ref != null) {
this.setState({currentEmotion: MASCOT_STYLE.ANGRY}); this.setState({currentEmotion: MASCOT_STYLE.ANGRY});
viewRef.current.tada(1000).then(() => { ref.tada(1000).then(() => {
this.setState({currentEmotion: this.initialEmotion}); this.setState({currentEmotion: this.initialEmotion});
}); });
@ -153,8 +156,8 @@ class Mascot extends React.Component<Props, State> {
position: "absolute", position: "absolute",
top: "15%", top: "15%",
left: 0, left: 0,
width: this.props.size, width: "100%",
height: this.props.size, height: "100%",
}} }}
/> />
} }
@ -168,8 +171,8 @@ class Mascot extends React.Component<Props, State> {
position: "absolute", position: "absolute",
top: "15%", top: "15%",
left: isRight ? "-11%" : "11%", left: isRight ? "-11%" : "11%",
width: this.props.size, width: "100%",
height: this.props.size, height: "100%",
transform: [{rotateY: rotation}] transform: [{rotateY: rotation}]
}} }}
/> />
@ -181,8 +184,8 @@ class Mascot extends React.Component<Props, State> {
key={"container"} key={"container"}
style={{ style={{
position: "absolute", position: "absolute",
width: this.props.size, width: "100%",
height: this.props.size, height: "100%",
}}/>); }}/>);
if (emotion === MASCOT_STYLE.CUTE) { if (emotion === MASCOT_STYLE.CUTE) {
final.push(this.getEye(EYE_STYLE.CUTE, true)); final.push(this.getEye(EYE_STYLE.CUTE, true));
@ -217,14 +220,13 @@ class Mascot extends React.Component<Props, State> {
} }
render() { render() {
const size = this.props.size;
const entryAnimation = this.props.animated ? this.props.entryAnimation : null; const entryAnimation = this.props.animated ? this.props.entryAnimation : null;
const loopAnimation = this.props.animated ? this.props.loopAnimation : null; const loopAnimation = this.props.animated ? this.props.loopAnimation : null;
return ( return (
<Animatable.View <Animatable.View
style={{ style={{
width: size, aspectRatio: 1,
height: size, ...this.props.style
}} }}
{...entryAnimation} {...entryAnimation}
> >
@ -241,8 +243,8 @@ class Mascot extends React.Component<Props, State> {
<Image <Image
source={MASCOT_IMAGE} source={MASCOT_IMAGE}
style={{ style={{
width: size, width: "100%",
height: size, height:"100%",
}} }}
/> />
{this.getEyes(this.state.currentEmotion)} {this.getEyes(this.state.currentEmotion)}

View file

@ -160,7 +160,7 @@ class MascotPopup extends React.Component<Props, State> {
duration={this.props.visible ? 1500 : 200} duration={this.props.visible ? 1500 : 200}
> >
<Mascot <Mascot
size={this.mascotSize} style={{width: this.mascotSize}}
animated={true} animated={true}
emotion={this.props.emotion} emotion={this.props.emotion}
/> />
@ -241,15 +241,16 @@ class MascotPopup extends React.Component<Props, State> {
}}> }}>
<View style={{ <View style={{
marginTop: -80, marginTop: -80,
width: "100%"
}}> }}>
{this.getMascot()} {this.getMascot()}
{this.getSpeechBubble()} {this.getSpeechBubble()}
</View> </View>
</View> </View>
</Portal> </Portal>
) )
; ;
} else } else
return null; return null;

View file

@ -146,20 +146,27 @@ export default class CustomIntroSlider extends React.Component<Props, State> {
</View> </View>
<Animatable.View <Animatable.View
animation={"fadeIn"}> animation={"fadeIn"}>
{index !== 0 && index !== this.introSlides.length -1 {index !== 0 && index !== this.introSlides.length - 1
? <Animatable.View ?
animation={"pulse"} <Mascot
iterationCount={"infinite"}
duration={2000}
style={{ style={{
marginLeft: 30, marginLeft: 30,
marginBottom: 0, marginBottom: 0,
width: 100, width: 100,
marginTop: -30, marginTop: -30,
}}> }}
<Mascot emotion={item.mascotStyle} size={100}/> emotion={item.mascotStyle}
</Animatable.View> : null} animated={true}
entryAnimation={{
animation: "slideInLeft",
duration: 500
}}
loopAnimation={{
animation: "pulse",
iterationCount: "infinite",
duration: 2000,
}}
/> : null}
<View style={{ <View style={{
marginLeft: 50, marginLeft: 50,
width: 0, width: 0,
@ -204,23 +211,23 @@ export default class CustomIntroSlider extends React.Component<Props, State> {
getEndView = () => { getEndView = () => {
return ( return (
<View style={{flex: 1}}> <View style={{flex: 1}}>
<View <Mascot
style={styles.center}> style={{
<Mascot ...styles.center,
size={250} height: "80%"
emotion={MASCOT_STYLE.COOL} }}
animated={true} emotion={MASCOT_STYLE.COOL}
entryAnimation={{ animated={true}
animation: "slideInDown", entryAnimation={{
duration: 2000, animation: "slideInDown",
}} duration: 2000,
loopAnimation={{ }}
animation: "pulse", loopAnimation={{
duration: 2000, animation: "pulse",
iterationCount: "infinite" duration: 2000,
}} iterationCount: "infinite"
/> }}
</View> />
</View> </View>
); );
} }
@ -228,55 +235,52 @@ export default class CustomIntroSlider extends React.Component<Props, State> {
getWelcomeView = () => { getWelcomeView = () => {
return ( return (
<View style={{flex: 1}}> <View style={{flex: 1}}>
<View <Mascot
style={styles.center}> style={{
<Mascot ...styles.center,
size={250} height: "80%"
emotion={MASCOT_STYLE.NORMAL} }}
animated={true} emotion={MASCOT_STYLE.NORMAL}
entryAnimation={{ animated={true}
animation: "bounceIn", entryAnimation={{
duration: 2000, animation: "bounceIn",
}} duration: 2000,
/> }}
<Animatable.Text />
useNativeDriver={true} <Animatable.Text
animation={"fadeInUp"} useNativeDriver={true}
duration={500} animation={"fadeInUp"}
duration={500}
style={{ style={{
color: "#fff", color: "#fff",
textAlign: "center", textAlign: "center",
fontSize: 25, fontSize: 25,
}}> }}>
PABLO PABLO
</Animatable.Text> </Animatable.Text>
<Animatable.View <Animatable.View
useNativeDriver={true} useNativeDriver={true}
animation={"fadeInUp"} animation={"fadeInUp"}
duration={500} duration={500}
delay={200} delay={200}
style={{
position: "absolute",
bottom: 30,
right: "20%",
width: 50,
height: 50,
}}>
<MaterialCommunityIcons
style={{ style={{
position: "absolute", ...styles.center,
top: 210, transform: [{rotateZ: "70deg"}],
left: 160, }}
width: 50, name={"undo"}
height: 50, color={'#fff'}
}}> size={40}/>
<MaterialCommunityIcons </Animatable.View>
style={{
marginLeft: "auto",
marginRight: "auto",
marginTop: "auto",
marginBottom: "auto",
transform: [{rotateZ: "70deg"}],
}}
name={"undo"}
color={'#fff'}
size={40}/>
</Animatable.View>
</View>
</View> </View>
) )
} }
@ -403,5 +407,5 @@ const styles = StyleSheet.create({
marginBottom: 'auto', marginBottom: 'auto',
marginRight: 'auto', marginRight: 'auto',
marginLeft: 'auto', marginLeft: 'auto',
} },
}); });

View file

@ -117,8 +117,10 @@ function HomeStackComponent(initialRoute: string | null, defaultData: { [key: st
}, },
headerTitle: (props) => <View style={{flexDirection: "row"}}> headerTitle: (props) => <View style={{flexDirection: "row"}}>
<Mascot <Mascot
style={{
width: 50
}}
emotion={MASCOT_STYLE.RANDOM} emotion={MASCOT_STYLE.RANDOM}
size={50}
animated={true} animated={true}
entryAnimation={{ entryAnimation={{
animation: "bounceIn", animation: "bounceIn",

View file

@ -158,15 +158,18 @@ class ProfileScreen extends React.Component<Props, State> {
<Card style={styles.card}> <Card style={styles.card}>
<Card.Title <Card.Title
title={i18n.t("screens.profile.welcomeTitle", {name: this.data.first_name})} title={i18n.t("screens.profile.welcomeTitle", {name: this.data.first_name})}
left={() => <Mascot left={() =>
emotion={MASCOT_STYLE.COOL} <Mascot
size={60} style={{
animated={true} width: 60
entryAnimation={{ }}
animation: "bounceIn", emotion={MASCOT_STYLE.COOL}
duration: 1000 animated={true}
}} entryAnimation={{
/>} animation: "bounceIn",
duration: 1000
}}
/>}
titleStyle={{marginLeft: 10}} titleStyle={{marginLeft: 10}}
/> />
<Card.Content> <Card.Content>

View file

@ -6,7 +6,7 @@ import type {CustomTheme} from "../../../managers/ThemeManager";
import {Button, Headline, withTheme} from "react-native-paper"; import {Button, Headline, withTheme} from "react-native-paper";
import {View} from "react-native"; import {View} from "react-native";
import i18n from "i18n-js"; import i18n from "i18n-js";
import {MASCOT_STYLE} from "../../../components/Mascot/Mascot"; import Mascot, {MASCOT_STYLE} from "../../../components/Mascot/Mascot";
import MascotPopup from "../../../components/Mascot/MascotPopup"; import MascotPopup from "../../../components/Mascot/MascotPopup";
import AsyncStorageManager from "../../../managers/AsyncStorageManager"; import AsyncStorageManager from "../../../managers/AsyncStorageManager";
@ -36,6 +36,11 @@ class GameStartScreen extends React.Component<Props, State> {
render() { render() {
return ( return (
<View style={{flex: 1}}> <View style={{flex: 1}}>
<Mascot emotion={MASCOT_STYLE.NORMAL} style={{
width: "50%",
marginLeft: "auto",
marginRight: "auto",
}}/>
<Headline style={{textAlign: "center"}}>Coucou</Headline> <Headline style={{textAlign: "center"}}>Coucou</Headline>
<Button <Button
mode={"contained"} mode={"contained"}