Browse Source

Improved game flow typing

Arnaud Vergnet 1 year ago
parent
commit
fe26ec0cc4

+ 38
- 47
src/screens/Game/GameScreen.js View File

@@ -5,17 +5,21 @@ import {Alert, View} from 'react-native';
5 5
 import {IconButton, Text, withTheme} from 'react-native-paper';
6 6
 import MaterialCommunityIcons from "react-native-vector-icons/MaterialCommunityIcons";
7 7
 import GameLogic from "./GameLogic";
8
-import Grid from "./components/Grid";
8
+import type {Grid} from "./components/GridComponent";
9
+import GridComponent from "./components/GridComponent";
9 10
 import Preview from "./components/Preview";
10 11
 import i18n from "i18n-js";
11 12
 import MaterialHeaderButtons, {Item} from "../../components/Overrides/CustomHeaderButton";
13
+import {StackNavigationProp} from "@react-navigation/stack";
14
+import type {CustomTheme} from "../../managers/ThemeManager";
12 15
 
13 16
 type Props = {
14
-    navigation: Object,
17
+    navigation: StackNavigationProp,
18
+    theme: CustomTheme,
15 19
 }
16 20
 
17 21
 type State = {
18
-    grid: Array<Array<Object>>,
22
+    grid: Grid,
19 23
     gameRunning: boolean,
20 24
     gameTime: number,
21 25
     gameScore: number,
@@ -24,19 +28,11 @@ type State = {
24 28
 
25 29
 class GameScreen extends React.Component<Props, State> {
26 30
 
27
-    colors: Object;
28
-
29 31
     logic: GameLogic;
30
-    onTick: Function;
31
-    onClock: Function;
32
-    onGameEnd: Function;
33
-    updateGrid: Function;
34
-    updateGridScore: Function;
35 32
 
36 33
     constructor(props) {
37 34
         super(props);
38
-        this.colors = props.theme.colors;
39
-        this.logic = new GameLogic(20, 10, this.colors);
35
+        this.logic = new GameLogic(20, 10, this.props.theme.colors);
40 36
         this.state = {
41 37
             grid: this.logic.getCurrentGrid(),
42 38
             gameRunning: false,
@@ -44,38 +40,32 @@ class GameScreen extends React.Component<Props, State> {
44 40
             gameScore: 0,
45 41
             gameLevel: 0,
46 42
         };
47
-        this.onTick = this.onTick.bind(this);
48
-        this.onClock = this.onClock.bind(this);
49
-        this.onGameEnd = this.onGameEnd.bind(this);
50
-        this.updateGrid = this.updateGrid.bind(this);
51
-        this.updateGridScore = this.updateGridScore.bind(this);
52
-        this.props.navigation.addListener('blur', this.onScreenBlur.bind(this));
53
-        this.props.navigation.addListener('focus', this.onScreenFocus.bind(this));
43
+        this.props.navigation.addListener('blur', this.onScreenBlur);
44
+        this.props.navigation.addListener('focus', this.onScreenFocus);
54 45
     }
55 46
 
56 47
     componentDidMount() {
57
-        const rightButton = this.getRightButton.bind(this);
58 48
         this.props.navigation.setOptions({
59
-            headerRight: rightButton,
49
+            headerRight: this.getRightButton,
60 50
         });
61 51
         this.startGame();
62 52
     }
63 53
 
64
-    getRightButton() {
54
+    getRightButton = () => {
65 55
         return <MaterialHeaderButtons>
66
-            <Item title="pause" iconName="pause" onPress={() => this.togglePause()}/>
56
+            <Item title="pause" iconName="pause" onPress={this.togglePause}/>
67 57
         </MaterialHeaderButtons>;
68 58
     }
69 59
 
70 60
     /**
71 61
      * Remove any interval on un-focus
72 62
      */
73
-    onScreenBlur() {
63
+    onScreenBlur = () => {
74 64
         if (!this.logic.isGamePaused())
75 65
             this.logic.togglePause();
76 66
     }
77 67
 
78
-    onScreenFocus() {
68
+    onScreenFocus = () => {
79 69
         if (!this.logic.isGameRunning())
80 70
             this.startGame();
81 71
         else if (this.logic.isGamePaused())
@@ -97,7 +87,7 @@ class GameScreen extends React.Component<Props, State> {
97 87
         return format;
98 88
     }
99 89
 
100
-    onTick(score: number, level: number, newGrid: Array<Array<Object>>) {
90
+    onTick = (score: number, level: number, newGrid: Grid) => {
101 91
         this.setState({
102 92
             gameScore: score,
103 93
             gameLevel: level,
@@ -105,50 +95,50 @@ class GameScreen extends React.Component<Props, State> {
105 95
         });
106 96
     }
107 97
 
108
-    onClock(time: number) {
98
+    onClock = (time: number) => {
109 99
         this.setState({
110 100
             gameTime: time,
111 101
         });
112 102
     }
113 103
 
114
-    updateGrid(newGrid: Array<Array<Object>>) {
104
+    updateGrid = (newGrid: Grid) => {
115 105
         this.setState({
116 106
             grid: newGrid,
117 107
         });
118 108
     }
119 109
 
120
-    updateGridScore(newGrid: Array<Array<Object>>, score: number) {
110
+    updateGridScore = (newGrid: Grid, score: number) => {
121 111
         this.setState({
122 112
             grid: newGrid,
123 113
             gameScore: score,
124 114
         });
125 115
     }
126 116
 
127
-    togglePause() {
117
+    togglePause = () => {
128 118
         this.logic.togglePause();
129 119
         if (this.logic.isGamePaused())
130 120
             this.showPausePopup();
131 121
     }
132 122
 
133
-    showPausePopup() {
123
+    showPausePopup = () => {
134 124
         Alert.alert(
135 125
             i18n.t("screens.game.pause"),
136 126
             i18n.t("screens.game.pauseMessage"),
137 127
             [
138
-                {text: i18n.t("screens.game.restart.text"), onPress: () => this.showRestartConfirm()},
139
-                {text: i18n.t("screens.game.resume"), onPress: () => this.togglePause()},
128
+                {text: i18n.t("screens.game.restart.text"), onPress: this.showRestartConfirm},
129
+                {text: i18n.t("screens.game.resume"), onPress: this.togglePause},
140 130
             ],
141 131
             {cancelable: false},
142 132
         );
143 133
     }
144 134
 
145
-    showRestartConfirm() {
135
+    showRestartConfirm = () => {
146 136
         Alert.alert(
147 137
             i18n.t("screens.game.restart.confirm"),
148 138
             i18n.t("screens.game.restart.confirmMessage"),
149 139
             [
150
-                {text: i18n.t("screens.game.restart.confirmNo"), onPress: () => this.showPausePopup()},
151
-                {text: i18n.t("screens.game.restart.confirmYes"), onPress: () => this.startGame()},
140
+                {text: i18n.t("screens.game.restart.confirmNo"), onPress: this.showPausePopup},
141
+                {text: i18n.t("screens.game.restart.confirmYes"), onPress: this.startGame},
152 142
             ],
153 143
             {cancelable: false},
154 144
         );
@@ -163,20 +153,20 @@ class GameScreen extends React.Component<Props, State> {
163 153
             message,
164 154
             [
165 155
                 {text: i18n.t("screens.game.gameOver.exit"), onPress: () => this.props.navigation.goBack()},
166
-                {text: i18n.t("screens.game.restart.text"), onPress: () => this.startGame()},
156
+                {text: i18n.t("screens.game.restart.text"), onPress: this.startGame},
167 157
             ],
168 158
             {cancelable: false},
169 159
         );
170 160
     }
171 161
 
172
-    startGame() {
162
+    startGame = () => {
173 163
         this.logic.startGame(this.onTick, this.onClock, this.onGameEnd);
174 164
         this.setState({
175 165
             gameRunning: true,
176 166
         });
177 167
     }
178 168
 
179
-    onGameEnd(time: number, score: number, isRestart: boolean) {
169
+    onGameEnd = (time: number, score: number, isRestart: boolean) => {
180 170
         this.setState({
181 171
             gameTime: time,
182 172
             gameScore: score,
@@ -187,6 +177,7 @@ class GameScreen extends React.Component<Props, State> {
187 177
     }
188 178
 
189 179
     render() {
180
+        const colors = this.props.theme.colors;
190 181
         return (
191 182
             <View style={{
192 183
                 width: '100%',
@@ -200,11 +191,11 @@ class GameScreen extends React.Component<Props, State> {
200 191
                 }}>
201 192
                     <MaterialCommunityIcons
202 193
                         name={'timer'}
203
-                        color={this.colors.subtitle}
194
+                        color={colors.subtitle}
204 195
                         size={20}/>
205 196
                     <Text style={{
206 197
                         marginLeft: 5,
207
-                        color: this.colors.subtitle
198
+                        color: colors.subtitle
208 199
                     }}>{this.getFormattedTime(this.state.gameTime)}</Text>
209 200
                 </View>
210 201
                 <View style={{
@@ -215,7 +206,7 @@ class GameScreen extends React.Component<Props, State> {
215 206
                 }}>
216 207
                     <MaterialCommunityIcons
217 208
                         name={'gamepad'}
218
-                        color={this.colors.text}
209
+                        color={colors.text}
219 210
                         size={20}/>
220 211
                     <Text style={{
221 212
                         marginLeft: 5
@@ -228,20 +219,20 @@ class GameScreen extends React.Component<Props, State> {
228 219
                 }}>
229 220
                     <MaterialCommunityIcons
230 221
                         name={'star'}
231
-                        color={this.colors.tetrisScore}
222
+                        color={colors.tetrisScore}
232 223
                         size={30}/>
233 224
                     <Text style={{
234 225
                         marginLeft: 5,
235 226
                         fontSize: 22,
236 227
                     }}>{this.state.gameScore}</Text>
237 228
                 </View>
238
-                <Grid
229
+                <GridComponent
239 230
                     width={this.logic.getWidth()}
240 231
                     height={this.logic.getHeight()}
241 232
                     containerMaxHeight={'80%'}
242 233
                     containerMaxWidth={'60%'}
243 234
                     grid={this.state.grid}
244
-                    backgroundColor={this.colors.tetrisBackground}
235
+                    backgroundColor={colors.tetrisBackground}
245 236
                 />
246 237
                 <View style={{
247 238
                     position: 'absolute',
@@ -249,7 +240,7 @@ class GameScreen extends React.Component<Props, State> {
249 240
                     right: 5,
250 241
                 }}>
251 242
                     <Preview
252
-                        next={this.logic.getNextPiecesPreviews()}
243
+                        items={this.logic.getNextPiecesPreviews()}
253 244
                     />
254 245
                 </View>
255 246
                 <View style={{
@@ -287,7 +278,7 @@ class GameScreen extends React.Component<Props, State> {
287 278
                         onPressIn={() => this.logic.downPressedIn(this.updateGridScore)}
288 279
                         onPress={() => this.logic.pressedOut()}
289 280
                         style={{marginLeft: 'auto'}}
290
-                        color={this.colors.tetrisScore}
281
+                        color={colors.tetrisScore}
291 282
                     />
292 283
                 </View>
293 284
             </View>

+ 23
- 25
src/screens/Game/GridManager.js View File

@@ -2,39 +2,37 @@
2 2
 
3 3
 import Piece from "./Piece";
4 4
 import ScoreManager from "./ScoreManager";
5
-import type {coordinates} from './Shapes/BaseShape';
6
-
7
-
8
-export type cell = {color: string, isEmpty: boolean, key: string};
9
-export type grid = Array<Array<cell>>;
5
+import type {Coordinates} from './Shapes/BaseShape';
6
+import type {Grid} from "./components/GridComponent";
7
+import type {Cell} from "./components/CellComponent";
8
+import type {CustomTheme} from "../../managers/ThemeManager";
10 9
 
11 10
 /**
12 11
  * Class used to manage the game grid
13
- *
14 12
  */
15 13
 export default class GridManager {
16 14
 
17
-    #currentGrid: grid;
18
-    #colors: Object;
15
+    #currentGrid: Grid;
16
+    #theme: CustomTheme;
19 17
 
20 18
     /**
21 19
      * Initializes a grid of the given size
22 20
      *
23 21
      * @param width The grid width
24 22
      * @param height The grid height
25
-     * @param colors Object containing current theme colors
23
+     * @param theme Object containing current theme
26 24
      */
27
-    constructor(width: number, height: number, colors: Object) {
28
-        this.#colors = colors;
25
+    constructor(width: number, height: number, theme: CustomTheme) {
26
+        this.#theme = theme;
29 27
         this.#currentGrid = this.getEmptyGrid(height, width);
30 28
     }
31 29
 
32 30
     /**
33 31
      * Get the current grid
34 32
      *
35
-     * @return {grid} The current grid
33
+     * @return {Grid} The current grid
36 34
      */
37
-    getCurrentGrid(): grid {
35
+    getCurrentGrid(): Grid {
38 36
         return this.#currentGrid;
39 37
     }
40 38
 
@@ -42,13 +40,13 @@ export default class GridManager {
42 40
      * Get a new empty grid line of the given size
43 41
      *
44 42
      * @param width The line size
45
-     * @return {Array<cell>}
43
+     * @return {Array<Cell>}
46 44
      */
47
-    getEmptyLine(width: number): Array<cell> {
45
+    getEmptyLine(width: number): Array<Cell> {
48 46
         let line = [];
49 47
         for (let col = 0; col < width; col++) {
50 48
             line.push({
51
-                color: this.#colors.tetrisBackground,
49
+                color: this.#theme.colors.tetrisBackground,
52 50
                 isEmpty: true,
53 51
                 key: col.toString(),
54 52
             });
@@ -61,9 +59,9 @@ export default class GridManager {
61 59
      *
62 60
      * @param width The grid width
63 61
      * @param height The grid height
64
-     * @return {grid} A new empty grid
62
+     * @return {Grid} A new empty grid
65 63
      */
66
-    getEmptyGrid(height: number, width: number): grid {
64
+    getEmptyGrid(height: number, width: number): Grid {
67 65
         let grid = [];
68 66
         for (let row = 0; row < height; row++) {
69 67
             grid.push(this.getEmptyLine(width));
@@ -91,21 +89,21 @@ export default class GridManager {
91 89
      * Gets the lines to clear around the given piece's coordinates.
92 90
      * The piece's coordinates are used for optimization and to prevent checking the whole grid.
93 91
      *
94
-     * @param coord The piece's coordinates to check lines at
92
+     * @param pos The piece's coordinates to check lines at
95 93
      * @return {Array<number>} An array containing the line numbers to clear
96 94
      */
97
-    getLinesToClear(coord: Array<coordinates>): Array<number> {
95
+    getLinesToClear(pos: Array<Coordinates>): Array<number> {
98 96
         let rows = [];
99
-        for (let i = 0; i < coord.length; i++) {
97
+        for (let i = 0; i < pos.length; i++) {
100 98
             let isLineFull = true;
101
-            for (let col = 0; col < this.#currentGrid[coord[i].y].length; col++) {
102
-                if (this.#currentGrid[coord[i].y][col].isEmpty) {
99
+            for (let col = 0; col < this.#currentGrid[pos[i].y].length; col++) {
100
+                if (this.#currentGrid[pos[i].y][col].isEmpty) {
103 101
                     isLineFull = false;
104 102
                     break;
105 103
                 }
106 104
             }
107
-            if (isLineFull && rows.indexOf(coord[i].y) === -1)
108
-                rows.push(coord[i].y);
105
+            if (isLineFull && rows.indexOf(pos[i].y) === -1)
106
+                rows.push(pos[i].y);
109 107
         }
110 108
         return rows;
111 109
     }

+ 36
- 34
src/screens/Game/Piece.js View File

@@ -5,8 +5,10 @@ import ShapeO from "./Shapes/ShapeO";
5 5
 import ShapeS from "./Shapes/ShapeS";
6 6
 import ShapeT from "./Shapes/ShapeT";
7 7
 import ShapeZ from "./Shapes/ShapeZ";
8
-import type {coordinates} from './Shapes/BaseShape';
9
-import type {grid} from './GridManager';
8
+import type {Coordinates} from './Shapes/BaseShape';
9
+import BaseShape from "./Shapes/BaseShape";
10
+import type {Grid} from "./components/GridComponent";
11
+import type {CustomTheme} from "../../managers/ThemeManager";
10 12
 
11 13
 /**
12 14
  * Class used as an abstraction layer for shapes.
@@ -24,26 +26,26 @@ export default class Piece {
24 26
         ShapeT,
25 27
         ShapeZ,
26 28
     ];
27
-    #currentShape: Object;
28
-    #colors: Object;
29
+    #currentShape: BaseShape;
30
+    #theme: CustomTheme;
29 31
 
30 32
     /**
31 33
      * Initializes this piece's color and shape
32 34
      *
33
-     * @param colors Object containing current theme colors
35
+     * @param theme Object containing current theme
34 36
      */
35
-    constructor(colors: Object) {
36
-        this.#currentShape = this.getRandomShape(colors);
37
-        this.#colors = colors;
37
+    constructor(theme: CustomTheme) {
38
+        this.#currentShape = this.getRandomShape(theme);
39
+        this.#theme = theme;
38 40
     }
39 41
 
40 42
     /**
41 43
      * Gets a random shape object
42 44
      *
43
-     * @param colors Object containing current theme colors
45
+     * @param theme Object containing current theme
44 46
      */
45
-    getRandomShape(colors: Object) {
46
-        return new this.#shapes[Math.floor(Math.random() * 7)](colors);
47
+    getRandomShape(theme: CustomTheme) {
48
+        return new this.#shapes[Math.floor(Math.random() * 7)](theme);
47 49
     }
48 50
 
49 51
     /**
@@ -51,13 +53,13 @@ export default class Piece {
51 53
      *
52 54
      * @param grid The grid to remove the piece from
53 55
      */
54
-    removeFromGrid(grid: grid) {
55
-        const coord: Array<coordinates> = this.#currentShape.getCellsCoordinates(true);
56
-        for (let i = 0; i < coord.length; i++) {
57
-            grid[coord[i].y][coord[i].x] = {
58
-                color: this.#colors.tetrisBackground,
56
+    removeFromGrid(grid: Grid) {
57
+        const pos: Array<Coordinates> = this.#currentShape.getCellsCoordinates(true);
58
+        for (let i = 0; i < pos.length; i++) {
59
+            grid[pos[i].y][pos[i].x] = {
60
+                color: this.#theme.colors.tetrisBackground,
59 61
                 isEmpty: true,
60
-                key: grid[coord[i].y][coord[i].x].key
62
+                key: grid[pos[i].y][pos[i].x].key
61 63
             };
62 64
         }
63 65
     }
@@ -68,13 +70,13 @@ export default class Piece {
68 70
      * @param grid The grid to add the piece to
69 71
      * @param isPreview Should we use this piece's current position to determine the cells?
70 72
      */
71
-    toGrid(grid: grid, isPreview: boolean) {
72
-        const coord: Array<coordinates> = this.#currentShape.getCellsCoordinates(!isPreview);
73
-        for (let i = 0; i < coord.length; i++) {
74
-            grid[coord[i].y][coord[i].x] = {
73
+    toGrid(grid: Grid, isPreview: boolean) {
74
+        const pos: Array<Coordinates> = this.#currentShape.getCellsCoordinates(!isPreview);
75
+        for (let i = 0; i < pos.length; i++) {
76
+            grid[pos[i].y][pos[i].x] = {
75 77
                 color: this.#currentShape.getColor(),
76 78
                 isEmpty: false,
77
-                key: grid[coord[i].y][coord[i].x].key
79
+                key: grid[pos[i].y][pos[i].x].key
78 80
             };
79 81
         }
80 82
     }
@@ -87,15 +89,15 @@ export default class Piece {
87 89
      * @param height The grid's height
88 90
      * @return {boolean} If the position is valid
89 91
      */
90
-    isPositionValid(grid: grid, width: number, height: number) {
92
+    isPositionValid(grid: Grid, width: number, height: number) {
91 93
         let isValid = true;
92
-        const coord: Array<coordinates> = this.#currentShape.getCellsCoordinates(true);
93
-        for (let i = 0; i < coord.length; i++) {
94
-            if (coord[i].x >= width
95
-                || coord[i].x < 0
96
-                || coord[i].y >= height
97
-                || coord[i].y < 0
98
-                || !grid[coord[i].y][coord[i].x].isEmpty) {
94
+        const pos: Array<Coordinates> = this.#currentShape.getCellsCoordinates(true);
95
+        for (let i = 0; i < pos.length; i++) {
96
+            if (pos[i].x >= width
97
+                || pos[i].x < 0
98
+                || pos[i].y >= height
99
+                || pos[i].y < 0
100
+                || !grid[pos[i].y][pos[i].x].isEmpty) {
99 101
                 isValid = false;
100 102
                 break;
101 103
             }
@@ -114,7 +116,7 @@ export default class Piece {
114 116
      * @param freezeCallback Callback to use if the piece should freeze itself
115 117
      * @return {boolean} True if the move was valid, false otherwise
116 118
      */
117
-    tryMove(x: number, y: number, grid: grid, width: number, height: number, freezeCallback: Function) {
119
+    tryMove(x: number, y: number, grid: Grid, width: number, height: number, freezeCallback: () => void) {
118 120
         if (x > 1) x = 1; // Prevent moving from more than one tile
119 121
         if (x < -1) x = -1;
120 122
         if (y > 1) y = 1;
@@ -143,7 +145,7 @@ export default class Piece {
143 145
      * @param height The grid's height
144 146
      * @return {boolean} True if the rotation was valid, false otherwise
145 147
      */
146
-    tryRotate(grid: grid, width: number, height: number) {
148
+    tryRotate(grid: Grid, width: number, height: number) {
147 149
         this.removeFromGrid(grid);
148 150
         this.#currentShape.rotate(true);
149 151
         if (!this.isPositionValid(grid, width, height)) {
@@ -158,9 +160,9 @@ export default class Piece {
158 160
     /**
159 161
      * Gets this piece used cells coordinates
160 162
      *
161
-     * @return {Array<coordinates>} An array of coordinates
163
+     * @return {Array<Coordinates>} An array of coordinates
162 164
      */
163
-    getCoordinates(): Array<coordinates> {
165
+    getCoordinates(): Array<Coordinates> {
164 166
         return this.#currentShape.getCellsCoordinates(true);
165 167
     }
166 168
 }

+ 14
- 8
src/screens/Game/Shapes/BaseShape.js View File

@@ -1,10 +1,14 @@
1 1
 // @flow
2 2
 
3
-export type coordinates = {
3
+import type {CustomTheme} from "../../../managers/ThemeManager";
4
+
5
+export type Coordinates = {
4 6
     x: number,
5 7
     y: number,
6 8
 }
7 9
 
10
+type Shape = Array<Array<number>>;
11
+
8 12
 /**
9 13
  * Abstract class used to represent a BaseShape.
10 14
  * Abstract classes do not exist by default in Javascript: we force it by throwing errors in the constructor
@@ -12,16 +16,18 @@ export type coordinates = {
12 16
  */
13 17
 export default class BaseShape {
14 18
 
15
-    #currentShape: Array<Array<number>>;
19
+    #currentShape: Shape;
16 20
     #rotation: number;
17
-    position: coordinates;
21
+    position: Coordinates;
22
+    theme: CustomTheme;
18 23
 
19 24
     /**
20 25
      * Prevent instantiation if classname is BaseShape to force class to be abstract
21 26
      */
22
-    constructor() {
27
+    constructor(theme: CustomTheme) {
23 28
         if (this.constructor === BaseShape)
24 29
             throw new Error("Abstract class can't be instantiated");
30
+        this.theme = theme;
25 31
         this.#rotation = 0;
26 32
         this.position = {x: 0, y: 0};
27 33
         this.#currentShape = this.getShapes()[this.#rotation];
@@ -41,7 +47,7 @@ export default class BaseShape {
41 47
      *
42 48
      * Used by tests to read private fields
43 49
      */
44
-    getShapes(): Array<Array<Array<number>>> {
50
+    getShapes(): Array<Shape> {
45 51
         throw new Error("Method 'getShapes()' must be implemented");
46 52
     }
47 53
 
@@ -50,7 +56,7 @@ export default class BaseShape {
50 56
      *
51 57
      * Used by tests to read private fields
52 58
      */
53
-    getCurrentShape(): Array<Array<number>> {
59
+    getCurrentShape(): Shape {
54 60
         return this.#currentShape;
55 61
     }
56 62
 
@@ -59,9 +65,9 @@ export default class BaseShape {
59 65
      * This will return an array of coordinates representing the positions of the cells used by this object.
60 66
      *
61 67
      * @param isAbsolute Should we take into account the current position of the object?
62
-     * @return {Array<coordinates>} This object cells coordinates
68
+     * @return {Array<Coordinates>} This object cells coordinates
63 69
      */
64
-    getCellsCoordinates(isAbsolute: boolean): Array<coordinates> {
70
+    getCellsCoordinates(isAbsolute: boolean): Array<Coordinates> {
65 71
         let coordinates = [];
66 72
         for (let row = 0; row < this.#currentShape.length; row++) {
67 73
             for (let col = 0; col < this.#currentShape[row].length; col++) {

+ 4
- 6
src/screens/Game/Shapes/ShapeI.js View File

@@ -1,19 +1,17 @@
1 1
 // @flow
2 2
 
3 3
 import BaseShape from "./BaseShape";
4
+import type {CustomTheme} from "../../../managers/ThemeManager";
4 5
 
5 6
 export default class ShapeI extends BaseShape {
6 7
 
7
-    #colors: Object;
8
-
9
-    constructor(colors: Object) {
10
-        super();
8
+    constructor(theme: CustomTheme) {
9
+        super(theme);
11 10
         this.position.x = 3;
12
-        this.#colors = colors;
13 11
     }
14 12
 
15 13
     getColor(): string {
16
-        return this.#colors.tetrisI;
14
+        return this.theme.colors.tetrisI;
17 15
     }
18 16
 
19 17
     getShapes() {

+ 4
- 6
src/screens/Game/Shapes/ShapeJ.js View File

@@ -1,19 +1,17 @@
1 1
 // @flow
2 2
 
3 3
 import BaseShape from "./BaseShape";
4
+import type {CustomTheme} from "../../../managers/ThemeManager";
4 5
 
5 6
 export default class ShapeJ extends BaseShape {
6 7
 
7
-    #colors: Object;
8
-
9
-    constructor(colors: Object) {
10
-        super();
8
+    constructor(theme: CustomTheme) {
9
+        super(theme);
11 10
         this.position.x = 3;
12
-        this.#colors = colors;
13 11
     }
14 12
 
15 13
     getColor(): string {
16
-        return this.#colors.tetrisJ;
14
+        return this.theme.colors.tetrisJ;
17 15
     }
18 16
 
19 17
     getShapes() {

+ 4
- 6
src/screens/Game/Shapes/ShapeL.js View File

@@ -1,19 +1,17 @@
1 1
 // @flow
2 2
 
3 3
 import BaseShape from "./BaseShape";
4
+import type {CustomTheme} from "../../../managers/ThemeManager";
4 5
 
5 6
 export default class ShapeL extends BaseShape {
6 7
 
7
-    #colors: Object;
8
-
9
-    constructor(colors: Object) {
10
-        super();
8
+    constructor(theme: CustomTheme) {
9
+        super(theme);
11 10
         this.position.x = 3;
12
-        this.#colors = colors;
13 11
     }
14 12
 
15 13
     getColor(): string {
16
-        return this.#colors.tetrisL;
14
+        return this.theme.colors.tetrisL;
17 15
     }
18 16
 
19 17
     getShapes() {

+ 4
- 6
src/screens/Game/Shapes/ShapeO.js View File

@@ -1,19 +1,17 @@
1 1
 // @flow
2 2
 
3 3
 import BaseShape from "./BaseShape";
4
+import type {CustomTheme} from "../../../managers/ThemeManager";
4 5
 
5 6
 export default class ShapeO extends BaseShape {
6 7
 
7
-    #colors: Object;
8
-
9
-    constructor(colors: Object) {
10
-        super();
8
+    constructor(theme: CustomTheme) {
9
+        super(theme);
11 10
         this.position.x = 4;
12
-        this.#colors = colors;
13 11
     }
14 12
 
15 13
     getColor(): string {
16
-        return this.#colors.tetrisO;
14
+        return this.theme.colors.tetrisO;
17 15
     }
18 16
 
19 17
     getShapes() {

+ 4
- 6
src/screens/Game/Shapes/ShapeS.js View File

@@ -1,19 +1,17 @@
1 1
 // @flow
2 2
 
3 3
 import BaseShape from "./BaseShape";
4
+import type {CustomTheme} from "../../../managers/ThemeManager";
4 5
 
5 6
 export default class ShapeS extends BaseShape {
6 7
 
7
-    #colors: Object;
8
-
9
-    constructor(colors: Object) {
10
-        super();
8
+    constructor(theme: CustomTheme) {
9
+        super(theme);
11 10
         this.position.x = 3;
12
-        this.#colors = colors;
13 11
     }
14 12
 
15 13
     getColor(): string {
16
-        return this.#colors.tetrisS;
14
+        return this.theme.colors.tetrisS;
17 15
     }
18 16
 
19 17
     getShapes() {

+ 4
- 6
src/screens/Game/Shapes/ShapeT.js View File

@@ -1,19 +1,17 @@
1 1
 // @flow
2 2
 
3 3
 import BaseShape from "./BaseShape";
4
+import type {CustomTheme} from "../../../managers/ThemeManager";
4 5
 
5 6
 export default class ShapeT extends BaseShape {
6 7
 
7
-    #colors: Object;
8
-
9
-    constructor(colors: Object) {
10
-        super();
8
+    constructor(theme: CustomTheme) {
9
+        super(theme);
11 10
         this.position.x = 3;
12
-        this.#colors = colors;
13 11
     }
14 12
 
15 13
     getColor(): string {
16
-        return this.#colors.tetrisT;
14
+        return this.theme.colors.tetrisT;
17 15
     }
18 16
 
19 17
     getShapes() {

+ 4
- 6
src/screens/Game/Shapes/ShapeZ.js View File

@@ -1,19 +1,17 @@
1 1
 // @flow
2 2
 
3 3
 import BaseShape from "./BaseShape";
4
+import type {CustomTheme} from "../../../managers/ThemeManager";
4 5
 
5 6
 export default class ShapeZ extends BaseShape {
6 7
 
7
-    #colors: Object;
8
-
9
-    constructor(colors: Object) {
10
-        super();
8
+    constructor(theme: CustomTheme) {
9
+        super(theme);
11 10
         this.position.x = 3;
12
-        this.#colors = colors;
13 11
     }
14 12
 
15 13
     getColor(): string {
16
-        return this.#colors.tetrisZ;
14
+        return this.theme.colors.tetrisZ;
17 15
     }
18 16
 
19 17
     getShapes() {

src/screens/Game/components/Cell.js → src/screens/Game/components/CellComponent.js View File

@@ -3,28 +3,25 @@
3 3
 import * as React from 'react';
4 4
 import {View} from 'react-native';
5 5
 import {withTheme} from 'react-native-paper';
6
+import type {CustomTheme} from "../../../managers/ThemeManager";
7
+
8
+export type Cell = {color: string, isEmpty: boolean, key: string};
6 9
 
7 10
 type Props = {
8
-    item: Object
11
+    cell: Cell,
12
+    theme: CustomTheme,
9 13
 }
10 14
 
11
-class Cell extends React.PureComponent<Props> {
12
-
13
-    colors: Object;
14
-
15
-    constructor(props) {
16
-        super(props);
17
-        this.colors = props.theme.colors;
18
-    }
15
+class CellComponent extends React.PureComponent<Props> {
19 16
 
20 17
     render() {
21
-        const item = this.props.item;
18
+        const item = this.props.cell;
22 19
         return (
23 20
             <View
24 21
                 style={{
25 22
                     flex: 1,
26 23
                     backgroundColor: item.isEmpty ? 'transparent' : item.color,
27
-                    borderColor: item.isEmpty ? 'transparent' : this.colors.tetrisBorder,
24
+                    borderColor: item.isEmpty ? 'transparent' : this.props.theme.colors.tetrisBorder,
28 25
                     borderStyle: 'solid',
29 26
                     borderRadius: 2,
30 27
                     borderWidth: 1,
@@ -38,4 +35,4 @@ class Cell extends React.PureComponent<Props> {
38 35
 
39 36
 }
40 37
 
41
-export default withTheme(Cell);
38
+export default withTheme(CellComponent);

src/screens/Game/components/Grid.js → src/screens/Game/components/GridComponent.js View File

@@ -3,10 +3,12 @@
3 3
 import * as React from 'react';
4 4
 import {View} from 'react-native';
5 5
 import {withTheme} from 'react-native-paper';
6
-import Cell from "./Cell";
6
+import type {Cell} from "./CellComponent";
7
+import CellComponent from "./CellComponent";
8
+
9
+export type Grid = Array<Array<CellComponent>>;
7 10
 
8 11
 type Props = {
9
-    navigation: Object,
10 12
     grid: Array<Array<Object>>,
11 13
     backgroundColor: string,
12 14
     height: number,
@@ -15,14 +17,7 @@ type Props = {
15 17
     containerMaxWidth: number | string,
16 18
 }
17 19
 
18
-class Grid extends React.Component<Props> {
19
-
20
-    colors: Object;
21
-
22
-    constructor(props) {
23
-        super(props);
24
-        this.colors = props.theme.colors;
25
-    }
20
+class GridComponent extends React.Component<Props> {
26 21
 
27 22
     getRow(rowNumber: number) {
28 23
         let cells = this.props.grid[rowNumber].map(this.getCellRender);
@@ -39,8 +34,8 @@ class Grid extends React.Component<Props> {
39 34
         );
40 35
     }
41 36
 
42
-    getCellRender = (item: Object) => {
43
-        return <Cell item={item} key={item.key}/>;
37
+    getCellRender = (item: Cell) => {
38
+        return <CellComponent cell={item}/>;
44 39
     };
45 40
 
46 41
     getGrid() {
@@ -67,4 +62,4 @@ class Grid extends React.Component<Props> {
67 62
     }
68 63
 }
69 64
 
70
-export default withTheme(Grid);
65
+export default withTheme(GridComponent);

+ 8
- 16
src/screens/Game/components/Preview.js View File

@@ -3,33 +3,25 @@
3 3
 import * as React from 'react';
4 4
 import {View} from 'react-native';
5 5
 import {withTheme} from 'react-native-paper';
6
-import Grid from "./Grid";
6
+import type {Grid} from "./GridComponent";
7
+import GridComponent from "./GridComponent";
7 8
 
8 9
 type Props = {
9
-    next: Object,
10
+    items: Array<Grid>,
10 11
 }
11 12
 
12 13
 class Preview extends React.PureComponent<Props> {
13 14
 
14
-    colors: Object;
15
-
16
-    constructor(props) {
17
-        super(props);
18
-        this.colors = props.theme.colors;
19
-    }
20
-
21 15
     getGrids() {
22 16
         let grids = [];
23
-        for (let i = 0; i < this.props.next.length; i++) {
24
-            grids.push(
25
-                this.getGridRender(this.props.next[i], i)
26
-            );
17
+        for (let i = 0; i < this.props.items.length; i++) {
18
+            grids.push(this.getGridRender(this.props.items[i], i));
27 19
         }
28 20
         return grids;
29 21
     }
30 22
 
31
-    getGridRender(item: Object, index: number) {
32
-        return <Grid
23
+    getGridRender(item: Grid, index: number) {
24
+        return <GridComponent
33 25
             width={item[0].length}
34 26
             height={item.length}
35 27
             grid={item}
@@ -41,7 +33,7 @@ class Preview extends React.PureComponent<Props> {
41 33
     };
42 34
 
43 35
     render() {
44
-        if (this.props.next.length > 0) {
36
+        if (this.props.items.length > 0) {
45 37
             return (
46 38
                 <View>
47 39
                     {this.getGrids()}

Loading…
Cancel
Save