fix theme and errors

This commit is contained in:
Halit Aksoy 2024-03-31 16:39:39 +03:00
parent 2cca40034d
commit 4f45da5ab5
8 changed files with 168 additions and 93 deletions

View File

@ -75,9 +75,12 @@ function App() {
return ( return (
<NavigationContainer> <NavigationContainer>
<Stack.Navigator> <Stack.Navigator>
<Stack.Screen name="Home" component={HomeScreen} initialParams={{context}} /> <Stack.Screen name="Home" component={HomeScreen} initialParams={{context}}
<Stack.Screen name="Loby" component={LobyScreen} /> options={{title: t("Mancala"), headerStyle: { backgroundColor: context.themeManager.theme.appBarBgColor }}}/>
<Stack.Screen name="Game" component={GameScreen} /> <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> </Stack.Navigator>
</NavigationContainer> </NavigationContainer>
); );

View File

@ -7,7 +7,9 @@ import PitView from "./PitView";
import StoreView from "./StoreView"; import StoreView from "./StoreView";
import { Game } from "../../models/Game"; import { Game } from "../../models/Game";
import { Pit } from "mancala.js"; 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<{ const BoardView: FunctionComponent<{
game: Game; game: Game;
@ -17,11 +19,30 @@ const BoardView: FunctionComponent<{
revert: boolean; revert: boolean;
onPitSelect: (index: number, pit: Pit) => void; onPitSelect: (index: number, pit: Pit) => void;
}> = ({ game, context, boardId, boardViewModel, revert, onPitSelect: onPitSelect }) => { }> = ({ 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 mancalaGame = game?.mancalaGame;
const theme = context.themeManager.theme; const theme = context.themeManager.theme;
const createPitView = (key: any, pit: Pit, pitViewModel: PitViewModel) => { 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])); 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 player2BankIndex = mancalaGame?.board.player2BankIndex();
const player1BankViewModel = boardViewModel.pits[player1BankIndex]; const player1BankViewModel = boardViewModel.pits[player1BankIndex];
const player2BankViewModel = boardViewModel.pits[player2BankIndex]; 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 ( return (
<View style={{ <View style={{
backgroundColor: theme.boardColor, backgroundColor: theme.boardColor,
padding: 20, padding: boardPadding,
//display: 'grid', borderRadius: 20,
//gridTemplateColumns: 'repeat(8, 11vw)', flexDirection: "row",
//gridTemplateRows: 'repeat(2, 11vw)', gap: gap,
borderRadius: 30 height: "auto",
}}> }}>
<StoreView <StoreView
context={context} context={context}
pitViewModel={revert ? player2BankViewModel : player1BankViewModel} pitViewModel={primaryStoreViewModel}
gridColumn="8 / 9" style={{width: pitWidth, height: pitWidth * 2 + gap}}
gridRow="1 / 3" 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 <StoreView
context={context} context={context}
pitViewModel={revert ? player1BankViewModel : player2BankViewModel} pitViewModel={secondaryStoreViewModel}
gridColumn="1 / 2" style={{width: pitWidth, height: pitWidth * 2 + gap}}
gridRow="1 / 3" fontSize={pitWidth / 5}
/> >
{revert ? player1Pits?.reverse() : player2Pits?.reverse()} {stonesSecondaryStore}
{revert ? player2Pits : player1Pits} </StoreView>
</View> </View>
); );
}; };

View File

@ -3,33 +3,35 @@ import { FunctionComponent } from "react";
import Util from "../../util/Util"; import Util from "../../util/Util";
import PitViewModel from "../../viewmodel/PitViewModel"; import PitViewModel from "../../viewmodel/PitViewModel";
import StoneView from "./StoneView"; import StoneView from "./StoneView";
import { Pressable, View } from "react-native"; import { Pressable, View, ViewStyle } from "react-native";
const PitView: FunctionComponent<{ const PitView: FunctionComponent<{
pitViewModel: PitViewModel; pitViewModel: PitViewModel;
onClick: () => void; onClick: () => void;
}> = ({ pitViewModel, onClick }) => { style: ViewStyle,
const stones = [...Util.range(pitViewModel.stoneCount)].map((i, index) => ( children: React.ReactNode
<StoneView key={index} color={pitViewModel.stoneColor} /> }> = ({ pitViewModel, onClick, style, children }) => {
));
return ( return (
<Pressable onPress={onClick}> <View style={[style, {
<View style={{
backgroundColor: pitViewModel.pitColor, backgroundColor: pitViewModel.pitColor,
margin: 5,
padding: 5,
borderRadius: 50, borderRadius: 50,
//justifyItems: 'center',
}]}>
<Pressable onPress={onClick} style={{
width: "100%",
height: "100%",
padding: 5,
display: 'flex', display: 'flex',
alignItems: 'center', alignItems: 'center',
alignContent: 'center', alignContent: 'center',
justifyContent: 'center', justifyContent: 'center',
//justifyItems: 'center', flexDirection: "row",
flexWrap: 'wrap', flexWrap: "wrap"
}}> }}>
{stones} {children}
</View>
</Pressable> </Pressable>
</View>
); );
}; };

View File

@ -1,16 +1,16 @@
import * as React from "react"; import * as React from "react";
import { FunctionComponent } 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 ( return (
<View style={{ <View style={[{
backgroundColor: color, backgroundColor: color,
margin: 1, margin: 1,
width: 10, width: 10,
height: 10, height: 10,
borderRadius: 10, borderRadius: 10,
}}> }, style]}>
</View> </View>
); );
}; };

