fix theme and errors
This commit is contained in:
parent
2cca40034d
commit
4f45da5ab5
@ -75,9 +75,12 @@ function App() {
|
||||
return (
|
||||
<NavigationContainer>
|
||||
<Stack.Navigator>
|
||||
<Stack.Screen name="Home" component={HomeScreen} initialParams={{context}} />
|
||||
<Stack.Screen name="Loby" component={LobyScreen} />
|
||||
<Stack.Screen name="Game" component={GameScreen} />
|
||||
<Stack.Screen name="Home" component={HomeScreen} initialParams={{context}}
|
||||
options={{title: t("Mancala"), headerStyle: { backgroundColor: context.themeManager.theme.appBarBgColor }}}/>
|
||||
<Stack.Screen name="Loby" component={LobyScreen}
|
||||
options={{title: t("Mancala"), headerStyle: { backgroundColor: context.themeManager.theme.appBarBgColor }}}/>
|
||||
<Stack.Screen name="Game" component={GameScreen}
|
||||
options={{title: t("Mancala"), headerStyle: { backgroundColor: context.themeManager.theme.appBarBgColor }}}/>
|
||||
</Stack.Navigator>
|
||||
</NavigationContainer>
|
||||
);
|
||||
|
||||
@ -7,7 +7,9 @@ import PitView from "./PitView";
|
||||
import StoreView from "./StoreView";
|
||||
import { Game } from "../../models/Game";
|
||||
import { Pit } from "mancala.js";
|
||||
import { View } from "react-native";
|
||||
import { View, Dimensions } from "react-native";
|
||||
import StoneView from "./StoneView";
|
||||
import Util from "../../util/Util";
|
||||
|
||||
const BoardView: FunctionComponent<{
|
||||
game: Game;
|
||||
@ -17,11 +19,30 @@ const BoardView: FunctionComponent<{
|
||||
revert: boolean;
|
||||
onPitSelect: (index: number, pit: Pit) => void;
|
||||
}> = ({ game, context, boardId, boardViewModel, revert, onPitSelect: onPitSelect }) => {
|
||||
const windowWidth = Dimensions.get('window').width;
|
||||
const windowHeight = Dimensions.get('window').height;
|
||||
|
||||
const boardMargin = 0;
|
||||
const boardPadding = 10;
|
||||
const gap = 5;
|
||||
const totalGap = gap * 7;
|
||||
|
||||
const pitWidth = (windowWidth - boardMargin * 2 - boardPadding * 2 - totalGap) / 8;
|
||||
|
||||
const mancalaGame = game?.mancalaGame;
|
||||
const theme = context.themeManager.theme;
|
||||
|
||||
const createPitView = (key: any, pit: Pit, pitViewModel: PitViewModel) => {
|
||||
return <PitView key={key} pitViewModel={pitViewModel} onClick={() => onPitSelect(pit.index, pit)} />;
|
||||
const stones = [...Util.range(pitViewModel.stoneCount)].map((i, index) => (
|
||||
<StoneView key={index} color={pitViewModel.stoneColor} style={{width: pitWidth / 10, height: pitWidth / 10}}/>
|
||||
));
|
||||
return <PitView
|
||||
key={key}
|
||||
pitViewModel={pitViewModel}
|
||||
onClick={() => onPitSelect(pit.index, pit)}
|
||||
style={{width: pitWidth, height: pitWidth}} >
|
||||
{stones}
|
||||
</PitView>;
|
||||
};
|
||||
const createPitViewList = (pits: Pit[]) => pits.map((pit, index) => createPitView(index, pit, boardViewModel.pits[pit.index]));
|
||||
|
||||
@ -31,29 +52,59 @@ const BoardView: FunctionComponent<{
|
||||
const player2BankIndex = mancalaGame?.board.player2BankIndex();
|
||||
const player1BankViewModel = boardViewModel.pits[player1BankIndex];
|
||||
const player2BankViewModel = boardViewModel.pits[player2BankIndex];
|
||||
|
||||
const primaryStoreViewModel = revert ? player1BankViewModel : player2BankViewModel;
|
||||
const secondaryStoreViewModel = revert ? player2BankViewModel : player1BankViewModel;
|
||||
const stonesPrimaryStore = [...Util.range(primaryStoreViewModel.stoneCount)].map((i, index) => (
|
||||
<StoneView key={index} color={primaryStoreViewModel.stoneColor} style={{width: pitWidth / 10, height: pitWidth / 10}}/>
|
||||
));
|
||||
const stonesSecondaryStore = [...Util.range(secondaryStoreViewModel.stoneCount)].map((i, index) => (
|
||||
<StoneView key={index} color={secondaryStoreViewModel.stoneColor} style={{width: pitWidth / 10, height: pitWidth / 10}} />
|
||||
));
|
||||
|
||||
return (
|
||||
<View style={{
|
||||
backgroundColor: theme.boardColor,
|
||||
padding: 20,
|
||||
//display: 'grid',
|
||||
//gridTemplateColumns: 'repeat(8, 11vw)',
|
||||
//gridTemplateRows: 'repeat(2, 11vw)',
|
||||
borderRadius: 30
|
||||
padding: boardPadding,
|
||||
borderRadius: 20,
|
||||
flexDirection: "row",
|
||||
gap: gap,
|
||||
height: "auto",
|
||||
}}>
|
||||
<StoreView
|
||||
context={context}
|
||||
pitViewModel={revert ? player2BankViewModel : player1BankViewModel}
|
||||
gridColumn="8 / 9"
|
||||
gridRow="1 / 3"
|
||||
/>
|
||||
pitViewModel={primaryStoreViewModel}
|
||||
style={{width: pitWidth, height: pitWidth * 2 + gap}}
|
||||
fontSize={pitWidth / 5}
|
||||
>
|
||||
{stonesPrimaryStore}
|
||||
</StoreView>
|
||||
<View style={{flex: 6}}>
|
||||
<View style={{
|
||||
flexDirection: "row",
|
||||
width: '100%',
|
||||
flex: 1,
|
||||
gap: gap
|
||||
}}>
|
||||
{revert ? player1Pits?.reverse() : player2Pits?.reverse()}
|
||||
</View>
|
||||
<View style={{
|
||||
flexDirection: "row",
|
||||
width: '100%',
|
||||
flex: 1,
|
||||
gap: gap
|
||||
}}>
|
||||
{revert ? player2Pits : player1Pits}
|
||||
</View>
|
||||
</View>
|
||||
<StoreView
|
||||
context={context}
|
||||
pitViewModel={revert ? player1BankViewModel : player2BankViewModel}
|
||||
gridColumn="1 / 2"
|
||||
gridRow="1 / 3"
|
||||
/>
|
||||
{revert ? player1Pits?.reverse() : player2Pits?.reverse()}
|
||||
{revert ? player2Pits : player1Pits}
|
||||
pitViewModel={secondaryStoreViewModel}
|
||||
style={{width: pitWidth, height: pitWidth * 2 + gap}}
|
||||
fontSize={pitWidth / 5}
|
||||
>
|
||||
{stonesSecondaryStore}
|
||||
</StoreView>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
@ -3,33 +3,35 @@ import { FunctionComponent } from "react";
|
||||
import Util from "../../util/Util";
|
||||
import PitViewModel from "../../viewmodel/PitViewModel";
|
||||
import StoneView from "./StoneView";
|
||||
import { Pressable, View } from "react-native";
|
||||
import { Pressable, View, ViewStyle } from "react-native";
|
||||
|
||||
const PitView: FunctionComponent<{
|
||||
pitViewModel: PitViewModel;
|
||||
onClick: () => void;
|
||||
}> = ({ pitViewModel, onClick }) => {
|
||||
const stones = [...Util.range(pitViewModel.stoneCount)].map((i, index) => (
|
||||
<StoneView key={index} color={pitViewModel.stoneColor} />
|
||||
));
|
||||
|
||||
style: ViewStyle,
|
||||
children: React.ReactNode
|
||||
}> = ({ pitViewModel, onClick, style, children }) => {
|
||||
return (
|
||||
<Pressable onPress={onClick}>
|
||||
<View style={{
|
||||
backgroundColor: pitViewModel.pitColor,
|
||||
margin: 5,
|
||||
<View style={[style, {
|
||||
backgroundColor: pitViewModel.pitColor,
|
||||
borderRadius: 50,
|
||||
//justifyItems: 'center',
|
||||
}]}>
|
||||
<Pressable onPress={onClick} style={{
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
padding: 5,
|
||||
borderRadius: 50,
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
alignContent: 'center',
|
||||
justifyContent: 'center',
|
||||
//justifyItems: 'center',
|
||||
flexWrap: 'wrap',
|
||||
flexDirection: "row",
|
||||
flexWrap: "wrap"
|
||||
}}>
|
||||
{stones}
|
||||
</View>
|
||||
</Pressable>
|
||||
{children}
|
||||
</Pressable>
|
||||
</View>
|
||||
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@ -1,16 +1,16 @@
|
||||
import * as React from "react";
|
||||
import { FunctionComponent } from "react";
|
||||
import { View } from "react-native";
|
||||
import { View, ViewStyle } from "react-native";
|
||||
|
||||
const StoneView: FunctionComponent<{ color: string }> = ({ color }) => {
|
||||
const StoneView: FunctionComponent<{ color: string, style?: ViewStyle }> = ({ color, style }) => {
|
||||
return (
|
||||
<View style={{
|
||||
<View style={[{
|
||||
backgroundColor: color,
|
||||
margin: 1,
|
||||
width: 10,
|
||||
height: 10,
|
||||
borderRadius: 10,
|
||||
}}>
|
||||
}, style]}>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
@ -5,17 +5,16 @@ import { getColorByBrightness } from "../../util/ColorUtil";
|
||||
import Util from "../../util/Util";
|
||||
import PitViewModel from "../../viewmodel/PitViewModel";
|
||||
import StoneView from "./StoneView";
|
||||
import { Text, View } from "react-native";
|
||||
import { Text, View, ViewStyle } from "react-native";
|
||||
|
||||
const StoreView: FunctionComponent<{
|
||||
context: Context;
|
||||
pitViewModel: PitViewModel;
|
||||
gridColumn: string;
|
||||
gridRow: string;
|
||||
}> = ({ context, pitViewModel, gridColumn, gridRow }) => {
|
||||
const stones = [...Util.range(pitViewModel.stoneCount)].map((i, index) => (
|
||||
<StoneView key={index} color={pitViewModel.stoneColor} />
|
||||
));
|
||||
style: ViewStyle,
|
||||
children: React.ReactNode
|
||||
fontSize: number
|
||||
}> = ({ context, pitViewModel, style, children, fontSize }) => {
|
||||
|
||||
const textColor = getColorByBrightness(
|
||||
pitViewModel.pitColor,
|
||||
context.themeManager.theme.textColor,
|
||||
@ -23,11 +22,8 @@ const StoreView: FunctionComponent<{
|
||||
);
|
||||
return (
|
||||
<View
|
||||
style={{
|
||||
style={[style, {
|
||||
backgroundColor: pitViewModel.pitColor,
|
||||
//gridColumn: gridColumn,
|
||||
//gridRow: gridRow,
|
||||
margin: 5,
|
||||
borderRadius: 50,
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
@ -35,17 +31,18 @@ const StoreView: FunctionComponent<{
|
||||
alignContent: 'center',
|
||||
flexWrap: 'wrap',
|
||||
position: 'relative',
|
||||
}}>
|
||||
{stones}
|
||||
flexDirection: "row"
|
||||
}]}>
|
||||
{children}
|
||||
<Text style={{
|
||||
color: textColor,
|
||||
position: 'absolute',
|
||||
bottom: 20,
|
||||
bottom: fontSize/2,
|
||||
fontFamily: 'monospace',
|
||||
fontWeight: 'bold',
|
||||
fontSize: 20,
|
||||
fontSize: fontSize
|
||||
}}>
|
||||
{stones.length}
|
||||
{pitViewModel.stoneCount}
|
||||
</Text>
|
||||
</View>
|
||||
);
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import * as React from 'react';
|
||||
import { View, Button, Text, useWindowDimensions } from 'react-native';
|
||||
import { View, Button, Text, useWindowDimensions, Alert } from 'react-native';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { GameScreenProps } from '../types';
|
||||
import { useState } from 'react';
|
||||
@ -76,7 +76,7 @@ export function GameScreen({ navigation, route }: GameScreenProps) {
|
||||
}
|
||||
const onGameCrashed = (message: any) => {
|
||||
const newCrashMessage = message as string;
|
||||
Snackbar.show({text: t("InternalErrorOccurred")});
|
||||
Snackbar.show({ text: t("InternalErrorOccurred") });
|
||||
console.error("on_game_crash");
|
||||
console.error(newCrashMessage);
|
||||
}
|
||||
@ -125,24 +125,29 @@ export function GameScreen({ navigation, route }: GameScreenProps) {
|
||||
|
||||
const onLeaveGameClick = () => {
|
||||
if (Util.checkConnectionAndMaybeAlert(context, t("ConnectionLost"))) return;
|
||||
|
||||
// TODO
|
||||
//swal({
|
||||
// title: context.texts.AreYouSureToLeaveGame,
|
||||
// icon: "warning",
|
||||
// buttons: [context.texts.Yes, context.texts.Cancel],
|
||||
// dangerMode: true,
|
||||
//})
|
||||
// .then((cancel) => {
|
||||
// if (!cancel) {
|
||||
// context.rtmt.sendMessage(channel_leave_game, {});
|
||||
// }
|
||||
// });
|
||||
Alert.alert(t('AreYouSureToLeaveGame'), "", [
|
||||
{
|
||||
text: t('Cancel'),
|
||||
style: 'cancel',
|
||||
},
|
||||
{
|
||||
text: t('Yes'),
|
||||
onPress: () => {
|
||||
context.rtmt.sendMessage(channel_leave_game, {});
|
||||
updateHeaderButton();
|
||||
},
|
||||
style: 'default',
|
||||
},
|
||||
],
|
||||
{
|
||||
cancelable: true,
|
||||
onDismiss: () => { }
|
||||
});
|
||||
};
|
||||
|
||||
const onNewGameClick = () => {
|
||||
if (Util.checkConnectionAndMaybeAlert(context, t("ConnectionLost"))) return;
|
||||
navigation.navigate("Loby", { context })
|
||||
navigation.replace("Loby", { context })
|
||||
};
|
||||
|
||||
const onPitSelect = (index: number, pit: Pit) => {
|
||||
@ -150,31 +155,31 @@ export function GameScreen({ navigation, route }: GameScreenProps) {
|
||||
return;
|
||||
}
|
||||
if (userKeyWhoLeave) {
|
||||
Snackbar.show({text: t("GameEnded")});
|
||||
Snackbar.show({ text: t("GameEnded") });
|
||||
return;
|
||||
}
|
||||
if (game.mancalaGame.state === "ended") {
|
||||
Snackbar.show({text: t("GameEnded")});
|
||||
Snackbar.show({ text: t("GameEnded") });
|
||||
return;
|
||||
}
|
||||
if (Util.checkConnectionAndMaybeAlert(context, t("ConnectionLost"))) return;
|
||||
if (game.mancalaGame.getPlayerIdByIndex(index) !== userKey) {
|
||||
Snackbar.show({text: t("UCanOnlyPlayYourOwnPits")});
|
||||
Snackbar.show({ text: t("UCanOnlyPlayYourOwnPits") });
|
||||
return;
|
||||
}
|
||||
const pitIndexForUser = index % (game.mancalaGame.board.totalPitCount() / 2);
|
||||
if (!game.mancalaGame.canPlayerMove(userKey, pitIndexForUser)) {
|
||||
Snackbar.show({text: t("OpponentTurn")});
|
||||
Snackbar.show({ text: t("OpponentTurn") });
|
||||
return;
|
||||
}
|
||||
if (checkHasAnOngoingAction()) {
|
||||
Snackbar.show({text: t("UMustWaitUntilCurrentMoveComplete")});
|
||||
Snackbar.show({ text: t("UMustWaitUntilCurrentMoveComplete") });
|
||||
return;
|
||||
}
|
||||
if (!boardViewModel) return;
|
||||
//TODO: this check should be in mancala.js
|
||||
if (pit.stoneCount === 0) {
|
||||
Snackbar.show({text: t("UCanNotPlayEmptyPit")});
|
||||
Snackbar.show({ text: t("UCanNotPlayEmptyPit") });
|
||||
return;
|
||||
}
|
||||
setHasOngoingAction(true);
|
||||
@ -206,6 +211,25 @@ export function GameScreen({ navigation, route }: GameScreenProps) {
|
||||
};
|
||||
}, []);
|
||||
|
||||
const updateHeaderButton = () => {
|
||||
console.info(game?.mancalaGame.state)
|
||||
navigation.setOptions({
|
||||
headerRight: () => (
|
||||
<Button onPress={() => {
|
||||
if (game?.mancalaGame.state !== "ended") {
|
||||
onLeaveGameClick();
|
||||
} else {
|
||||
onNewGameClick();
|
||||
}
|
||||
}} title={game?.mancalaGame.state !== "ended" ? t('Leave') : t('NewGame')} />
|
||||
),
|
||||
});
|
||||
}
|
||||
|
||||
React.useEffect(() => {
|
||||
updateHeaderButton();
|
||||
}, [navigation, game]);
|
||||
|
||||
const textColorOnAppBar = getColorByBrightness(
|
||||
context.themeManager.theme.appBarBgColor,
|
||||
context.themeManager.theme.textColor,
|
||||
@ -279,21 +303,18 @@ export function GameScreen({ navigation, route }: GameScreenProps) {
|
||||
|
||||
function renderMobileBoardToolbar() {
|
||||
return <BoardToolbar style={{ justifyContent: "center" }} visible={showBoardView && isMobile || false}>
|
||||
<View />
|
||||
{buildInfoPanel({ visible: isMobile })}
|
||||
<View />
|
||||
</BoardToolbar>;
|
||||
}
|
||||
|
||||
function buildBoardTopToolbar() {
|
||||
return <BoardToolbar style={{ alignItems: "flex-end" }} visible={showBoardView || false}>
|
||||
<UserStatus style={{
|
||||
marginBottom: 15, marginLeft: "6%", maxWidth: isMobile ? 40 : 30,
|
||||
width: isMobile ? 40 : 30
|
||||
}} context={context} layoutMode="left" user={topLocatedUser} visible={showBoardView || false} />
|
||||
<UserStatus style={{ marginLeft: 10, width: 100 }} context={context}
|
||||
layoutMode="left" user={topLocatedUser} visible={showBoardView || false} />
|
||||
{buildInfoPanel({ visible: !isMobile })}
|
||||
<UserStatus style={{
|
||||
marginBottom: 15, marginRight: "6%", maxWidth: isMobile ? 40: 30,
|
||||
width: isMobile ? 40: 30
|
||||
}} context={context} layoutMode="right" user={bottomLocatedUser} visible={showBoardView || false} />
|
||||
<UserStatus style={{ marginLeft: 10, width: 100 }} context={context} layoutMode="right" user={bottomLocatedUser} visible={showBoardView || false} />
|
||||
</BoardToolbar>;
|
||||
}
|
||||
|
||||
|
||||
@ -1,7 +1,8 @@
|
||||
import * as React from 'react';
|
||||
import { View, Button } from 'react-native';
|
||||
import { View, Button, Pressable, Text } from 'react-native';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { HomeScreenProps } from '../types';
|
||||
import CircularPanel from '../components/CircularPanel';
|
||||
|
||||
export function HomeScreen({ navigation, route }: HomeScreenProps) {
|
||||
|
||||
@ -9,10 +10,10 @@ export function HomeScreen({ navigation, route }: HomeScreenProps) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
|
||||
<Button
|
||||
title={t('NewGame')}
|
||||
onPress={() => navigation.navigate('Loby', { context })}></Button>
|
||||
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center', backgroundColor: context.themeManager.theme?.background }}>
|
||||
<Pressable onPress={() => navigation.replace('Loby', { context })}>
|
||||
<CircularPanel color={context.themeManager.theme?.boardColor} children={<Text style={{color: context.themeManager.theme.textColor}}>{t('NewGame')}</Text>}/>
|
||||
</Pressable>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
@ -14,7 +14,7 @@ export default function LobyScreen({ navigation, route }: LobyScreenProps) {
|
||||
const onGameStart = async (message: Object) => {
|
||||
const newGame: CommonMancalaGame = message as CommonMancalaGame;
|
||||
const userKey = await context.userKeyStore.getUserKey();
|
||||
navigation.navigate("Game", { context, gameId: newGame.id, userKey })
|
||||
navigation.replace("Game", { context, gameId: newGame.id, userKey })
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
@ -26,7 +26,7 @@ export default function LobyScreen({ navigation, route }: LobyScreenProps) {
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
|
||||
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center', backgroundColor: context.themeManager.theme?.background }}>
|
||||
<Text>{t('SearchingOpponent')}</Text>
|
||||
</View>
|
||||
);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user