|
@@ -17,27 +17,27 @@
|
17
|
17
|
* along with Campus INSAT. If not, see <https://www.gnu.org/licenses/>.
|
18
|
18
|
*/
|
19
|
19
|
|
20
|
|
-// @flow
|
21
|
|
-
|
22
|
20
|
import * as React from 'react';
|
23
|
21
|
import * as Animatable from 'react-native-animatable';
|
24
|
|
-import {Image, TouchableWithoutFeedback, View} from 'react-native';
|
25
|
|
-import type {ViewStyle} from 'react-native/Libraries/StyleSheet/StyleSheet';
|
|
22
|
+import {Image, TouchableWithoutFeedback, View, ViewStyle} from 'react-native';
|
|
23
|
+import {AnimatableProperties} from 'react-native-animatable';
|
26
|
24
|
|
27
|
|
-export type AnimatableViewRefType = {current: null | Animatable.View};
|
|
25
|
+export type AnimatableViewRefType = {
|
|
26
|
+ current: null | (typeof Animatable.View & View);
|
|
27
|
+};
|
28
|
28
|
|
29
|
29
|
type PropsType = {
|
30
|
|
- emotion?: number,
|
31
|
|
- animated?: boolean,
|
32
|
|
- style?: ViewStyle | null,
|
33
|
|
- entryAnimation?: Animatable.AnimatableProperties | null,
|
34
|
|
- loopAnimation?: Animatable.AnimatableProperties | null,
|
35
|
|
- onPress?: null | ((viewRef: AnimatableViewRefType) => void),
|
36
|
|
- onLongPress?: null | ((viewRef: AnimatableViewRefType) => void),
|
|
30
|
+ emotion?: MASCOT_STYLE;
|
|
31
|
+ animated?: boolean;
|
|
32
|
+ style?: ViewStyle;
|
|
33
|
+ entryAnimation?: AnimatableProperties<ViewStyle>;
|
|
34
|
+ loopAnimation?: AnimatableProperties<ViewStyle>;
|
|
35
|
+ onPress?: null | ((viewRef: AnimatableViewRefType) => void);
|
|
36
|
+ onLongPress?: null | ((viewRef: AnimatableViewRefType) => void);
|
37
|
37
|
};
|
38
|
38
|
|
39
|
39
|
type StateType = {
|
40
|
|
- currentEmotion: number,
|
|
40
|
+ currentEmotion: MASCOT_STYLE;
|
41
|
41
|
};
|
42
|
42
|
|
43
|
43
|
const MASCOT_IMAGE = require('../../../assets/mascot/mascot.png');
|
|
@@ -50,32 +50,32 @@ const MASCOT_EYES_ANGRY = require('../../../assets/mascot/mascot_eyes_angry.png'
|
50
|
50
|
const MASCOT_GLASSES = require('../../../assets/mascot/mascot_glasses.png');
|
51
|
51
|
const MASCOT_SUNGLASSES = require('../../../assets/mascot/mascot_sunglasses.png');
|
52
|
52
|
|
53
|
|
-export const EYE_STYLE = {
|
54
|
|
- NORMAL: 0,
|
55
|
|
- GIRLY: 2,
|
56
|
|
- CUTE: 3,
|
57
|
|
- WINK: 4,
|
58
|
|
- HEART: 5,
|
59
|
|
- ANGRY: 6,
|
60
|
|
-};
|
|
53
|
+enum EYE_STYLE {
|
|
54
|
+ NORMAL,
|
|
55
|
+ GIRLY,
|
|
56
|
+ CUTE,
|
|
57
|
+ WINK,
|
|
58
|
+ HEART,
|
|
59
|
+ ANGRY,
|
|
60
|
+}
|
61
|
61
|
|
62
|
|
-const GLASSES_STYLE = {
|
63
|
|
- NORMAL: 0,
|
64
|
|
- COOl: 1,
|
65
|
|
-};
|
|
62
|
+enum GLASSES_STYLE {
|
|
63
|
+ NORMAL,
|
|
64
|
+ COOl,
|
|
65
|
+}
|
66
|
66
|
|
67
|
|
-export const MASCOT_STYLE = {
|
68
|
|
- NORMAL: 0,
|
69
|
|
- HAPPY: 1,
|
70
|
|
- GIRLY: 2,
|
71
|
|
- WINK: 3,
|
72
|
|
- CUTE: 4,
|
73
|
|
- INTELLO: 5,
|
74
|
|
- LOVE: 6,
|
75
|
|
- COOL: 7,
|
76
|
|
- ANGRY: 8,
|
77
|
|
- RANDOM: 999,
|
78
|
|
-};
|
|
67
|
+export enum MASCOT_STYLE {
|
|
68
|
+ NORMAL,
|
|
69
|
+ HAPPY,
|
|
70
|
+ GIRLY,
|
|
71
|
+ WINK,
|
|
72
|
+ CUTE,
|
|
73
|
+ INTELLO,
|
|
74
|
+ LOVE,
|
|
75
|
+ COOL,
|
|
76
|
+ ANGRY,
|
|
77
|
+ RANDOM = 999,
|
|
78
|
+}
|
79
|
79
|
|
80
|
80
|
class Mascot extends React.Component<PropsType, StateType> {
|
81
|
81
|
static defaultProps = {
|
|
@@ -100,9 +100,9 @@ class Mascot extends React.Component<PropsType, StateType> {
|
100
|
100
|
|
101
|
101
|
viewRef: AnimatableViewRefType;
|
102
|
102
|
|
103
|
|
- eyeList: {[key: number]: number | string};
|
|
103
|
+ eyeList: {[key in EYE_STYLE]: number};
|
104
|
104
|
|
105
|
|
- glassesList: {[key: number]: number | string};
|
|
105
|
+ glassesList: {[key in GLASSES_STYLE]: number};
|
106
|
106
|
|
107
|
107
|
onPress: (viewRef: AnimatableViewRefType) => void;
|
108
|
108
|
|
|
@@ -113,23 +113,25 @@ class Mascot extends React.Component<PropsType, StateType> {
|
113
|
113
|
constructor(props: PropsType) {
|
114
|
114
|
super(props);
|
115
|
115
|
this.viewRef = React.createRef();
|
116
|
|
- this.eyeList = {};
|
117
|
|
- this.glassesList = {};
|
118
|
|
- this.eyeList[EYE_STYLE.NORMAL] = MASCOT_EYES_NORMAL;
|
119
|
|
- this.eyeList[EYE_STYLE.GIRLY] = MASCOT_EYES_GIRLY;
|
120
|
|
- this.eyeList[EYE_STYLE.CUTE] = MASCOT_EYES_CUTE;
|
121
|
|
- this.eyeList[EYE_STYLE.WINK] = MASCOT_EYES_WINK;
|
122
|
|
- this.eyeList[EYE_STYLE.HEART] = MASCOT_EYES_HEART;
|
123
|
|
- this.eyeList[EYE_STYLE.ANGRY] = MASCOT_EYES_ANGRY;
|
124
|
|
-
|
125
|
|
- this.glassesList[GLASSES_STYLE.NORMAL] = MASCOT_GLASSES;
|
126
|
|
- this.glassesList[GLASSES_STYLE.COOl] = MASCOT_SUNGLASSES;
|
127
|
|
-
|
128
|
|
- this.initialEmotion =
|
129
|
|
- props.emotion != null ? props.emotion : Mascot.defaultProps.emotion;
|
|
116
|
+ this.eyeList = {
|
|
117
|
+ [EYE_STYLE.NORMAL]: MASCOT_EYES_NORMAL,
|
|
118
|
+ [EYE_STYLE.GIRLY]: MASCOT_EYES_GIRLY,
|
|
119
|
+ [EYE_STYLE.CUTE]: MASCOT_EYES_CUTE,
|
|
120
|
+ [EYE_STYLE.WINK]: MASCOT_EYES_WINK,
|
|
121
|
+ [EYE_STYLE.HEART]: MASCOT_EYES_HEART,
|
|
122
|
+ [EYE_STYLE.ANGRY]: MASCOT_EYES_ANGRY,
|
|
123
|
+ };
|
|
124
|
+ this.glassesList = {
|
|
125
|
+ [GLASSES_STYLE.NORMAL]: MASCOT_GLASSES,
|
|
126
|
+ [GLASSES_STYLE.COOl]: MASCOT_SUNGLASSES,
|
|
127
|
+ };
|
|
128
|
+ this.initialEmotion = props.emotion
|
|
129
|
+ ? props.emotion
|
|
130
|
+ : Mascot.defaultProps.emotion;
|
130
|
131
|
|
131
|
|
- if (this.initialEmotion === MASCOT_STYLE.RANDOM)
|
|
132
|
+ if (this.initialEmotion === MASCOT_STYLE.RANDOM) {
|
132
|
133
|
this.initialEmotion = Math.floor(Math.random() * MASCOT_STYLE.ANGRY) + 1;
|
|
134
|
+ }
|
133
|
135
|
|
134
|
136
|
this.state = {
|
135
|
137
|
currentEmotion: this.initialEmotion,
|
|
@@ -138,29 +140,33 @@ class Mascot extends React.Component<PropsType, StateType> {
|
138
|
140
|
if (props.onPress == null) {
|
139
|
141
|
this.onPress = (viewRef: AnimatableViewRefType) => {
|
140
|
142
|
const ref = viewRef.current;
|
141
|
|
- if (ref != null) {
|
|
143
|
+ if (ref && ref.rubberBand) {
|
142
|
144
|
this.setState({currentEmotion: MASCOT_STYLE.LOVE});
|
143
|
145
|
ref.rubberBand(1500).then(() => {
|
144
|
146
|
this.setState({currentEmotion: this.initialEmotion});
|
145
|
147
|
});
|
146
|
148
|
}
|
147
|
149
|
};
|
148
|
|
- } else this.onPress = props.onPress;
|
|
150
|
+ } else {
|
|
151
|
+ this.onPress = props.onPress;
|
|
152
|
+ }
|
149
|
153
|
|
150
|
154
|
if (props.onLongPress == null) {
|
151
|
155
|
this.onLongPress = (viewRef: AnimatableViewRefType) => {
|
152
|
156
|
const ref = viewRef.current;
|
153
|
|
- if (ref != null) {
|
|
157
|
+ if (ref && ref.tada) {
|
154
|
158
|
this.setState({currentEmotion: MASCOT_STYLE.ANGRY});
|
155
|
159
|
ref.tada(1000).then(() => {
|
156
|
160
|
this.setState({currentEmotion: this.initialEmotion});
|
157
|
161
|
});
|
158
|
162
|
}
|
159
|
163
|
};
|
160
|
|
- } else this.onLongPress = props.onLongPress;
|
|
164
|
+ } else {
|
|
165
|
+ this.onLongPress = props.onLongPress;
|
|
166
|
+ }
|
161
|
167
|
}
|
162
|
168
|
|
163
|
|
- getGlasses(style: number): React.Node {
|
|
169
|
+ getGlasses(style: GLASSES_STYLE) {
|
164
|
170
|
const glasses = this.glassesList[style];
|
165
|
171
|
return (
|
166
|
172
|
<Image
|
|
@@ -179,11 +185,7 @@ class Mascot extends React.Component<PropsType, StateType> {
|
179
|
185
|
);
|
180
|
186
|
}
|
181
|
187
|
|
182
|
|
- getEye(
|
183
|
|
- style: number,
|
184
|
|
- isRight: boolean,
|
185
|
|
- rotation: string = '0deg',
|
186
|
|
- ): React.Node {
|
|
188
|
+ getEye(style: EYE_STYLE, isRight: boolean, rotation: string = '0deg') {
|
187
|
189
|
const eye = this.eyeList[style];
|
188
|
190
|
return (
|
189
|
191
|
<Image
|
|
@@ -201,7 +203,7 @@ class Mascot extends React.Component<PropsType, StateType> {
|
201
|
203
|
);
|
202
|
204
|
}
|
203
|
205
|
|
204
|
|
- getEyes(emotion: number): React.Node {
|
|
206
|
+ getEyes(emotion: MASCOT_STYLE) {
|
205
|
207
|
const final = [];
|
206
|
208
|
final.push(
|
207
|
209
|
<View
|
|
@@ -246,7 +248,7 @@ class Mascot extends React.Component<PropsType, StateType> {
|
246
|
248
|
return final;
|
247
|
249
|
}
|
248
|
250
|
|
249
|
|
- render(): React.Node {
|
|
251
|
+ render() {
|
250
|
252
|
const {props, state} = this;
|
251
|
253
|
const entryAnimation = props.animated ? props.entryAnimation : null;
|
252
|
254
|
const loopAnimation = props.animated ? props.loopAnimation : null;
|
|
@@ -256,7 +258,6 @@ class Mascot extends React.Component<PropsType, StateType> {
|
256
|
258
|
aspectRatio: 1,
|
257
|
259
|
...props.style,
|
258
|
260
|
}}
|
259
|
|
- // eslint-disable-next-line react/jsx-props-no-spreading
|
260
|
261
|
{...entryAnimation}>
|
261
|
262
|
<TouchableWithoutFeedback
|
262
|
263
|
onPress={() => {
|
|
@@ -266,9 +267,7 @@ class Mascot extends React.Component<PropsType, StateType> {
|
266
|
267
|
this.onLongPress(this.viewRef);
|
267
|
268
|
}}>
|
268
|
269
|
<Animatable.View ref={this.viewRef}>
|
269
|
|
- <Animatable.View
|
270
|
|
- // eslint-disable-next-line react/jsx-props-no-spreading
|
271
|
|
- {...loopAnimation}>
|
|
270
|
+ <Animatable.View {...loopAnimation}>
|
272
|
271
|
<Image
|
273
|
272
|
source={MASCOT_IMAGE}
|
274
|
273
|
style={{
|