View File

@ -5,17 +5,16 @@ import { getColorByBrightness } from "../../util/ColorUtil";
import Util from "../../util/Util"; import Util from "../../util/Util";
import PitViewModel from "../../viewmodel/PitViewModel"; import PitViewModel from "../../viewmodel/PitViewModel";
import StoneView from "./StoneView"; import StoneView from "./StoneView";
import { Text, View } from "react-native"; import { Text, View, ViewStyle } from "react-native";
const StoreView: FunctionComponent<{ const StoreView: FunctionComponent<{
context: Context; context: Context;
pitViewModel: PitViewModel; pitViewModel: PitViewModel;
gridColumn: string; style: ViewStyle,
gridRow: string; children: React.ReactNode
}> = ({ context, pitViewModel, gridColumn, gridRow }) => { fontSize: number
const stones = [...Util.range(pitViewModel.stoneCount)].map((i, index) => ( }> = ({ context, pitViewModel, style, children, fontSize }) => {
<StoneView key={index} color={pitViewModel.stoneColor} />
));
const textColor = getColorByBrightness( const textColor = getColorByBrightness(
pitViewModel.pitColor, pitViewModel.pitColor,
context.themeManager.theme.textColor, context.themeManager.theme.textColor,
@ -23,11 +22,8 @@ const StoreView: FunctionComponent<{
); );
return ( return (
<View <View
style={{ style={[style, {
backgroundColor: pitViewModel.pitColor, backgroundColor: pitViewModel.pitColor,
//gridColumn: gridColumn,
//gridRow: gridRow,
margin: 5,
borderRadius: 50, borderRadius: 50,
display: 'flex', display: 'flex',
alignItems: 'center', alignItems: 'center',
@ -35,17 +31,18 @@ const StoreView: FunctionComponent<{
alignContent: 'center', alignContent: 'center',
flexWrap: 'wrap', flexWrap: 'wrap',
position: 'relative', position: 'relative',
}}> flexDirection: "row"
{stones} }]}>
{children}
<Text style={{ <Text style={{
color: textColor, color: textColor,
position: 'absolute', position: 'absolute',
bottom: 20, bottom: fontSize/2,
fontFamily: 'monospace', fontFamily: 'monospace',
fontWeight: 'bold', fontWeight: 'bold',
fontSize: 20, fontSize: fontSize
}}> }}>
{stones.length} {pitViewModel.stoneCount}
</Text> </Text>
</View> </View>
); );

View File

@ -1,5 +1,5 @@
import * as React from 'react'; 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 { useTranslation } from 'react-i18next';
import { GameScreenProps } from '../types'; import { GameScreenProps } from '../types';
import { useState } from 'react'; import { useState } from 'react';
@ -125,24 +125,29 @@ export function GameScreen({ navigation, route }: GameScreenProps) {
const onLeaveGameClick = () => { const onLeaveGameClick = () => {
if (Util.checkConnectionAndMaybeAlert(context, t("ConnectionLost"))) return; if (Util.checkConnectionAndMaybeAlert(context, t("ConnectionLost"))) return;
Alert.alert(t('AreYouSureToLeaveGame'), "", [
// TODO {
//swal({ text: t('Cancel'),
// title: context.texts.AreYouSureToLeaveGame, style: 'cancel',
// icon: "warning", },
// buttons: [context.texts.Yes, context.texts.Cancel], {
// dangerMode: true, text: t('Yes'),
//}) onPress: () => {
// .then((cancel) => { context.rtmt.sendMessage(channel_leave_game, {});
// if (!cancel) { updateHeaderButton();
// context.rtmt.sendMessage(channel_leave_game, {}); },
// } style: 'default',
// }); },
],
{
cancelable: true,
onDismiss: () => { }
});
}; };
const onNewGameClick = () => { const onNewGameClick = () => {
if (Util.checkConnectionAndMaybeAlert(context, t("ConnectionLost"))) return; if (Util.checkConnectionAndMaybeAlert(context, t("ConnectionLost"))) return;
navigation.navigate("Loby", { context }) navigation.replace("Loby", { context })
}; };
const onPitSelect = (index: number, pit: Pit) => { const onPitSelect = (index: number, pit: Pit) => {
@ -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( const textColorOnAppBar = getColorByBrightness(
context.themeManager.theme.appBarBgColor, context.themeManager.theme.appBarBgColor,
context.themeManager.theme.textColor, context.themeManager.theme.textColor,
@ -279,21 +303,18 @@ export function GameScreen({ navigation, route }: GameScreenProps) {
function renderMobileBoardToolbar() { function renderMobileBoardToolbar() {
return <BoardToolbar style={{ justifyContent: "center" }} visible={showBoardView && isMobile || false}> return <BoardToolbar style={{ justifyContent: "center" }} visible={showBoardView && isMobile || false}>
<View />
{buildInfoPanel({ visible: isMobile })} {buildInfoPanel({ visible: isMobile })}
<View />
</BoardToolbar>; </BoardToolbar>;
} }
function buildBoardTopToolbar() { function buildBoardTopToolbar() {
return <BoardToolbar style={{ alignItems: "flex-end" }} visible={showBoardView || false}> return <BoardToolbar style={{ alignItems: "flex-end" }} visible={showBoardView || false}>
<UserStatus style={{ <UserStatus style={{ marginLeft: 10, width: 100 }} context={context}
marginBottom: 15, marginLeft: "6%", maxWidth: isMobile ? 40 : 30, layoutMode="left" user={topLocatedUser} visible={showBoardView || false} />
width: isMobile ? 40 : 30
}} context={context} layoutMode="left" user={topLocatedUser} visible={showBoardView || false} />
{buildInfoPanel({ visible: !isMobile })} {buildInfoPanel({ visible: !isMobile })}
<UserStatus style={{ <UserStatus style={{ marginLeft: 10, width: 100 }} context={context} layoutMode="right" user={bottomLocatedUser} visible={showBoardView || false} />
marginBottom: 15, marginRight: "6%", maxWidth: isMobile ? 40: 30,
width: isMobile ? 40: 30
}} context={context} layoutMode="right" user={bottomLocatedUser} visible={showBoardView || false} />
</BoardToolbar>; </BoardToolbar>;
} }

View File

@ -1,7 +1,8 @@
import * as React from 'react'; 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 { useTranslation } from 'react-i18next';
import { HomeScreenProps } from '../types'; import { HomeScreenProps } from '../types';
import CircularPanel from '../components/CircularPanel';
export function HomeScreen({ navigation, route }: HomeScreenProps) { export function HomeScreen({ navigation, route }: HomeScreenProps) {
@ -9,10 +10,10 @@ export function HomeScreen({ navigation, route }: HomeScreenProps) {
const { t } = useTranslation(); const { t } = useTranslation();
return ( return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}> <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center', backgroundColor: context.themeManager.theme?.background }}>
<Button <Pressable onPress={() => navigation.replace('Loby', { context })}>
title={t('NewGame')} <CircularPanel color={context.themeManager.theme?.boardColor} children={<Text style={{color: context.themeManager.theme.textColor}}>{t('NewGame')}</Text>}/>
onPress={() => navigation.navigate('Loby', { context })}></Button> </Pressable>
</View> </View>
); );
} }

View File

@ -14,7 +14,7 @@ export default function LobyScreen({ navigation, route }: LobyScreenProps) {
const onGameStart = async (message: Object) => { const onGameStart = async (message: Object) => {
const newGame: CommonMancalaGame = message as CommonMancalaGame; const newGame: CommonMancalaGame = message as CommonMancalaGame;
const userKey = await context.userKeyStore.getUserKey(); const userKey = await context.userKeyStore.getUserKey();
navigation.navigate("Game", { context, gameId: newGame.id, userKey }) navigation.replace("Game", { context, gameId: newGame.id, userKey })
} }
useEffect(() => { useEffect(() => {
@ -26,7 +26,7 @@ export default function LobyScreen({ navigation, route }: LobyScreenProps) {
}, []); }, []);
return ( 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> <Text>{t('SearchingOpponent')}</Text>
</View> </View>
); );