2026-05-07 10:55:15 +00:00
|
|
|
//npx expo install expo-location expo-camera
|
2026-02-18 18:36:17 +00:00
|
|
|
|
2026-05-07 10:55:15 +00:00
|
|
|
import {
|
|
|
|
|
CameraView,
|
|
|
|
|
useCameraPermissions,
|
|
|
|
|
} from "expo-camera";
|
|
|
|
|
|
|
|
|
|
import React, { useRef, useState } from "react";
|
|
|
|
|
import {
|
|
|
|
|
ActivityIndicator,
|
|
|
|
|
Alert,
|
|
|
|
|
Image,
|
|
|
|
|
Linking,
|
|
|
|
|
StyleSheet,
|
|
|
|
|
Text,
|
|
|
|
|
TouchableOpacity,
|
|
|
|
|
View,
|
|
|
|
|
} from "react-native";
|
2026-02-18 18:36:17 +00:00
|
|
|
|
2026-05-07 10:55:15 +00:00
|
|
|
export default function App() {
|
|
|
|
|
const cameraRef = useRef(null);
|
2026-02-18 18:36:17 +00:00
|
|
|
|
2026-05-07 10:55:15 +00:00
|
|
|
const [statusText, setStatusText] = useState("Permission non demandée");
|
|
|
|
|
const [loading, setLoading] = useState(false);
|
2026-02-18 18:36:17 +00:00
|
|
|
|
2026-05-07 10:55:15 +00:00
|
|
|
const [cameraVisible, setCameraVisible] = useState(false);
|
|
|
|
|
const [photoUri, setPhotoUri] = useState(null);
|
2026-02-18 18:36:17 +00:00
|
|
|
|
2026-05-07 10:55:15 +00:00
|
|
|
const [permission, requestPermission] =
|
|
|
|
|
useCameraPermissions();
|
2026-02-18 18:36:17 +00:00
|
|
|
|
2026-05-07 10:55:15 +00:00
|
|
|
const openSettings = () => {
|
|
|
|
|
Linking.openSettings();
|
|
|
|
|
};
|
2026-02-18 18:36:17 +00:00
|
|
|
|
2026-05-07 10:55:15 +00:00
|
|
|
const openCamera = async () => {
|
|
|
|
|
try {
|
|
|
|
|
setLoading(true);
|
|
|
|
|
setStatusText("Demande de permission caméra...");
|
2026-02-18 18:36:17 +00:00
|
|
|
|
2026-05-07 10:55:15 +00:00
|
|
|
const result = await requestPermission();
|
2026-02-18 18:36:17 +00:00
|
|
|
|
2026-05-07 10:55:15 +00:00
|
|
|
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 },
|
|
|
|
|
]
|
|
|
|
|
);
|
|
|
|
|
} else {
|
|
|
|
|
Alert.alert(
|
|
|
|
|
"Permission refusée",
|
|
|
|
|
"Impossible d'utiliser la caméra."
|
|
|
|
|
);
|
|
|
|
|
}
|
2026-02-18 18:36:17 +00:00
|
|
|
|
2026-05-07 10:55:15 +00:00
|
|
|
setStatusText("Permission caméra refusée");
|
|
|
|
|
return;
|
|
|
|
|
}
|
2026-02-18 18:36:17 +00:00
|
|
|
|
2026-05-07 10:55:15 +00:00
|
|
|
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>
|
|
|
|
|
);
|
2026-02-18 18:36:17 +00:00
|
|
|
}
|
2026-05-07 10:55:15 +00:00
|
|
|
|
|
|
|
|
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,
|
|
|
|
|
},
|
|
|
|
|
});
|