Version 2 : permissions caméra
This commit is contained in:
parent
a9260a1fee
commit
bdfca474cc
4 changed files with 301 additions and 34 deletions
238
app/home.tsx
238
app/home.tsx
|
|
@ -1,43 +1,219 @@
|
||||||
import { useState } from 'react';
|
//npx expo install expo-location expo-camera
|
||||||
import { Text, TextInput, View } from 'react-native';
|
|
||||||
|
|
||||||
export default function Home() {
|
import {
|
||||||
const users = [
|
CameraView,
|
||||||
"alice",
|
useCameraPermissions,
|
||||||
"bob",
|
} from "expo-camera";
|
||||||
"charlie"
|
|
||||||
]
|
import React, { useRef, useState } from "react";
|
||||||
|
import {
|
||||||
|
ActivityIndicator,
|
||||||
|
Alert,
|
||||||
|
Image,
|
||||||
|
Linking,
|
||||||
|
StyleSheet,
|
||||||
|
Text,
|
||||||
|
TouchableOpacity,
|
||||||
|
View,
|
||||||
|
} from "react-native";
|
||||||
|
|
||||||
const variable = true;
|
export default function App() {
|
||||||
|
const cameraRef = useRef(null);
|
||||||
|
|
||||||
const [nom, setNom] = useState('');
|
const [statusText, setStatusText] = useState("Permission non demandée");
|
||||||
|
const [loading, setLoading] = useState(false);
|
||||||
|
|
||||||
|
const [cameraVisible, setCameraVisible] = useState(false);
|
||||||
|
const [photoUri, setPhotoUri] = useState(null);
|
||||||
|
|
||||||
return (
|
const [permission, requestPermission] =
|
||||||
<View style={{ flex: 1, padding: 16, gap: 12 }}>
|
useCameraPermissions();
|
||||||
{variable && <Text>Test</Text>}
|
|
||||||
{variable ? <Text>Vrai</Text> : <Text>Faux</Text>}
|
|
||||||
{users.map(user => {
|
|
||||||
return <Text key={user}>{user}</Text>
|
|
||||||
})}
|
|
||||||
|
|
||||||
<View style={{ height: 1, borderWidth: 1 }} />
|
const openSettings = () => {
|
||||||
|
Linking.openSettings();
|
||||||
|
};
|
||||||
|
|
||||||
<Text style={{ fontSize: 18, fontWeight: '600' }}>
|
const openCamera = async () => {
|
||||||
Saisie + bouton "Valider"
|
try {
|
||||||
</Text>
|
setLoading(true);
|
||||||
|
setStatusText("Demande de permission caméra...");
|
||||||
|
|
||||||
<Text>Valeur validée : {nom || '(vide)'}</Text>
|
const result = await requestPermission();
|
||||||
|
|
||||||
<TextInput
|
if (!result.granted) {
|
||||||
value={nom}
|
if (result.canAskAgain === false) {
|
||||||
onChangeText={setNom}
|
Alert.alert(
|
||||||
placeholder="Taper un nom "
|
"Permission bloquée",
|
||||||
style={{ borderWidth: 1, padding: 12, borderRadius: 10 }}
|
"La caméra doit être activée dans les paramètres.",
|
||||||
autoCapitalize="none"
|
[
|
||||||
/>
|
{ text: "Annuler", style: "cancel" },
|
||||||
|
{ text: "Paramètres", onPress: openSettings },
|
||||||
|
]
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
Alert.alert(
|
||||||
|
"Permission refusée",
|
||||||
|
"Impossible d'utiliser la caméra."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
</View>
|
setStatusText("Permission caméra refusée");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
);
|
setPhotoUri(null);
|
||||||
|
setCameraVisible(true);
|
||||||
|
setStatusText("Caméra autorisée");
|
||||||
|
} catch (e) {
|
||||||
|
setStatusText("Erreur lors de la demande caméra");
|
||||||
|
} finally {
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const takePhoto = async () => {
|
||||||
|
try {
|
||||||
|
if (!cameraRef.current) {
|
||||||
|
Alert.alert("Erreur", "La caméra n'est pas encore prête.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setLoading(true);
|
||||||
|
setStatusText("Prise de photo...");
|
||||||
|
|
||||||
|
const photo = await cameraRef.current.takePictureAsync();
|
||||||
|
|
||||||
|
if (!photo || !photo.uri) {
|
||||||
|
Alert.alert("Erreur", "Aucune photo obtenue.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setPhotoUri(photo.uri);
|
||||||
|
setCameraVisible(false);
|
||||||
|
setStatusText("Photo prise");
|
||||||
|
} catch (e) {
|
||||||
|
setStatusText("Erreur lors de la prise de photo");
|
||||||
|
} finally {
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const closeCamera = () => {
|
||||||
|
setCameraVisible(false);
|
||||||
|
setStatusText("Caméra fermée");
|
||||||
|
};
|
||||||
|
|
||||||
|
if (cameraVisible) {
|
||||||
|
return (
|
||||||
|
<View style={styles.cameraContainer}>
|
||||||
|
<CameraView
|
||||||
|
ref={cameraRef}
|
||||||
|
style={styles.camera}
|
||||||
|
facing="back"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<View style={styles.cameraControls}>
|
||||||
|
<TouchableOpacity style={styles.secondaryButton} onPress={closeCamera}>
|
||||||
|
<Text style={styles.buttonText}>Fermer</Text>
|
||||||
|
</TouchableOpacity>
|
||||||
|
|
||||||
|
<TouchableOpacity style={styles.button} onPress={takePhoto}>
|
||||||
|
<Text style={styles.buttonText}>Prendre une photo</Text>
|
||||||
|
</TouchableOpacity>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View style={styles.container}>
|
||||||
|
<Text style={styles.title}>TP permissions Expo</Text>
|
||||||
|
|
||||||
|
<TouchableOpacity style={styles.button} onPress={openCamera}>
|
||||||
|
<Text style={styles.buttonText}>Ouvrir la caméra</Text>
|
||||||
|
</TouchableOpacity>
|
||||||
|
|
||||||
|
{loading ? <ActivityIndicator size="large" /> : null}
|
||||||
|
|
||||||
|
<Text style={styles.status}>{statusText}</Text>
|
||||||
|
|
||||||
|
{photoUri ? (
|
||||||
|
<View style={styles.photoBox}>
|
||||||
|
<Text style={styles.subtitle}>Photo prise :</Text>
|
||||||
|
<Image source={{ uri: photoUri }} style={styles.photo} />
|
||||||
|
</View>
|
||||||
|
) : null}
|
||||||
|
</View>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
container: {
|
||||||
|
flex: 1,
|
||||||
|
justifyContent: "center",
|
||||||
|
padding: 20,
|
||||||
|
backgroundColor: "#fff",
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
fontSize: 24,
|
||||||
|
fontWeight: "bold",
|
||||||
|
marginBottom: 20,
|
||||||
|
textAlign: "center",
|
||||||
|
},
|
||||||
|
subtitle: {
|
||||||
|
fontWeight: "bold",
|
||||||
|
marginBottom: 10,
|
||||||
|
},
|
||||||
|
button: {
|
||||||
|
backgroundColor: "#2563eb",
|
||||||
|
padding: 14,
|
||||||
|
borderRadius: 8,
|
||||||
|
marginBottom: 12,
|
||||||
|
},
|
||||||
|
secondaryButton: {
|
||||||
|
backgroundColor: "#666",
|
||||||
|
padding: 14,
|
||||||
|
borderRadius: 8,
|
||||||
|
marginBottom: 12,
|
||||||
|
},
|
||||||
|
buttonText: {
|
||||||
|
color: "#fff",
|
||||||
|
textAlign: "center",
|
||||||
|
fontWeight: "bold",
|
||||||
|
},
|
||||||
|
status: {
|
||||||
|
textAlign: "center",
|
||||||
|
marginVertical: 20,
|
||||||
|
},
|
||||||
|
box: {
|
||||||
|
padding: 16,
|
||||||
|
borderWidth: 1,
|
||||||
|
borderColor: "#ccc",
|
||||||
|
borderRadius: 8,
|
||||||
|
marginBottom: 20,
|
||||||
|
},
|
||||||
|
photoBox: {
|
||||||
|
marginTop: 10,
|
||||||
|
alignItems: "center",
|
||||||
|
},
|
||||||
|
photo: {
|
||||||
|
width: 250,
|
||||||
|
height: 250,
|
||||||
|
borderRadius: 8,
|
||||||
|
borderWidth: 1,
|
||||||
|
borderColor: "#ccc",
|
||||||
|
},
|
||||||
|
cameraContainer: {
|
||||||
|
flex: 1,
|
||||||
|
backgroundColor: "#000",
|
||||||
|
},
|
||||||
|
camera: {
|
||||||
|
flex: 1,
|
||||||
|
},
|
||||||
|
cameraControls: {
|
||||||
|
position: "absolute",
|
||||||
|
bottom: 40,
|
||||||
|
left: 20,
|
||||||
|
right: 20,
|
||||||
|
},
|
||||||
|
});
|
||||||
87
package-lock.json
generated
87
package-lock.json
generated
|
|
@ -9,15 +9,19 @@
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@expo/vector-icons": "^15.0.3",
|
"@expo/vector-icons": "^15.0.3",
|
||||||
|
"@react-native-async-storage/async-storage": "2.2.0",
|
||||||
"@react-navigation/bottom-tabs": "^7.4.0",
|
"@react-navigation/bottom-tabs": "^7.4.0",
|
||||||
"@react-navigation/elements": "^2.6.3",
|
"@react-navigation/elements": "^2.6.3",
|
||||||
"@react-navigation/native": "^7.1.8",
|
"@react-navigation/native": "^7.1.8",
|
||||||
"expo": "~54.0.33",
|
"expo": "~54.0.33",
|
||||||
|
"expo-camera": "~17.0.10",
|
||||||
"expo-constants": "~18.0.13",
|
"expo-constants": "~18.0.13",
|
||||||
"expo-font": "~14.0.11",
|
"expo-font": "~14.0.11",
|
||||||
"expo-haptics": "~15.0.8",
|
"expo-haptics": "~15.0.8",
|
||||||
"expo-image": "~3.0.11",
|
"expo-image": "~3.0.11",
|
||||||
|
"expo-image-picker": "~17.0.10",
|
||||||
"expo-linking": "~8.0.11",
|
"expo-linking": "~8.0.11",
|
||||||
|
"expo-location": "~19.0.8",
|
||||||
"expo-router": "~6.0.23",
|
"expo-router": "~6.0.23",
|
||||||
"expo-splash-screen": "~31.0.13",
|
"expo-splash-screen": "~31.0.13",
|
||||||
"expo-status-bar": "~3.0.9",
|
"expo-status-bar": "~3.0.9",
|
||||||
|
|
@ -2756,6 +2760,18 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@react-native-async-storage/async-storage": {
|
||||||
|
"version": "2.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@react-native-async-storage/async-storage/-/async-storage-2.2.0.tgz",
|
||||||
|
"integrity": "sha512-gvRvjR5JAaUZF8tv2Kcq/Gbt3JHwbKFYfmb445rhOj6NUMx3qPLixmDx5pZAyb9at1bYvJ4/eTUipU5aki45xw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"merge-options": "^3.0.4"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react-native": "^0.0.0-0 || >=0.65 <1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@react-native/assets-registry": {
|
"node_modules/@react-native/assets-registry": {
|
||||||
"version": "0.81.5",
|
"version": "0.81.5",
|
||||||
"resolved": "https://registry.npmjs.org/@react-native/assets-registry/-/assets-registry-0.81.5.tgz",
|
"resolved": "https://registry.npmjs.org/@react-native/assets-registry/-/assets-registry-0.81.5.tgz",
|
||||||
|
|
@ -6062,6 +6078,26 @@
|
||||||
"react-native": "*"
|
"react-native": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/expo-camera": {
|
||||||
|
"version": "17.0.10",
|
||||||
|
"resolved": "https://registry.npmjs.org/expo-camera/-/expo-camera-17.0.10.tgz",
|
||||||
|
"integrity": "sha512-w1RBw83mAGVk4BPPwNrCZyFop0VLiVSRE3c2V9onWbdFwonpRhzmB4drygG8YOUTl1H3wQvALJHyMPTbgsK1Jg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"invariant": "^2.2.4"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"expo": "*",
|
||||||
|
"react": "*",
|
||||||
|
"react-native": "*",
|
||||||
|
"react-native-web": "*"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"react-native-web": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/expo-constants": {
|
"node_modules/expo-constants": {
|
||||||
"version": "18.0.13",
|
"version": "18.0.13",
|
||||||
"resolved": "https://registry.npmjs.org/expo-constants/-/expo-constants-18.0.13.tgz",
|
"resolved": "https://registry.npmjs.org/expo-constants/-/expo-constants-18.0.13.tgz",
|
||||||
|
|
@ -6126,6 +6162,27 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/expo-image-loader": {
|
||||||
|
"version": "6.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/expo-image-loader/-/expo-image-loader-6.0.0.tgz",
|
||||||
|
"integrity": "sha512-nKs/xnOGw6ACb4g26xceBD57FKLFkSwEUTDXEDF3Gtcu3MqF3ZIYd3YM+sSb1/z9AKV1dYT7rMSGVNgsveXLIQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peerDependencies": {
|
||||||
|
"expo": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/expo-image-picker": {
|
||||||
|
"version": "17.0.10",
|
||||||
|
"resolved": "https://registry.npmjs.org/expo-image-picker/-/expo-image-picker-17.0.10.tgz",
|
||||||
|
"integrity": "sha512-a2xrowp2trmvXyUWgX3O6Q2rZaa2C59AqivKI7+bm+wLvMfTEbZgldLX4rEJJhM8xtmEDTNU+lzjtObwzBRGaw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"expo-image-loader": "~6.0.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"expo": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/expo-keep-awake": {
|
"node_modules/expo-keep-awake": {
|
||||||
"version": "15.0.8",
|
"version": "15.0.8",
|
||||||
"resolved": "https://registry.npmjs.org/expo-keep-awake/-/expo-keep-awake-15.0.8.tgz",
|
"resolved": "https://registry.npmjs.org/expo-keep-awake/-/expo-keep-awake-15.0.8.tgz",
|
||||||
|
|
@ -6150,6 +6207,15 @@
|
||||||
"react-native": "*"
|
"react-native": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/expo-location": {
|
||||||
|
"version": "19.0.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/expo-location/-/expo-location-19.0.8.tgz",
|
||||||
|
"integrity": "sha512-H/FI75VuJ1coodJbbMu82pf+Zjess8X8Xkiv9Bv58ZgPKS/2ztjC1YO1/XMcGz7+s9DrbLuMIw22dFuP4HqneA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peerDependencies": {
|
||||||
|
"expo": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/expo-modules-autolinking": {
|
"node_modules/expo-modules-autolinking": {
|
||||||
"version": "3.0.24",
|
"version": "3.0.24",
|
||||||
"resolved": "https://registry.npmjs.org/expo-modules-autolinking/-/expo-modules-autolinking-3.0.24.tgz",
|
"resolved": "https://registry.npmjs.org/expo-modules-autolinking/-/expo-modules-autolinking-3.0.24.tgz",
|
||||||
|
|
@ -7829,6 +7895,15 @@
|
||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/is-plain-obj": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/is-regex": {
|
"node_modules/is-regex": {
|
||||||
"version": "1.2.1",
|
"version": "1.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz",
|
||||||
|
|
@ -8807,6 +8882,18 @@
|
||||||
"integrity": "sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==",
|
"integrity": "sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/merge-options": {
|
||||||
|
"version": "3.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/merge-options/-/merge-options-3.0.4.tgz",
|
||||||
|
"integrity": "sha512-2Sug1+knBjkaMsMgf1ctR1Ujx+Ayku4EdJN4Z+C2+JzoeF7A3OZ9KM2GY0CpQS51NR61LTurMJrRKPhSs3ZRTQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"is-plain-obj": "^2.1.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/merge-stream": {
|
"node_modules/merge-stream": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
|
||||||
|
|
|
||||||
|
|
@ -12,15 +12,19 @@
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@expo/vector-icons": "^15.0.3",
|
"@expo/vector-icons": "^15.0.3",
|
||||||
|
"@react-native-async-storage/async-storage": "2.2.0",
|
||||||
"@react-navigation/bottom-tabs": "^7.4.0",
|
"@react-navigation/bottom-tabs": "^7.4.0",
|
||||||
"@react-navigation/elements": "^2.6.3",
|
"@react-navigation/elements": "^2.6.3",
|
||||||
"@react-navigation/native": "^7.1.8",
|
"@react-navigation/native": "^7.1.8",
|
||||||
"expo": "~54.0.33",
|
"expo": "~54.0.33",
|
||||||
|
"expo-camera": "~17.0.10",
|
||||||
"expo-constants": "~18.0.13",
|
"expo-constants": "~18.0.13",
|
||||||
"expo-font": "~14.0.11",
|
"expo-font": "~14.0.11",
|
||||||
"expo-haptics": "~15.0.8",
|
"expo-haptics": "~15.0.8",
|
||||||
"expo-image": "~3.0.11",
|
"expo-image": "~3.0.11",
|
||||||
|
"expo-image-picker": "~17.0.10",
|
||||||
"expo-linking": "~8.0.11",
|
"expo-linking": "~8.0.11",
|
||||||
|
"expo-location": "~19.0.8",
|
||||||
"expo-router": "~6.0.23",
|
"expo-router": "~6.0.23",
|
||||||
"expo-splash-screen": "~31.0.13",
|
"expo-splash-screen": "~31.0.13",
|
||||||
"expo-status-bar": "~3.0.9",
|
"expo-status-bar": "~3.0.9",
|
||||||
|
|
@ -31,11 +35,11 @@
|
||||||
"react-dom": "19.1.0",
|
"react-dom": "19.1.0",
|
||||||
"react-native": "0.81.5",
|
"react-native": "0.81.5",
|
||||||
"react-native-gesture-handler": "~2.28.0",
|
"react-native-gesture-handler": "~2.28.0",
|
||||||
"react-native-worklets": "0.5.1",
|
|
||||||
"react-native-reanimated": "~4.1.1",
|
"react-native-reanimated": "~4.1.1",
|
||||||
"react-native-safe-area-context": "~5.6.0",
|
"react-native-safe-area-context": "~5.6.0",
|
||||||
"react-native-screens": "~4.16.0",
|
"react-native-screens": "~4.16.0",
|
||||||
"react-native-web": "~0.21.0"
|
"react-native-web": "~0.21.0",
|
||||||
|
"react-native-worklets": "0.5.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/react": "~19.1.0",
|
"@types/react": "~19.1.0",
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"extends": "expo/tsconfig.base",
|
"extends": "expo/tsconfig.base",
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"strict": true,
|
"strict": false,
|
||||||
"paths": {
|
"paths": {
|
||||||
"@/*": [
|
"@/*": [
|
||||||
"./*"
|
"./*"
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue