mirror of
https://git.rezel.net/LudoTech/traque.git
synced 2026-02-09 02:10:18 +01:00
Ajout traque-app
This commit is contained in:
33
traque-app/hook/useGame.jsx
Normal file
33
traque-app/hook/useGame.jsx
Normal file
@@ -0,0 +1,33 @@
|
||||
import { useSocket } from "../context/socketContext";
|
||||
import { useTeamConnexion } from "../context/teamConnexionContext";
|
||||
import { useTeamContext } from "../context/teamContext";
|
||||
|
||||
export default function useGame() {
|
||||
const { teamSocket } = useSocket();
|
||||
const { teamId } = useTeamConnexion();
|
||||
const { teamInfos, gameState } = useTeamContext();
|
||||
|
||||
function sendCurrentPosition() {
|
||||
console.log("Reveal position.")
|
||||
teamSocket.emit("send_position");
|
||||
}
|
||||
|
||||
function capture(captureCode) {
|
||||
console.log("Try to capture :", captureCode);
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
const timeout = setTimeout(() => {
|
||||
console.warn("Server did not respond to capture emit.");
|
||||
reject();
|
||||
}, 3000);
|
||||
|
||||
teamSocket.emit("capture", captureCode, (response) => {
|
||||
clearTimeout(timeout);
|
||||
console.log(response.message);
|
||||
resolve(response);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
return {...teamInfos, sendCurrentPosition, capture, teamId, gameState};
|
||||
}
|
||||
34
traque-app/hook/useLocalStorage.jsx
Normal file
34
traque-app/hook/useLocalStorage.jsx
Normal file
@@ -0,0 +1,34 @@
|
||||
import AsyncStorage from '@react-native-async-storage/async-storage';
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
export function useLocalStorage(key, initialValue) {
|
||||
const [storedValue, setStoredValue] = useState(initialValue);
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
useEffect(() => {
|
||||
async function fetchData() {
|
||||
try {
|
||||
const item = await AsyncStorage.getItem(key);
|
||||
setStoredValue(item ? JSON.parse(item) : initialValue);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
setLoading(false);
|
||||
}
|
||||
fetchData();
|
||||
}, []);
|
||||
|
||||
const setValue = async value => {
|
||||
try {
|
||||
setLoading(true);
|
||||
const valueToStore = value instanceof Function ? value(storedValue) : value;
|
||||
setStoredValue(valueToStore);
|
||||
await AsyncStorage.setItem(key, JSON.stringify(valueToStore));
|
||||
setLoading(false);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
return [storedValue, setValue, loading];
|
||||
}
|
||||
80
traque-app/hook/useLocation.jsx
Normal file
80
traque-app/hook/useLocation.jsx
Normal file
@@ -0,0 +1,80 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { Alert } from "react-native";
|
||||
import { defineTask, isTaskRegisteredAsync } from "expo-task-manager";
|
||||
import * as Location from 'expo-location';
|
||||
import { useSocket } from "../context/socketContext";
|
||||
|
||||
export function useLocation(timeInterval, distanceInterval) {
|
||||
const [location, setLocation] = useState(null); // [latitude, longitude]
|
||||
const { teamSocket } = useSocket();
|
||||
const LOCATION_TASK_NAME = "background-location-task";
|
||||
const locationUpdateParameters = {
|
||||
accuracy: Location.Accuracy.High,
|
||||
distanceInterval: distanceInterval, // Update every 10 meters
|
||||
timeInterval: timeInterval, // Minimum interval in ms
|
||||
showsBackgroundLocationIndicator: true, // iOS only
|
||||
pausesUpdatesAutomatically: false, // (iOS) Prevents auto-pausing of location updates
|
||||
foregroundService: {
|
||||
notificationTitle: "Enregistrement de votre position.",
|
||||
notificationBody: "L'application utilise votre position en arrière plan.",
|
||||
notificationColor: "#FF0000", // (Android) Notification icon color
|
||||
},
|
||||
};
|
||||
|
||||
defineTask(LOCATION_TASK_NAME, async ({ data, error }) => {
|
||||
if (error) {
|
||||
console.error(error);
|
||||
return;
|
||||
}
|
||||
if (data) {
|
||||
const { locations } = data;
|
||||
if (locations.length > 0) {
|
||||
const firstLocation = locations[0];
|
||||
const { latitude, longitude } = firstLocation.coords;
|
||||
const new_location = [latitude, longitude];
|
||||
try {
|
||||
setLocation(new_location);
|
||||
} catch (e) {
|
||||
console.warn("setLocation failed (probably in background):", e);
|
||||
}
|
||||
console.log("Sending position :", new_location);
|
||||
teamSocket.emit("update_position", new_location);
|
||||
} else {
|
||||
console.log("No location measured.")
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
getLocationAuthorization();
|
||||
}, []);
|
||||
|
||||
async function getLocationAuthorization() {
|
||||
const { status : statusForeground } = await Location.requestForegroundPermissionsAsync();
|
||||
const { status : statusBackground } = await Location.requestBackgroundPermissionsAsync();
|
||||
if (statusForeground !== "granted" || statusBackground !== "granted") {
|
||||
Alert.alert("Échec", "Activez la localisation en arrière plan dans les paramètres.");
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
async function startLocationTracking() {
|
||||
if (await getLocationAuthorization()) {
|
||||
if (!(await isTaskRegisteredAsync(LOCATION_TASK_NAME))) {
|
||||
await Location.startLocationUpdatesAsync(LOCATION_TASK_NAME, locationUpdateParameters);
|
||||
console.log("Location tracking started.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function stopLocationTracking() {
|
||||
if (await isTaskRegisteredAsync(LOCATION_TASK_NAME)) {
|
||||
await Location.stopLocationUpdatesAsync(LOCATION_TASK_NAME);
|
||||
console.log("Location tracking stopped.")
|
||||
}
|
||||
}
|
||||
|
||||
return [location, getLocationAuthorization, startLocationTracking, stopLocationTracking];
|
||||
}
|
||||
58
traque-app/hook/usePickImage.jsx
Normal file
58
traque-app/hook/usePickImage.jsx
Normal file
@@ -0,0 +1,58 @@
|
||||
import { useState, } from 'react';
|
||||
import { Alert } from 'react-native';
|
||||
import { launchImageLibraryAsync, requestMediaLibraryPermissionsAsync } from 'expo-image-picker';
|
||||
|
||||
export function usePickImage() {
|
||||
const [image, setImage] = useState(null);
|
||||
|
||||
const pickImage = async () => {
|
||||
try {
|
||||
const permissionResult = await requestMediaLibraryPermissionsAsync();
|
||||
|
||||
if (permissionResult.granted === false) {
|
||||
Alert.alert("Permission refusée", "Activez l'accès au stockage ou à la gallerie dans les paramètres.");
|
||||
return;
|
||||
}
|
||||
|
||||
let result = await launchImageLibraryAsync({
|
||||
mediaTypes: ['images'],
|
||||
allowsMultipleSelection: false,
|
||||
allowsEditing: true,
|
||||
aspect: [4, 3],
|
||||
quality: 1,
|
||||
});
|
||||
|
||||
if (!result.canceled && result) {
|
||||
setImage(result.assets[0]);
|
||||
}
|
||||
else {
|
||||
console.log('Image picker cancelled.');
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
console.error('Error picking image;', error);
|
||||
Alert.alert('Erreur', "Une erreur est survenue lors de la sélection d'une image.");
|
||||
}
|
||||
}
|
||||
|
||||
function sendImage(location) {
|
||||
if (image) {
|
||||
let data = new FormData();
|
||||
data.append('file', {
|
||||
uri: image.uri,
|
||||
name: 'photo.jpg',
|
||||
type: 'image/jpeg',
|
||||
});
|
||||
|
||||
fetch(location , {
|
||||
method: 'POST',
|
||||
body: data,
|
||||
headers: {
|
||||
'Content-Type': 'multipart/form-data',
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return {image, pickImage, sendImage};
|
||||
}
|
||||
35
traque-app/hook/useSendDeviceInfo.jsx
Normal file
35
traque-app/hook/useSendDeviceInfo.jsx
Normal file
@@ -0,0 +1,35 @@
|
||||
import { useEffect } from 'react';
|
||||
import DeviceInfo from 'react-native-device-info';
|
||||
import { useSocket } from "../context/socketContext";
|
||||
import { useTeamConnexion } from "../context/teamConnexionContext";
|
||||
|
||||
export default function useSendDeviceInfo() {
|
||||
const batteryUpdateTimeout = 5*60*1000;
|
||||
const { teamSocket } = useSocket();
|
||||
const {loggedIn} = useTeamConnexion();
|
||||
|
||||
useEffect(() => {
|
||||
if (!loggedIn) return;
|
||||
|
||||
const sendInfo = async () => {
|
||||
const brand = DeviceInfo.getBrand();
|
||||
const model = DeviceInfo.getModel();
|
||||
const name = await DeviceInfo.getDeviceName();
|
||||
teamSocket.emit('deviceInfo', {model: brand + " " + model, name: name});
|
||||
};
|
||||
|
||||
const sendBattery = async () => {
|
||||
const level = await DeviceInfo.getBatteryLevel();
|
||||
teamSocket.emit('batteryUpdate', Math.round(level * 100));
|
||||
};
|
||||
|
||||
sendInfo();
|
||||
sendBattery();
|
||||
|
||||
const batteryCheckInterval = setInterval(() => sendBattery(), batteryUpdateTimeout);
|
||||
|
||||
return () => {clearInterval(batteryCheckInterval)};
|
||||
}, [loggedIn]);
|
||||
|
||||
return null;
|
||||
}
|
||||
72
traque-app/hook/useSocketAuth.jsx
Normal file
72
traque-app/hook/useSocketAuth.jsx
Normal file
@@ -0,0 +1,72 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useLocalStorage } from './useLocalStorage';
|
||||
|
||||
const LOGIN_MESSAGE = "login";
|
||||
const LOGOUT_MESSAGE = "logout";
|
||||
|
||||
export function useSocketAuth(socket, passwordName) {
|
||||
const [loggedIn, setLoggedIn] = useState(false);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [waitingForResponse, setWaitingForResponse] = useState(false);
|
||||
const [hasTriedSavedPassword, setHasTriedSavedPassword] = useState(false);
|
||||
const [savedPassword, setSavedPassword, savedPasswordLoading] = useLocalStorage(passwordName, null);
|
||||
|
||||
useEffect(() => {
|
||||
if (!loading && !hasTriedSavedPassword) {
|
||||
console.log("Try to log in with saved password :", savedPassword);
|
||||
setWaitingForResponse(true);
|
||||
|
||||
const timeout = setTimeout(() => {
|
||||
console.warn("Server did not respond to login emit.");
|
||||
setWaitingForResponse(false);
|
||||
}, 3000);
|
||||
|
||||
socket.emit(LOGIN_MESSAGE, savedPassword, (response) => {
|
||||
clearTimeout(timeout);
|
||||
console.log(response.message);
|
||||
setLoggedIn(response.isLoggedIn);
|
||||
setWaitingForResponse(false);
|
||||
});
|
||||
setHasTriedSavedPassword(true);
|
||||
}
|
||||
}, [loading]);
|
||||
|
||||
function login(password) {
|
||||
console.log("Try to log in with :", password);
|
||||
setSavedPassword(password);
|
||||
setWaitingForResponse(true);
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
const timeout = setTimeout(() => {
|
||||
console.warn("Server did not respond to login emit.");
|
||||
setWaitingForResponse(false);
|
||||
reject();
|
||||
}, 3000);
|
||||
|
||||
socket.emit(LOGIN_MESSAGE, password, (response) => {
|
||||
clearTimeout(timeout);
|
||||
console.log(response.message);
|
||||
setLoggedIn(response.isLoggedIn);
|
||||
setWaitingForResponse(false);
|
||||
resolve(response);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function logout() {
|
||||
console.log("Logout");
|
||||
setSavedPassword(null);
|
||||
setLoggedIn(false);
|
||||
socket.emit(LOGOUT_MESSAGE);
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if(!waitingForResponse && !savedPasswordLoading) {
|
||||
setLoading(false);
|
||||
} else {
|
||||
setLoading(true);
|
||||
}
|
||||
}, [waitingForResponse, savedPasswordLoading]);
|
||||
|
||||
return {login, logout, password: savedPassword, loggedIn, loading};
|
||||
}
|
||||
10
traque-app/hook/useSocketListener.jsx
Normal file
10
traque-app/hook/useSocketListener.jsx
Normal file
@@ -0,0 +1,10 @@
|
||||
import { useEffect } from "react";
|
||||
|
||||
export function useSocketListener(socket, event, callback) {
|
||||
useEffect(() => {
|
||||
socket.on(event,callback);
|
||||
return () => {
|
||||
socket.off(event, callback);
|
||||
}
|
||||
}, []);
|
||||
}
|
||||
21
traque-app/hook/useTimeDifference.jsx
Normal file
21
traque-app/hook/useTimeDifference.jsx
Normal file
@@ -0,0 +1,21 @@
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
export function useTimeDifference(refTime, timeout) {
|
||||
// If refTime is in the past, time will be positive
|
||||
// If refTime is in the future, time will be negative
|
||||
// The time is updated every timeout milliseconds
|
||||
const [time, setTime] = useState(0);
|
||||
|
||||
useEffect(() => {
|
||||
const updateTime = () => {
|
||||
setTime(Math.floor((Date.now() - refTime) / 1000));
|
||||
};
|
||||
|
||||
updateTime();
|
||||
const interval = setInterval(updateTime, timeout);
|
||||
|
||||
return () => clearInterval(interval);
|
||||
}, [refTime]);
|
||||
|
||||
return [time];
|
||||
}
|
||||
Reference in New Issue
Block a user