diff --git a/client/app/(tabs)/settings.tsx b/client/app/(tabs)/settings.tsx index 0335a7c..b38ef20 100644 --- a/client/app/(tabs)/settings.tsx +++ b/client/app/(tabs)/settings.tsx @@ -1,10 +1,12 @@ import { useGameRepairMutation, useGameResetMutation, useGameStartMutation, useGameStopMutation, useGameSwitchPlayerMutation } from '@/hooks/mutations/useGameMutation' import { useAuth } from '@/hooks/useAuth' -import { useGame, useUpdateGameState } from '@/hooks/useGame' +import { useGame, useSetLocationAccuracy, useUpdateGameState } from '@/hooks/useGame' import { useQueryClient } from '@tanstack/react-query' import { useRouter } from 'expo-router' import { useState } from 'react' -import { Button, Dialog, FAB, List, MD3Colors, Portal, Snackbar, Surface, Text } from 'react-native-paper' +import { Button, Dialog, List, MD3Colors, Portal, Snackbar, Surface, Text } from 'react-native-paper' +import { Dropdown } from 'react-native-paper-dropdown' +import { Accuracy } from 'expo-location' export default function HistoryScreen() { const [successVisible, setSuccessVisible] = useState(false) @@ -17,6 +19,17 @@ export default function HistoryScreen() { const auth = useAuth() const game = useGame() const updateGameState = useUpdateGameState() + const setLocationAccuracy = useSetLocationAccuracy() + + const accuracyArrayList = [ + { value: Accuracy.BestForNavigation.toString(), label: "Navigation" }, + { value: Accuracy.Highest.toString(), label: "Plus haute" }, + { value: Accuracy.High.toString(), label: "Haute" }, + { value: Accuracy.Balanced.toString(), label: "Équilibrée" }, + { value: Accuracy.Low.toString(), label: "Basse" }, + { value: Accuracy.Lowest.toString(), label: "Plus basse" }, + { value: 'null', label: "Désactivée" }, + ] const gameStartMutation = useGameStartMutation({ auth, @@ -112,6 +125,11 @@ export default function HistoryScreen() { description={auth.loggedIn ? "Vous êtes déjà connecté⋅e" : "Vous n'êtes pas connecté⋅e"} right={() => } onPress={() => router.navigate('/login')} /> + setLocationAccuracy(!value || value == 'null' ? null : +value)} />} /> useAppSelector((state) => state.game) +export const useSettings = () => useAppSelector((state) => state.game.settings) export const useSetPlayerId = () => { const dispath = useAppDispatch() return (playerId: number) => dispath(setPlayerId(playerId)) @@ -22,3 +24,7 @@ export const useUpdatePenalty = () => { const dispatch = useAppDispatch() return (penalty: PenaltyPayload) => dispatch(updatePenalty(penalty)) } +export const useSetLocationAccuracy = () => { + const dispatch = useAppDispatch() + return (accuracy: Accuracy | null) => dispatch(setLocationAccuracy(accuracy)) +} diff --git a/client/package-lock.json b/client/package-lock.json index f68618a..bf4005f 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -1,12 +1,12 @@ { "name": "traintrape-moi-client", - "version": "1.0.0", + "version": "1.0.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "traintrape-moi-client", - "version": "1.0.0", + "version": "1.0.1", "dependencies": { "@dev-plugins/react-navigation": "^0.1.0", "@dev-plugins/react-query": "^0.1.0", @@ -47,6 +47,7 @@ "react-native": "0.76.3", "react-native-gesture-handler": "~2.20.2", "react-native-paper": "^5.12.5", + "react-native-paper-dropdown": "^2.3.1", "react-native-reanimated": "~3.16.1", "react-native-safe-area-context": "~4.12.0", "react-native-screens": "~4.1.0", @@ -13631,6 +13632,23 @@ "react-native-vector-icons": "*" } }, + "node_modules/react-native-paper-dropdown": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/react-native-paper-dropdown/-/react-native-paper-dropdown-2.3.1.tgz", + "integrity": "sha512-IvcHTucAV5+fiX2IVMiVdBDKT6KHxycW0o9QzZe7bpmeZWmuCajHDnwG3OSBGlXhUxrrM3TC0/HJZHwORWGgQg==", + "license": "MIT", + "workspaces": [ + "example" + ], + "dependencies": { + "react-native-paper": "^5.12.3" + }, + "peerDependencies": { + "react": "*", + "react-native": "*", + "react-native-paper": "*" + } + }, "node_modules/react-native-paper/node_modules/color": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz", diff --git a/client/package.json b/client/package.json index 72b0e30..332ef17 100644 --- a/client/package.json +++ b/client/package.json @@ -53,6 +53,7 @@ "react-native": "0.76.3", "react-native-gesture-handler": "~2.20.2", "react-native-paper": "^5.12.5", + "react-native-paper-dropdown": "^2.3.1", "react-native-reanimated": "~3.16.1", "react-native-safe-area-context": "~4.12.0", "react-native-screens": "~4.1.0", diff --git a/client/utils/features/game/gameSlice.ts b/client/utils/features/game/gameSlice.ts index 9ef7205..2fb443b 100644 --- a/client/utils/features/game/gameSlice.ts +++ b/client/utils/features/game/gameSlice.ts @@ -1,4 +1,5 @@ import { createSlice, PayloadAction } from '@reduxjs/toolkit' +import { Accuracy } from 'expo-location' export interface RunPayload { id: number @@ -37,6 +38,11 @@ export interface GameState { chaseFreeTime: number | null // date penaltyStart: number | null // date penaltyEnd: number | null //date + settings: Settings +} + +export interface Settings { + locationAccuracy: Accuracy | null } const initialState: GameState = { @@ -49,6 +55,9 @@ const initialState: GameState = { chaseFreeTime: null, penaltyStart: null, penaltyEnd: null, + settings: { + locationAccuracy: Accuracy.Highest, + } } export const gameSlice = createSlice({ @@ -77,10 +86,13 @@ export const gameSlice = createSlice({ updatePenalty: (state, action: PayloadAction) => { state.penaltyStart = action.payload.penaltyStart state.penaltyEnd = action.payload.penaltyEnd + }, + setLocationAccuracy: (state, action: PayloadAction) => { + state.settings.locationAccuracy = action.payload } }, }) -export const { setPlayerId, updateMoney, updateActiveChallengeId, updateGameState, updatePenalty } = gameSlice.actions +export const { setLocationAccuracy, setPlayerId, updateMoney, updateActiveChallengeId, updateGameState, updatePenalty } = gameSlice.actions export default gameSlice.reducer diff --git a/client/utils/geolocation.ts b/client/utils/geolocation.ts index f841aad..8cb198d 100644 --- a/client/utils/geolocation.ts +++ b/client/utils/geolocation.ts @@ -5,9 +5,11 @@ import { PlayerLocation, setLastLocation } from './features/location/locationSli import store from './store' import { useEffect } from 'react' import { socket } from './socket' -import { Constants } from '@/constants/Constants' +import { useSettings } from '@/hooks/useGame' +import { useAuth } from '@/hooks/useAuth' +import { isAuthValid } from './features/auth/authSlice' -const LOCATION_TASK = "fetch-geolocation" +const LOCATION_TASK = "TRAINTRAPE_MOI_GEOLOCATION" TaskManager.defineTask(LOCATION_TASK, async ({ data, error }: any) => { if (error) { @@ -33,9 +35,12 @@ TaskManager.defineTask(LOCATION_TASK, async ({ data, error }: any) => { } }) -export async function startGeolocationService(): Promise void)> { +export async function startGeolocationService(locationAccuracy: Location.Accuracy | null): Promise void)> { if (Platform.OS !== "web" && await Location.hasStartedLocationUpdatesAsync(LOCATION_TASK)) - return async () => await Location.stopLocationUpdatesAsync(LOCATION_TASK) + await Location.stopLocationUpdatesAsync(LOCATION_TASK) + + if (locationAccuracy === null) + return await Location.enableNetworkProviderAsync().catch(error => alert(error)) @@ -49,9 +54,9 @@ export async function startGeolocationService(): Promise void)> { if (Platform.OS !== "web") { await Location.startLocationUpdatesAsync(LOCATION_TASK, { - accuracy: Constants.LOCATION_ACCURACY, + accuracy: locationAccuracy, activityType: Location.ActivityType.OtherNavigation, - deferredUpdatesInterval: 1000, + distanceInterval: 10, timeInterval: 1000, foregroundService: { killServiceOnDestroy: false, @@ -63,13 +68,19 @@ export async function startGeolocationService(): Promise void)> { return async () => await Location.stopLocationUpdatesAsync(LOCATION_TASK) } else { - const locationSubscription = await Location.watchPositionAsync({ accuracy: Constants.LOCATION_ACCURACY }, location_nouveau => store.dispatch(setLastLocation(location_nouveau))) + const locationSubscription = await Location.watchPositionAsync({ accuracy: locationAccuracy }, location_nouveau => store.dispatch(setLastLocation(location_nouveau))) return locationSubscription.remove } } -export const useStartGeolocationServiceEffect = () => useEffect(() => { - let cleanup: void | (() => void) = () => {} - startGeolocationService().then(result => cleanup = result) - return cleanup -}, []) +export const useStartGeolocationServiceEffect = () => { + const auth = useAuth() + const settings = useSettings() + return useEffect(() => { + if (!isAuthValid(auth)) + return + let cleanup: void | (() => void) = () => {} + startGeolocationService(settings.locationAccuracy).then(result => cleanup = result) + return cleanup + }, [auth, settings.locationAccuracy]) +}