/* * 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 {View} from 'react-native'; import {Caption, IconButton, Text, withTheme} from 'react-native-paper'; import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons'; import i18n from 'i18n-js'; import {StackNavigationProp} from '@react-navigation/stack'; import GameLogic from '../logic/GameLogic'; import type {GridType} from '../components/GridComponent'; import GridComponent from '../components/GridComponent'; import Preview from '../components/Preview'; import MaterialHeaderButtons, { Item, } from '../../../components/Overrides/CustomHeaderButton'; import type {OptionsDialogButtonType} from '../../../components/Dialogs/OptionsDialog'; import OptionsDialog from '../../../components/Dialogs/OptionsDialog'; type PropsType = { navigation: StackNavigationProp; route: {params: {highScore: number}}; theme: ReactNativePaper.Theme; }; type StateType = { grid: GridType; gameTime: number; gameScore: number; gameLevel: number; dialogVisible: boolean; dialogTitle: string; dialogMessage: string; dialogButtons: Array; onDialogDismiss: () => void; }; class GameMainScreen extends React.Component { static getFormattedTime(seconds: number): string { const date = new Date(); date.setHours(0); date.setMinutes(0); date.setSeconds(seconds); let format; if (date.getHours()) { format = `${date.getHours()}:${date.getMinutes()}:${date.getSeconds()}`; } else if (date.getMinutes()) { format = `${date.getMinutes()}:${date.getSeconds()}`; } else { format = date.getSeconds().toString(); } return format; } logic: GameLogic; highScore: number | null; constructor(props: PropsType) { super(props); this.highScore = null; this.logic = new GameLogic(20, 10, props.theme); this.state = { grid: this.logic.getCurrentGrid(), gameTime: 0, gameScore: 0, gameLevel: 0, dialogVisible: false, dialogTitle: '', dialogMessage: '', dialogButtons: [], onDialogDismiss: () => {}, }; if (props.route.params != null) { this.highScore = props.route.params.highScore; } } componentDidMount() { const {navigation} = this.props; navigation.setOptions({ headerRight: this.getRightButton, }); this.startGame(); } componentWillUnmount() { this.logic.endGame(true); } getRightButton = () => { return ( ); }; onTick = (score: number, level: number, newGrid: GridType) => { this.setState({ gameScore: score, gameLevel: level, grid: newGrid, }); }; onClock = (time: number) => { this.setState({ gameTime: time, }); }; onDialogDismiss = () => { this.setState({dialogVisible: false}); }; onGameEnd = (time: number, score: number, isRestart: boolean) => { const {props, state} = this; this.setState({ gameTime: time, gameScore: score, }); if (!isRestart) { props.navigation.replace('game-start', { score: state.gameScore, level: state.gameLevel, time: state.gameTime, }); } }; getStatusIcons() { const {props, state} = this; return ( {i18n.t('screens.game.time')} {GameMainScreen.getFormattedTime(state.gameTime)} {i18n.t('screens.game.level')} {state.gameLevel} ); } getScoreIcon() { const {props, state} = this; const highScore = this.highScore == null || state.gameScore > this.highScore ? state.gameScore : this.highScore; return ( {i18n.t('screens.game.score', {score: state.gameScore})} {i18n.t('screens.game.highScore', {score: highScore})} ); } getControlButtons() { const {props} = this; return ( { this.logic.rotatePressed(this.updateGrid); }} style={{flex: 1}} /> { this.logic.pressedOut(); }} onPressIn={() => { this.logic.leftPressedIn(this.updateGrid); }} /> { this.logic.pressedOut(); }} onPressIn={() => { this.logic.rightPressed(this.updateGrid); }} /> { this.logic.downPressedIn(this.updateGridScore); }} onPress={() => { this.logic.pressedOut(); }} style={{flex: 1}} color={props.theme.colors.tetrisScore} /> ); } updateGrid = (newGrid: GridType) => { this.setState({ grid: newGrid, }); }; updateGridScore = (newGrid: GridType, score?: number) => { this.setState((prevState: StateType): { grid: GridType; gameScore: number; } => ({ grid: newGrid, gameScore: score != null ? score : prevState.gameScore, })); }; togglePause = () => { this.logic.togglePause(); if (this.logic.isGamePaused()) { this.showPausePopup(); } }; showPausePopup = () => { const onDismiss = () => { this.togglePause(); this.onDialogDismiss(); }; this.setState({ dialogVisible: true, dialogTitle: i18n.t('screens.game.pause'), dialogMessage: i18n.t('screens.game.pauseMessage'), dialogButtons: [ { title: i18n.t('screens.game.restart.text'), onPress: this.showRestartConfirm, }, { title: i18n.t('screens.game.resume'), onPress: onDismiss, }, ], onDialogDismiss: onDismiss, }); }; showRestartConfirm = () => { this.setState({ dialogVisible: true, dialogTitle: i18n.t('screens.game.restart.confirm'), dialogMessage: i18n.t('screens.game.restart.confirmMessage'), dialogButtons: [ { title: i18n.t('screens.game.restart.confirmYes'), onPress: () => { this.onDialogDismiss(); this.startGame(); }, }, { title: i18n.t('screens.game.restart.confirmNo'), onPress: this.showPausePopup, }, ], onDialogDismiss: this.showPausePopup, }); }; startGame = () => { this.logic.startGame(this.onTick, this.onClock, this.onGameEnd); }; render() { const {props, state} = this; return ( {this.getStatusIcons()} {this.getScoreIcon()} {this.getControlButtons()} ); } } export default withTheme(GameMainScreen);