feat(mobile): implement "Rejoin Game" functionality and fix storage bugs
This commit is contained in:
parent
8a485e2db3
commit
69664796ce
@ -4,4 +4,10 @@ export class LocalStorage implements Storage {
|
|||||||
getString(key: string): string | undefined {
|
getString(key: string): string | undefined {
|
||||||
return localStorage.getItem(key) as string;
|
return localStorage.getItem(key) as string;
|
||||||
}
|
}
|
||||||
|
setString(key: string, value: string): void {
|
||||||
|
localStorage.setItem(key, value);
|
||||||
|
}
|
||||||
|
deleteString(key: string): void {
|
||||||
|
localStorage.removeItem(key);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -55,6 +55,9 @@ export function GameScreen({ navigation, route }: GameScreenProps) {
|
|||||||
pitAnimator.setUpdatedGame(newGame);
|
pitAnimator.setUpdatedGame(newGame);
|
||||||
setHasOngoingAction(false);
|
setHasOngoingAction(false);
|
||||||
setGameUsersConnectionInfo(newGame.gameUsersConnectionInfo);
|
setGameUsersConnectionInfo(newGame.gameUsersConnectionInfo);
|
||||||
|
if (newGame.mancalaGame.state === 'ended') {
|
||||||
|
context.storage.deleteString('lastGameId');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const isUserOnline = (userId: string) => {
|
const isUserOnline = (userId: string) => {
|
||||||
@ -81,6 +84,7 @@ export function GameScreen({ navigation, route }: GameScreenProps) {
|
|||||||
const userKeyWhoLeave = message;
|
const userKeyWhoLeave = message;
|
||||||
setUserKeyWhoLeave(userKeyWhoLeave);
|
setUserKeyWhoLeave(userKeyWhoLeave);
|
||||||
setHasOngoingAction(false);
|
setHasOngoingAction(false);
|
||||||
|
context.storage.deleteString('lastGameId');
|
||||||
};
|
};
|
||||||
const onUserConnectionChange = (message: any) => {
|
const onUserConnectionChange = (message: any) => {
|
||||||
const gameUsersConnectionInfo = message as GameUsersConnectionInfo;
|
const gameUsersConnectionInfo = message as GameUsersConnectionInfo;
|
||||||
@ -131,6 +135,7 @@ export function GameScreen({ navigation, route }: GameScreenProps) {
|
|||||||
text: t('Yes'),
|
text: t('Yes'),
|
||||||
onPress: () => {
|
onPress: () => {
|
||||||
context.rtmt.sendMessage(channel_leave_game, {});
|
context.rtmt.sendMessage(channel_leave_game, {});
|
||||||
|
context.storage.deleteString('lastGameId');
|
||||||
updateHeaderButton();
|
updateHeaderButton();
|
||||||
},
|
},
|
||||||
style: 'default',
|
style: 'default',
|
||||||
@ -144,6 +149,7 @@ export function GameScreen({ navigation, route }: GameScreenProps) {
|
|||||||
|
|
||||||
const onNewGameClick = () => {
|
const onNewGameClick = () => {
|
||||||
if (Util.checkConnectionAndMaybeAlert(context, t("ConnectionLost"))) return;
|
if (Util.checkConnectionAndMaybeAlert(context, t("ConnectionLost"))) return;
|
||||||
|
context.storage.deleteString('lastGameId');
|
||||||
navigation.replace("Loby", { context })
|
navigation.replace("Loby", { context })
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -193,12 +199,16 @@ export function GameScreen({ navigation, route }: GameScreenProps) {
|
|||||||
setLoadingStateGame(LoadingState.Loading())
|
setLoadingStateGame(LoadingState.Loading())
|
||||||
context.gameStore.get(gameId!!).then((game) => {
|
context.gameStore.get(gameId!!).then((game) => {
|
||||||
if (game) {
|
if (game) {
|
||||||
|
if (game.mancalaGame.state !== 'ended') {
|
||||||
|
context.storage.setString('lastGameId', game.id);
|
||||||
|
}
|
||||||
pitAnimator = new PitAnimator(context.themeManager, updateBoardViewModel);
|
pitAnimator = new PitAnimator(context.themeManager, updateBoardViewModel);
|
||||||
setPitAnimator(pitAnimator);
|
setPitAnimator(pitAnimator);
|
||||||
onGameUpdate(pitAnimator, game);
|
onGameUpdate(pitAnimator, game);
|
||||||
unlistenMessages = listenMessages(game, pitAnimator);
|
unlistenMessages = listenMessages(game, pitAnimator);
|
||||||
setLoadingStateGame(LoadingState.Loaded({ value: game }))
|
setLoadingStateGame(LoadingState.Loaded({ value: game }))
|
||||||
} else {
|
} else {
|
||||||
|
context.storage.deleteString('lastGameId');
|
||||||
setLoadingStateGame(LoadingState.Error({ errorMessage: t('GameNotFound') }))
|
setLoadingStateGame(LoadingState.Error({ errorMessage: t('GameNotFound') }))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -210,6 +220,7 @@ export function GameScreen({ navigation, route }: GameScreenProps) {
|
|||||||
|
|
||||||
const updateHeaderButton = () => {
|
const updateHeaderButton = () => {
|
||||||
const isGameEnded = game?.mancalaGame.state === "ended" || leftPlayer;
|
const isGameEnded = game?.mancalaGame.state === "ended" || leftPlayer;
|
||||||
|
const isError = gameLoadingState.isError();
|
||||||
navigation.setOptions({
|
navigation.setOptions({
|
||||||
headerRight: () => (
|
headerRight: () => (
|
||||||
<View style={{
|
<View style={{
|
||||||
@ -219,13 +230,15 @@ export function GameScreen({ navigation, route }: GameScreenProps) {
|
|||||||
gap: 5
|
gap: 5
|
||||||
}}>
|
}}>
|
||||||
<Pressable onPress={() => {
|
<Pressable onPress={() => {
|
||||||
if (isGameEnded) {
|
if (isError) {
|
||||||
|
navigation.replace("Home", { context });
|
||||||
|
} else if (isGameEnded) {
|
||||||
onNewGameClick();
|
onNewGameClick();
|
||||||
} else {
|
} else {
|
||||||
onLeaveGameClick();
|
onLeaveGameClick();
|
||||||
}
|
}
|
||||||
}}>
|
}}>
|
||||||
<CircularPanel color={context.themeManager.theme?.background} children={<Text style={{ color: context.themeManager.theme.textColor }}>{isGameEnded ? t('NewGame') : t('Leave')}</Text>} />
|
<CircularPanel color={context.themeManager.theme?.background} children={<Text style={{ color: context.themeManager.theme.textColor }}>{isError ? t('Home') : (isGameEnded ? t('NewGame') : t('Leave'))}</Text>} />
|
||||||
</Pressable>
|
</Pressable>
|
||||||
<Pressable onPress={() => {
|
<Pressable onPress={() => {
|
||||||
navigation.push("Help", { context })
|
navigation.push("Help", { context })
|
||||||
@ -240,7 +253,7 @@ export function GameScreen({ navigation, route }: GameScreenProps) {
|
|||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
updateHeaderButton();
|
updateHeaderButton();
|
||||||
}, [navigation, game, userKeyWhoLeave]);
|
}, [navigation, game, userKeyWhoLeave, gameLoadingState]);
|
||||||
|
|
||||||
const textColorOnAppBar = getColorByBrightness(
|
const textColorOnAppBar = getColorByBrightness(
|
||||||
context.themeManager.theme.appBarBgColor,
|
context.themeManager.theme.appBarBgColor,
|
||||||
|
|||||||
@ -11,6 +11,7 @@ export function HomeScreen({ navigation, route }: HomeScreenProps) {
|
|||||||
|
|
||||||
const { context } = route.params;
|
const { context } = route.params;
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
const [lastGameId, setLastGameId] = React.useState<string | undefined>(undefined);
|
||||||
|
|
||||||
const textColorOnAppBar = getColorByBrightness(
|
const textColorOnAppBar = getColorByBrightness(
|
||||||
context.themeManager.theme.appBarBgColor,
|
context.themeManager.theme.appBarBgColor,
|
||||||
@ -32,6 +33,10 @@ export function HomeScreen({ navigation, route }: HomeScreenProps) {
|
|||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
updateHeaderButton();
|
updateHeaderButton();
|
||||||
|
const savedGameId = context.storage.getString('lastGameId');
|
||||||
|
if (savedGameId) {
|
||||||
|
setLastGameId(savedGameId);
|
||||||
|
}
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -39,6 +44,22 @@ export function HomeScreen({ navigation, route }: HomeScreenProps) {
|
|||||||
<Pressable onPress={() => navigation.replace('Loby', { context })}>
|
<Pressable onPress={() => navigation.replace('Loby', { context })}>
|
||||||
<CircularPanel color={context.themeManager.theme?.boardColor} children={<Text style={{ color: context.themeManager.theme.textColor }}>{t('NewGame')}</Text>} />
|
<CircularPanel color={context.themeManager.theme?.boardColor} children={<Text style={{ color: context.themeManager.theme.textColor }}>{t('NewGame')}</Text>} />
|
||||||
</Pressable>
|
</Pressable>
|
||||||
|
{lastGameId && (
|
||||||
|
<>
|
||||||
|
<View style={{ height: 20 }} />
|
||||||
|
<Pressable onPress={async () => {
|
||||||
|
try {
|
||||||
|
const userKey = await context.userKeyStore.getUserKey();
|
||||||
|
navigation.replace('Game', { context, gameId: lastGameId, userKey });
|
||||||
|
} catch (error) {
|
||||||
|
context.storage.deleteString('lastGameId');
|
||||||
|
setLastGameId(undefined);
|
||||||
|
}
|
||||||
|
}}>
|
||||||
|
<CircularPanel color={context.themeManager.theme?.boardColor} children={<Text style={{ color: context.themeManager.theme.textColor }}>{t('RejoinGame')}</Text>} />
|
||||||
|
</Pressable>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,6 +17,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;
|
||||||
|
context.storage.setString('lastGameId', newGame.id);
|
||||||
const userKey = await context.userKeyStore.getUserKey();
|
const userKey = await context.userKeyStore.getUserKey();
|
||||||
navigation.replace("Game", { context, gameId: newGame.id, userKey })
|
navigation.replace("Game", { context, gameId: newGame.id, userKey })
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,4 +8,10 @@ export class LocalStorage implements Storage {
|
|||||||
getString(key: string): string | undefined {
|
getString(key: string): string | undefined {
|
||||||
return storage.getString(key);
|
return storage.getString(key);
|
||||||
}
|
}
|
||||||
|
setString(key: string, value: string): void {
|
||||||
|
storage.set(key, value);
|
||||||
|
}
|
||||||
|
deleteString(key: string): void {
|
||||||
|
storage.remove(key);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -21,7 +21,7 @@ export class GameStoreImpl implements GameStore {
|
|||||||
return game;
|
return game;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// todo check error
|
// todo check error
|
||||||
Promise.resolve(undefined);
|
return undefined;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -36,5 +36,7 @@ export const en = {
|
|||||||
Cancel: "Cancel",
|
Cancel: "Cancel",
|
||||||
Help: "Help",
|
Help: "Help",
|
||||||
WebApp: "Goto WebApp",
|
WebApp: "Goto WebApp",
|
||||||
Privacy: "Open Privacy Policy"
|
Privacy: "Open Privacy Policy",
|
||||||
|
Home: "Home",
|
||||||
|
RejoinGame: "Rejoin Game"
|
||||||
}
|
}
|
||||||
@ -36,5 +36,7 @@ export const tr = {
|
|||||||
Cancel: "İptal",
|
Cancel: "İptal",
|
||||||
Help: "Yardım",
|
Help: "Yardım",
|
||||||
WebApp: "Web Uygulamasına Git",
|
WebApp: "Web Uygulamasına Git",
|
||||||
Privacy: "Gizlilik Politikasını Göster"
|
Privacy: "Gizlilik Politikasını Göster",
|
||||||
|
Home: "Ana Sayfa",
|
||||||
|
RejoinGame: "Oyuna Geri Dön"
|
||||||
};
|
};
|
||||||
@ -1,4 +1,6 @@
|
|||||||
|
|
||||||
export interface Storage {
|
export interface Storage {
|
||||||
getString(key: string): string | undefined;
|
getString(key: string): string | undefined;
|
||||||
|
setString(key: string, value: string): void;
|
||||||
|
deleteString(key: string): void;
|
||||||
}
|
}
|
||||||
Loading…
Reference in New Issue
Block a user