BlueWallet/screen/send/ScanQRCode.js

193 lines
6.0 KiB
JavaScript
Raw Normal View History

2019-09-21 19:37:37 +02:00
/* global alert */
2019-12-28 01:53:34 +01:00
import React, { useEffect, useState } from 'react';
import { Image, View, TouchableOpacity, Platform } from 'react-native';
2019-05-02 22:33:03 +02:00
import { RNCamera } from 'react-native-camera';
2019-09-21 19:37:37 +02:00
import { Icon } from 'react-native-elements';
import ImagePicker from 'react-native-image-picker';
2019-12-28 01:53:34 +01:00
import PropTypes from 'prop-types';
import { useNavigationParam, useNavigation } from 'react-navigation-hooks';
2020-01-01 04:31:04 +01:00
import DocumentPicker from 'react-native-document-picker';
import RNFS from 'react-native-fs';
2019-09-21 19:37:37 +02:00
const LocalQRCode = require('@remobile/react-native-qrcode-local-image');
const createHash = require('create-hash');
2018-01-30 23:42:38 +01:00
2019-12-28 01:53:34 +01:00
const ScanQRCode = ({
2020-04-02 18:47:13 +02:00
// eslint-disable-next-line react-hooks/rules-of-hooks
2019-12-28 01:53:34 +01:00
onBarScanned = useNavigationParam('onBarScanned'),
cameraPreviewIsPaused = false,
showCloseButton = true,
2020-04-02 18:47:13 +02:00
// eslint-disable-next-line react-hooks/rules-of-hooks
2020-01-01 04:31:04 +01:00
showFileImportButton = useNavigationParam('showFileImportButton') || false,
2020-04-02 18:47:13 +02:00
// eslint-disable-next-line react-hooks/rules-of-hooks
2019-12-28 01:53:34 +01:00
launchedBy = useNavigationParam('launchedBy'),
}) => {
if (!launchedBy || !onBarScanned) console.warn('Necessary params missing');
2019-12-28 01:53:34 +01:00
const [isLoading, setIsLoading] = useState(false);
const { navigate, goBack } = useNavigation();
2018-05-12 22:27:34 +02:00
const scannedCache = {};
const HashIt = function(s) {
return createHash('sha256')
.update(s)
.digest()
.toString('hex');
};
2019-12-28 01:53:34 +01:00
const onBarCodeRead = ret => {
const h = HashIt(ret.data);
if (scannedCache[h]) {
// this QR was already scanned by this ScanQRCode, lets prevent firing duplicate callbacks
return;
}
scannedCache[h] = +new Date();
2019-12-28 01:53:34 +01:00
if (!isLoading && !cameraPreviewIsPaused) {
setIsLoading(true);
try {
if (showCloseButton && launchedBy) {
navigate(launchedBy);
}
2020-01-01 04:31:04 +01:00
if (ret.additionalProperties) {
onBarScanned(ret.data, ret.additionalProperties);
} else {
onBarScanned(ret.data);
}
2019-12-28 01:53:34 +01:00
} catch (e) {
console.log(e);
}
}
setIsLoading(false);
};
2018-01-30 23:42:38 +01:00
2020-01-01 04:31:04 +01:00
const showFilePicker = async () => {
setIsLoading(true);
try {
const res = await DocumentPicker.pick();
const file = await RNFS.readFile(res.uri);
const fileParsed = JSON.parse(file);
if (fileParsed.keystore.xpub) {
2020-01-02 21:54:34 +01:00
let masterFingerprint;
if (fileParsed.keystore.ckcc_xfp) {
2020-01-03 05:02:41 +01:00
masterFingerprint = Number(fileParsed.keystore.ckcc_xfp);
2020-01-02 21:54:34 +01:00
}
onBarCodeRead({ data: fileParsed.keystore.xpub, additionalProperties: { masterFingerprint, label: fileParsed.keystore.label } });
2020-01-01 04:31:04 +01:00
} else {
throw new Error();
}
} catch (err) {
if (!DocumentPicker.isCancel(err)) {
alert('The selected file does not contain a wallet that can be imported.');
}
setIsLoading(false);
}
setIsLoading(false);
};
2018-01-30 23:42:38 +01:00
2019-12-28 01:53:34 +01:00
useEffect(() => {}, [cameraPreviewIsPaused]);
2018-01-30 23:42:38 +01:00
2019-12-28 01:53:34 +01:00
return (
<View style={{ flex: 1, backgroundColor: '#000000' }}>
{!cameraPreviewIsPaused && !isLoading && (
2019-05-02 22:33:03 +02:00
<RNCamera
captureAudio={false}
androidCameraPermissionOptions={{
title: 'Permission to use camera',
message: 'We need your permission to use your camera',
buttonPositive: 'OK',
buttonNegative: 'Cancel',
}}
2019-12-28 01:53:34 +01:00
style={{ flex: 1, justifyContent: 'space-between', backgroundColor: '#000000' }}
onBarCodeRead={onBarCodeRead}
2019-05-02 22:33:03 +02:00
barCodeTypes={[RNCamera.Constants.BarCodeType.qr]}
/>
2019-12-28 01:53:34 +01:00
)}
{showCloseButton && (
2019-05-02 22:33:03 +02:00
<TouchableOpacity
style={{
width: 40,
height: 40,
backgroundColor: 'rgba(0,0,0,0.4)',
2019-05-02 22:33:03 +02:00
justifyContent: 'center',
borderRadius: 20,
position: 'absolute',
right: 16,
2019-05-02 22:33:03 +02:00
top: 64,
}}
2020-01-22 20:27:40 +01:00
onPress={() => (launchedBy ? navigate(launchedBy) : goBack(null))}
2019-05-02 22:33:03 +02:00
>
<Image style={{ alignSelf: 'center' }} source={require('../../img/close-white.png')} />
2019-05-02 22:33:03 +02:00
</TouchableOpacity>
2019-12-28 01:53:34 +01:00
)}
<TouchableOpacity
style={{
width: 40,
height: 40,
backgroundColor: '#FFFFFF',
justifyContent: 'center',
borderRadius: 20,
position: 'absolute',
left: 24,
bottom: 48,
}}
onPress={() => {
if (!isLoading) {
setIsLoading(true);
2019-09-21 19:37:37 +02:00
ImagePicker.launchImageLibrary(
{
title: null,
mediaType: 'photo',
takePhotoButtonTitle: null,
},
response => {
2019-09-22 01:39:42 +02:00
if (response.uri) {
const uri = Platform.OS === 'ios' ? response.uri.toString().replace('file://', '') : response.path.toString();
2019-09-22 01:39:42 +02:00
LocalQRCode.decode(uri, (error, result) => {
if (!error) {
2019-12-28 01:53:34 +01:00
onBarCodeRead({ data: result });
2019-09-22 01:39:42 +02:00
} else {
alert('The selected image does not contain a QR Code.');
}
});
}
2019-12-28 01:53:34 +01:00
setIsLoading(false);
2019-09-21 19:37:37 +02:00
},
);
2019-12-28 01:53:34 +01:00
}
}}
>
<Icon name="image" type="font-awesome" color="#0c2550" />
</TouchableOpacity>
2020-01-01 04:31:04 +01:00
{showFileImportButton && (
<TouchableOpacity
style={{
width: 40,
height: 40,
backgroundColor: '#FFFFFF',
justifyContent: 'center',
borderRadius: 20,
position: 'absolute',
left: 96,
bottom: 48,
2019-09-21 19:37:37 +02:00
}}
2020-01-01 04:31:04 +01:00
onPress={showFilePicker}
2019-09-21 19:37:37 +02:00
>
2020-01-01 04:31:04 +01:00
<Icon name="file-import" type="material-community" color="#0c2550" />
2019-09-21 19:37:37 +02:00
</TouchableOpacity>
2020-01-01 04:31:04 +01:00
)}
2019-12-28 01:53:34 +01:00
</View>
);
};
2018-03-18 03:48:23 +01:00
2019-12-28 01:53:34 +01:00
ScanQRCode.navigationOptions = {
header: null,
};
2019-09-21 19:37:37 +02:00
ScanQRCode.propTypes = {
2019-12-28 01:53:34 +01:00
launchedBy: PropTypes.string,
onBarScanned: PropTypes.func,
cameraPreviewIsPaused: PropTypes.bool,
2020-01-01 04:31:04 +01:00
showFileImportButton: PropTypes.bool,
2019-12-28 01:53:34 +01:00
showCloseButton: PropTypes.bool,
2018-03-18 03:48:23 +01:00
};
2019-12-28 01:53:34 +01:00
export default ScanQRCode;