/*
* 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 React, { useCallback, useLayoutEffect, useRef, useState } from 'react';
import { StyleSheet, View } from 'react-native';
import { useTheme } from 'react-native-paper';
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';
import GENERAL_STYLES from '../../../constants/Styles';
import { MainRoutes } from '../../../navigation/MainNavigator';
import GameStatus from '../components/GameStatus';
import GameControls from '../components/GameControls';
import GameScore from '../components/GameScore';
import { usePreferences } from '../../../context/preferencesContext';
import {
getPreferenceObject,
PreferenceKeys,
} from '../../../utils/asyncStorage';
import { useFocusEffect, useNavigation } from '@react-navigation/core';
const styles = StyleSheet.create({
container: {
flex: 1,
flexDirection: 'row',
},
gridContainer: {
flex: 4,
},
controlsContainer: {
height: 80,
flexDirection: 'row',
},
directionsContainer: {
flexDirection: 'row',
flex: 4,
},
preview: {
marginLeft: 'auto',
marginRight: 'auto',
marginTop: 10,
},
});
export default function GameMainScreen() {
const theme = useTheme();
const navigation = useNavigation>();
const logic = useRef(new GameLogic(20, 10, theme));
const [gameTime, setGameTime] = useState(0);
const [gameState, setGameState] = useState({
grid: logic.current.getCurrentGrid(),
gameScore: 0,
gameLevel: 0,
});
const [dialogContent, setDialogContent] =
useState<{
dialogTitle: string;
dialogMessage: string;
dialogButtons: Array;
onDialogDismiss: () => void;
}>();
const { preferences, updatePreferences } = usePreferences();
function getScores() {
const pref = getPreferenceObject(PreferenceKeys.gameScores, preferences) as
| Array
| undefined;
if (pref) {
return pref.sort((a, b) => b - a);
} else {
return [];
}
}
const savedScores = getScores();
const highScore = savedScores.length > 0 ? savedScores[0] : undefined;
useLayoutEffect(() => {
navigation.setOptions({
headerRight: getRightButton,
});
startGame();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [navigation]);
useFocusEffect(
useCallback(() => {
const l = logic.current;
return () => l.endGame(true);
}, [])
);
const getRightButton = () => (
);
const onTick = (score: number, level: number, newGrid: GridType) => {
setGameState({
gameScore: score,
gameLevel: level,
grid: newGrid,
});
};
const onDialogDismiss = () => setDialogContent(undefined);
const onGameEnd = (time: number, score: number, isRestart: boolean) => {
setGameState((prevState) => ({
...prevState,
gameScore: score,
}));
setGameTime(time);
const newScores = [...savedScores];
const isHighScore = newScores.length === 0 || score > newScores[0];
for (let i = 0; i < 3; i += 1) {
if (newScores.length > i && score > newScores[i]) {
newScores.splice(i, 0, score);
break;
} else if (newScores.length <= i) {
newScores.push(score);
break;
}
}
if (newScores.length > 3) {
newScores.splice(3, 1);
}
if (newScores.some((item, i) => item !== savedScores[i])) {
updatePreferences(PreferenceKeys.gameScores, newScores);
}
if (!isRestart) {
navigation.replace(MainRoutes.GameStart, {
score: score,
level: gameState.gameLevel,
time: time,
isHighScore: isHighScore,
});
}
};
const onDirectionPressed = (newGrid: GridType, score?: number) => {
setGameState((prevState) => ({
...prevState,
grid: newGrid,
gameScore: score != null ? score : prevState.gameScore,
}));
};
const togglePause = () => {
logic.current.togglePause();
if (logic.current.isGamePaused()) {
showPausePopup();
}
};
const showPausePopup = () => {
const onDismiss = () => {
togglePause();
onDialogDismiss();
};
setDialogContent({
dialogTitle: i18n.t('screens.game.pause'),
dialogMessage: i18n.t('screens.game.pauseMessage'),
dialogButtons: [
{
title: i18n.t('screens.game.restart.text'),
onPress: showRestartConfirm,
},
{
title: i18n.t('screens.game.resume'),
onPress: onDismiss,
},
],
onDialogDismiss: onDismiss,
});
};
const showRestartConfirm = () => {
setDialogContent({
dialogTitle: i18n.t('screens.game.restart.confirm'),
dialogMessage: i18n.t('screens.game.restart.confirmMessage'),
dialogButtons: [
{
title: i18n.t('screens.game.restart.confirmYes'),
onPress: () => {
onDialogDismiss();
startGame();
},
},
{
title: i18n.t('screens.game.restart.confirmNo'),
onPress: showPausePopup,
},
],
onDialogDismiss: showPausePopup,
});
};
const startGame = () => {
logic.current.startGame(onTick, setGameTime, onGameEnd);
};
return (
{dialogContent ? (
) : null}
);
}