Files
SafeQR_Front_End_Mobile/screens/QRScannerScreen.tsx

252 lines
7.2 KiB
TypeScript

import React, { useState, useEffect } from 'react';
import { View, Text, StyleSheet, ActivityIndicator, TouchableOpacity, Alert } from 'react-native';
import { Camera, CameraView, scanFromURLAsync } from 'expo-camera';
import axios from 'axios'; // For URL calls
import { Ionicons } from '@expo/vector-icons'; // For icons
import { useNavigation } from '@react-navigation/native';
import * as ImagePicker from 'expo-image-picker';
import ScannedDataBox from '../components/ScannedDataBox';
import { useDispatch } from 'react-redux';
import { addQRCode } from '../actions/qrCodeActions';
const QRScannerScreen: React.FC = () => {
const navigation = useNavigation(); // call Navigation bar
const [showSplash, setShowSplash] = useState<boolean>(true); // call splash screen
const dispatch = useDispatch();
const [hasPermission, setHasPermission] = useState<boolean | null>(null);
const [scanned, setScanned] = useState<boolean>(false);
const [scannedData, setScannedData] = useState<string>(''); // State for QR scanned Data
const [dataType, setDataType] = useState<string>(''); // State for data type
const [enableTorch, setEnableTorch] = useState<boolean>(false); // State for torch
useEffect(() => {
const initializeApp = async () => {
const { status } = await Camera.requestCameraPermissionsAsync();
setHasPermission(status === 'granted');
setShowSplash(false);
};
initializeApp();
}, []);
const clearScanDataInternal = () => {
setScannedData('');
setScanned(false);
setDataType('');
};
const handlePayload = async (payload: string) => {
setScanned(true);
console.log("Scanning Competed payload is :", payload);
const type = await sendToAPIServer(payload);
const qrCode = {
data: payload,
type,
bookmarked: false,
scanResult: {
secureConnection: true, // Placeholder, replace with actual logic
virusTotalCheck: true, // Placeholder, replace with actual logic
redirects: 0 // Placeholder, replace with actual logic
}
};
setScannedData(payload);
console.log("handlePayload -> payload", payload);
console.log("handlePayload -> type", type);
setDataType(type);
dispatch(addQRCode(qrCode));
};
const sendToAPIServer = async (payload: string): Promise<string> => {
console.log('Sending QR code data to backend:', payload);
try {
const response = await axios.post('http://192.168.10.247:8080/v1/api/qrcodetypes/detect', {
data: payload,
}, {
headers: {
'Content-Type': 'application/json',
},
});
console.log('Response from backend:', response.data);
return response.data;
} catch (error) {
console.error('Error detecting QR code type:', error);
return 'UNKNOWN';
}
};
const toggleTorch = () => {
setEnableTorch((prev) => !prev);
};
const handleTestScan = () => {
handlePayload('TEST123');
};
const readQRFromImage = async () => {
clearScanDataInternal();
console.log("readingQRFromImage");
const result = await ImagePicker.launchImageLibraryAsync({
mediaTypes: ImagePicker.MediaTypeOptions.Images,
allowsEditing: false, // Don't ask user to crop images
quality: 1,
});
if (result && result.assets && result.assets.length > 0 && result.assets[0].uri) { // Ensure the uri is not empty
try {
const scannedResult = await scanFromURLAsync(result.assets[0].uri);
if (scannedResult && scannedResult[0] && scannedResult[0].data) {
handlePayload(scannedResult[0].data);
// Not sure why scannedResult.data is undefined but access as array work, KIV
console.log('readingQRFromImage -> scannedResult[0].data:', scannedResult[0].data);
} else {
setScannedData("No QR Code Found");
setTimeout(() => setScannedData(""), 4000);
}
} catch (error) {
console.error('Error scanning QR code from image:', error);
Alert.alert('Failed to scan QR code from image.');
}
}
};
useEffect(() => {
const unsubscribe = navigation.addListener('focus', () => {
clearScanDataInternal();
});
return unsubscribe;
}, [navigation]);
if (showSplash) {
return (
<View style={styles.splashContainer}>
<ActivityIndicator size="large" color="#ff69b4" />
</View>
);
}
if (hasPermission === null) {
return <Text>Requesting for camera permission</Text>;
}
if (hasPermission === false) {
return <Text>No access to camera</Text>;
}
return (
<View style={styles.container}>
<View style={styles.banner}>
<Text style={styles.headerText}>SafeQR v0.89</Text>
</View>
<Text style={styles.welcomeText}>Welcome to SafeQR code Scanner</Text>
<View style={styles.cameraContainer}>
<CameraView
onBarcodeScanned={scanned ? undefined : ({ data }) => handlePayload(data)}
barcodeScannerSettings={{ barcodeTypes: ['qr', 'pdf417'] }}
style={styles.camera}
enableTorch={enableTorch}
/>
<TouchableOpacity onPress={toggleTorch} style={styles.flashButton}>
<Ionicons name="flashlight" size={24} color="#fff" />
</TouchableOpacity>
<TouchableOpacity onPress={handleTestScan} style={styles.testButton}>
<Ionicons name="bug" size={24} color="#fff" />
</TouchableOpacity>
<TouchableOpacity onPress={readQRFromImage} style={styles.galleryButton}>
<Ionicons name="image" size={24} color="#fff" />
</TouchableOpacity>
</View>
{scannedData !== '' && (
<View style={styles.scannedDataBox}>
<ScannedDataBox data={scannedData} dataType={dataType} clearScanData={clearScanDataInternal} />
</View>
)}
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#f8f0fc',
padding: 20,
},
banner: {
alignItems: 'center',
marginBottom: 20,
},
headerText: {
fontSize: 24,
fontWeight: 'bold',
color: '#ff69b4',
},
splashContainer: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#f8f0fc',
},
cameraContainer: {
height: '60%',
alignItems: 'center',
justifyContent: 'center',
borderRadius: 10,
overflow: 'hidden',
},
camera: {
width: '100%',
height: '100%',
},
flashButton: {
position: 'absolute',
bottom: 20,
left: 100,
width: 50,
height: 50,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#000',
borderRadius: 25,
},
testButton: {
position: 'absolute',
bottom: 1,
alignSelf: 'stretch',
backgroundColor: '#000',
padding: 10,
borderRadius: 5,
},
galleryButton: {
position: 'absolute',
bottom: 20,
right: 100,
width: 50,
height: 50,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#000',
borderRadius: 25,
},
scannedDataBox: {
position: 'absolute',
top: '10%',
left: '5%',
right: '5%',
zIndex: 2,
},
welcomeText: {
textAlign: 'center',
fontSize: 20,
marginVertical: 10,
color: 'black',
},
});
export default QRScannerScreen;