Version 2 : permissions caméra
This commit is contained in:
parent
a9260a1fee
commit
bdfca474cc
4 changed files with 301 additions and 34 deletions
254
app/home.tsx
254
app/home.tsx
|
|
@ -1,43 +1,219 @@
|
|||
import { useState } from 'react';
|
||||
import { Text, TextInput, View } from 'react-native';
|
||||
//npx expo install expo-location expo-camera
|
||||
|
||||
export default function Home() {
|
||||
const users = [
|
||||
"alice",
|
||||
"bob",
|
||||
"charlie"
|
||||
import {
|
||||
CameraView,
|
||||
useCameraPermissions,
|
||||
} from "expo-camera";
|
||||
|
||||
import React, { useRef, useState } from "react";
|
||||
import {
|
||||
ActivityIndicator,
|
||||
Alert,
|
||||
Image,
|
||||
Linking,
|
||||
StyleSheet,
|
||||
Text,
|
||||
TouchableOpacity,
|
||||
View,
|
||||
} from "react-native";
|
||||
|
||||
export default function App() {
|
||||
const cameraRef = useRef(null);
|
||||
|
||||
const [statusText, setStatusText] = useState("Permission non demandée");
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
const [cameraVisible, setCameraVisible] = useState(false);
|
||||
const [photoUri, setPhotoUri] = useState(null);
|
||||
|
||||
const [permission, requestPermission] =
|
||||
useCameraPermissions();
|
||||
|
||||
const openSettings = () => {
|
||||
Linking.openSettings();
|
||||
};
|
||||
|
||||
const openCamera = async () => {
|
||||
try {
|
||||
setLoading(true);
|
||||
setStatusText("Demande de permission caméra...");
|
||||
|
||||
const result = await requestPermission();
|
||||
|
||||
if (!result.granted) {
|
||||
if (result.canAskAgain === false) {
|
||||
Alert.alert(
|
||||
"Permission bloquée",
|
||||
"La caméra doit être activée dans les paramètres.",
|
||||
[
|
||||
{ text: "Annuler", style: "cancel" },
|
||||
{ text: "Paramètres", onPress: openSettings },
|
||||
]
|
||||
|
||||
const variable = true;
|
||||
|
||||
const [nom, setNom] = useState('');
|
||||
|
||||
|
||||
return (
|
||||
<View style={{ flex: 1, padding: 16, gap: 12 }}>
|
||||
{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 }} />
|
||||
|
||||
<Text style={{ fontSize: 18, fontWeight: '600' }}>
|
||||
Saisie + bouton "Valider"
|
||||
</Text>
|
||||
|
||||
<Text>Valeur validée : {nom || '(vide)'}</Text>
|
||||
|
||||
<TextInput
|
||||
value={nom}
|
||||
onChangeText={setNom}
|
||||
placeholder="Taper un nom "
|
||||
style={{ borderWidth: 1, padding: 12, borderRadius: 10 }}
|
||||
autoCapitalize="none"
|
||||
/>
|
||||
|
||||
</View>
|
||||
|
||||
);
|
||||
} else {
|
||||
Alert.alert(
|
||||
"Permission refusée",
|
||||
"Impossible d'utiliser la caméra."
|
||||
);
|
||||
}
|
||||
|
||||
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",
|
||||
"dependencies": {
|
||||
"@expo/vector-icons": "^15.0.3",
|
||||
"@react-native-async-storage/async-storage": "2.2.0",
|
||||
"@react-navigation/bottom-tabs": "^7.4.0",
|
||||
"@react-navigation/elements": "^2.6.3",
|
||||
"@react-navigation/native": "^7.1.8",
|
||||
"expo": "~54.0.33",
|
||||
"expo-camera": "~17.0.10",
|
||||
"expo-constants": "~18.0.13",
|
||||
"expo-font": "~14.0.11",
|
||||
"expo-haptics": "~15.0.8",
|
||||
"expo-image": "~3.0.11",
|
||||
"expo-image-picker": "~17.0.10",
|
||||
"expo-linking": "~8.0.11",
|
||||
"expo-location": "~19.0.8",
|
||||
"expo-router": "~6.0.23",
|
||||
"expo-splash-screen": "~31.0.13",
|
||||
"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": {
|
||||
"version": "0.81.5",
|
||||
"resolved": "https://registry.npmjs.org/@react-native/assets-registry/-/assets-registry-0.81.5.tgz",
|
||||
|
|
@ -6062,6 +6078,26 @@
|
|||
"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": {
|
||||
"version": "18.0.13",
|
||||
"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": {
|
||||
"version": "15.0.8",
|
||||
"resolved": "https://registry.npmjs.org/expo-keep-awake/-/expo-keep-awake-15.0.8.tgz",
|
||||
|
|
@ -6150,6 +6207,15 @@
|
|||
"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": {
|
||||
"version": "3.0.24",
|
||||
"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"
|
||||
}
|
||||
},
|
||||
"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": {
|
||||
"version": "1.2.1",
|
||||
"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==",
|
||||
"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": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
|
||||
|
|
|
|||
|
|
@ -12,15 +12,19 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"@expo/vector-icons": "^15.0.3",
|
||||
"@react-native-async-storage/async-storage": "2.2.0",
|
||||
"@react-navigation/bottom-tabs": "^7.4.0",
|
||||
"@react-navigation/elements": "^2.6.3",
|
||||
"@react-navigation/native": "^7.1.8",
|
||||
"expo": "~54.0.33",
|
||||
"expo-camera": "~17.0.10",
|
||||
"expo-constants": "~18.0.13",
|
||||
"expo-font": "~14.0.11",
|
||||
"expo-haptics": "~15.0.8",
|
||||
"expo-image": "~3.0.11",
|
||||
"expo-image-picker": "~17.0.10",
|
||||
"expo-linking": "~8.0.11",
|
||||
"expo-location": "~19.0.8",
|
||||
"expo-router": "~6.0.23",
|
||||
"expo-splash-screen": "~31.0.13",
|
||||
"expo-status-bar": "~3.0.9",
|
||||
|
|
@ -31,11 +35,11 @@
|
|||
"react-dom": "19.1.0",
|
||||
"react-native": "0.81.5",
|
||||
"react-native-gesture-handler": "~2.28.0",
|
||||
"react-native-worklets": "0.5.1",
|
||||
"react-native-reanimated": "~4.1.1",
|
||||
"react-native-safe-area-context": "~5.6.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": {
|
||||
"@types/react": "~19.1.0",
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"extends": "expo/tsconfig.base",
|
||||
"compilerOptions": {
|
||||
"strict": true,
|
||||
"strict": false,
|
||||
"paths": {
|
||||
"@/*": [
|
||||
"./*"
|
||||
|
|
|
|||
Loading…
Reference in a new issue