Working EN traduction + wait page + permission page

This commit is contained in:
Sebastien Riviere
2026-02-21 02:46:58 +01:00
parent 76ee9674de
commit 28e81894ce
19 changed files with 299 additions and 91 deletions

View File

@@ -1,7 +1,39 @@
import { Text } from 'react-native';
//React
import { StyleSheet, Text, View, Image } from 'react-native';
import { useTranslation } from 'react-i18next';
const LocationPermission = () => {
return <Text>{"Veuillez activer la géolocalisation en arrière plan dans les paramètres, puis relancez l'application."}</Text>;
const { t } = useTranslation();
return (<>
<View style={styles.container}>
<Image style={styles.image} source={require("@/assets/images/placement.png")} />
<Text style={styles.title}>{t("location-permission.title")}</Text>
<Text style={styles.subtitle}>{t("location-permission.subtitle")}</Text>
</View>
</>);
};
export default LocationPermission;
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: "center",
justifyContent: "center",
padding: 20,
gap: 20
},
image: {
width: 150,
height: 150,
marginTop: -100,
},
title: {
fontSize: 20,
fontWeight: "bold",
},
subtitle: {
fontSize: 15,
},
});

View File

@@ -1,6 +1,6 @@
// React
import { useState } from 'react';
import { ScrollView, View, Text, StyleSheet, Image, Alert, TouchableHighlight } from 'react-native';
import { Keyboard, ScrollView, View, Text, StyleSheet, Image, Alert, TouchableHighlight } from 'react-native';
import { useTranslation } from 'react-i18next';
// Components
import { TouchableImage } from '@/components/common/Image';
@@ -28,7 +28,9 @@ const Login = () => {
const regex = /^\d{6}$/;
if (!regex.test(teamId)) {
setTimeout(() => Alert.alert(t("error.title"), t("error.invalid_team_id")), 100);
Keyboard.dismiss();
Alert.alert(t("error.default.title"), t("error.default.invalid_team_id"));
setIsSubmitting(false);
return;
}
@@ -39,10 +41,12 @@ const Login = () => {
uploadTeamImage(teamId, image?.uri);
setTeamId("");
} else {
setTimeout(() => Alert.alert(t("error.title"), t("error.unknown_team_id")), 100);
Keyboard.dismiss();
Alert.alert(t("error.default.title"), t("error.default.unknown_team_id"));
}
} catch (error) {
setTimeout(() => Alert.alert(t("error.title"), t("error.server_connection")), 100);
Keyboard.dismiss();
Alert.alert(t("error.default.title"), t("error.default.server_connection"));
} finally {
setIsSubmitting(false);
}
@@ -53,20 +57,20 @@ const Login = () => {
<View style={styles.transitionContainer}>
<View style={styles.subContainer}>
<Image style={styles.logoImage} source={require('@/assets/images/logo/logo_traque.png')}/>
<Text style={styles.logoText}>{t("index.header.title")}</Text>
<Text style={styles.logoText}>{t("login.header.title")}</Text>
</View>
<View style={styles.subContainer}>
<CustomTextInput value={teamId} inputMode="numeric" placeholder={t("index.form.team_id_input")} style={styles.input} onChangeText={setTeamId}/>
<CustomTextInput value={teamId} inputMode="numeric" placeholder={t("login.form.team_id_input")} style={styles.input} onChangeText={setTeamId}/>
</View>
<View style={styles.subContainer}>
<Text style={{fontSize: 15}}>{t("index.form.image_label")}</Text>
<Text style={{fontSize: 13, marginBottom: 3}}>{t("index.form.image_sublabel")}</Text>
<Text style={{fontSize: 15}}>{t("login.form.image_label")}</Text>
<Text style={{fontSize: 13, marginBottom: 3}}>{t("login.form.image_sublabel")}</Text>
<TouchableImage source={image ? {uri: image.uri} : require('@/assets/images/missing_image.jpg')} onPress={pickImage}/>
</View>
<View style={styles.subContainer}>
<View style={styles.buttonContainer}>
<TouchableHighlight style={styles.button} onPress={handleSubmit}>
<Text style={styles.buttonLabel}>{isSubmitting ? "..." : t("index.form.validate_button")}</Text>
<Text style={styles.buttonLabel}>{isSubmitting ? "..." : t("login.form.validate_button")}</Text>
</TouchableHighlight>
</View>
</View>

View File

@@ -35,8 +35,8 @@ const Play = () => {
<Header/>
<Show when={userState == USER_STATE.PLAYING}>
<View style={styles.infoContainer}>
<TimerMMSS style={{width: "50%"}} title={t("interface.zone_reduction_label")} date={nextZoneDate} />
<TimerMMSS style={{width: "50%"}} title={t("interface.send_position_label")} date={locationSendDeadline} />
<TimerMMSS style={{width: "50%"}} title={t("play.info.zone_reduction_label")} date={nextZoneDate} />
<TimerMMSS style={{width: "50%"}} title={t("play.info.send_position_label")} date={locationSendDeadline} />
</View>
</Show>
</View>
@@ -49,8 +49,8 @@ const Play = () => {
<GameZone/>
</Show>
<Show when={userState == USER_STATE.PLAYING && !hasHandicap}>
<PositionMarker position={lastSentLocation} color={"grey"} onPress={() => Alert.alert(t("interface.map.previous_marker_title"), t("interface.map.previous_marker_description"))} />
<PositionMarker position={enemyLocation} color={"red"} onPress={() => Alert.alert(t("interface.map.enemy_marker_title"), t("interface.map.enemy_marker_description"))} />
<PositionMarker position={lastSentLocation} color={"grey"} onPress={() => Alert.alert(t("play.map.previous_marker_title"), t("play.map.previous_marker_description"))} />
<PositionMarker position={enemyLocation} color={"red"} onPress={() => Alert.alert(t("play.map.enemy_marker_title"), t("play.map.enemy_marker_description"))} />
</Show>
</Map>
<LinearGradient colors={['rgba(0,0,0,0.3)', 'rgba(0,0,0,0)']} style={styles.gradient}/>

View File

@@ -1,16 +1,35 @@
// React
import { View, Text, StyleSheet } from 'react-native';
import { View, Text, StyleSheet, Image } from 'react-native';
import { useTranslation } from 'react-i18next';
// Components
import { Header } from '@/components/game/Header';
// Constants
import { COLORS } from '@/constants';
const Wait = () => {
const { t } = useTranslation();
return (
<View style={styles.globalContainer}>
<View style={styles.topContainer}>
<Header/>
<Text>Veuillez patienter, la partie va bientôt commencer !</Text>
<Header/>
<View style={styles.rulesContainer}>
<Text style={styles.title}>{t("wait.title")}</Text>
<View style={styles.section}>
<Image style={styles.image} source={require("@/assets/images/flag.png")} />
<Text style={styles.description}>{t("wait.placement_rule")}</Text>
</View>
<View style={styles.section}>
<Text style={styles.description}>{t("wait.capture_rule")}</Text>
<Image style={styles.image} source={require("@/assets/images/target/black.png")} />
</View>
<View style={styles.section}>
<Image style={styles.image} source={require("@/assets/images/running.png")} />
<Text style={styles.description}>{t("wait.zone_rule")}</Text>
</View>
<View style={styles.section}>
<Text style={styles.description}>{t("wait.team_rule")}</Text>
<Image style={styles.image} source={require("@/assets/images/team.png")} />
</View>
</View>
</View>
);
@@ -22,10 +41,35 @@ const styles = StyleSheet.create({
globalContainer: {
backgroundColor: COLORS.background,
flex: 1,
padding: 20,
},
topContainer: {
width: '100%',
rulesContainer: {
flex: 1,
alignItems: 'center',
padding: 15,
gap: 30
},
title: {
backgroundColor: "white",
textAlign: 'center',
fontSize: 30,
fontWeight: "bold",
borderWidth: 2,
borderRadius: 10,
padding: 10,
},
section: {
width: '100%',
flexDirection: "row",
alignItems: "center",
justifyContent: "center",
gap: 20,
},
image: {
width: 100,
height: 100,
},
description: {
flex: 1,
}
});

View File

@@ -1,17 +1,22 @@
// React
import { useEffect } from 'react';
import { View, StyleSheet } from 'react-native';
import { useTranslation } from 'react-i18next';
// Expo
import { Slot, useRouter, usePathname } from 'expo-router';
// Components
import { IconButton } from '@/components/common/IconButton';
// Contexts
import { AuthProvider } from "@/contexts/authContext";
import { TeamProvider } from "@/contexts/teamContext";
// Hook
import { useUserState } from '@/hooks/useUserState';
// Services
import { startLocationTracking , stopLocationTracking } from '@/services/tasks/backgroundLocation';
// Constants
import { USER_STATE } from '@/constants';
// Traduction
import '@/i18n/config';
import { useUserState } from '@/hooks/useUserState';
const NavigationManager = () => {
const router = useRouter();
@@ -72,15 +77,43 @@ const NavigationManager = () => {
return null;
};
const Language = () => {
const { i18n } = useTranslation();
const toggleLanguage = () => {
i18n.changeLanguage(i18n.language === 'fr' ? 'en' : 'fr');
};
return (
<View style={styles.languageButton}>
<IconButton source={require('@/assets/images/language.png')} onPress={toggleLanguage} />
</View>
);
};
const RootLayout = () => {
return (
<AuthProvider>
<TeamProvider>
<Slot/>
<NavigationManager/>
<Language/>
</TeamProvider>
</AuthProvider>
);
};
export default RootLayout;
const styles = StyleSheet.create({
languageButton: {
position: 'absolute',
top: 0,
right: 0,
backgroundColor: "rgb(126, 182, 199)",
borderBottomLeftRadius: 20,
padding: 5,
justifyContent: 'center',
alignItems: 'center',
}
});