import React, { useState } from 'react' import { useTranslation } from 'react-i18next' import { Keyboard, StyleSheet, Text, TextInput, TouchableOpacity, View } from 'react-native' import { RNCamera } from 'react-native-camera' import DeviceInfo from 'react-native-device-info' import { useSafeAreaFrame, useSafeAreaInsets } from 'react-native-safe-area-context' import { Defs, Mask, Rect, Svg } from 'react-native-svg' import Modal from 'src/components/Modal' import TextButton from 'src/components/TextButton' import NotAuthorizedView from 'src/qrcode/NotAuthorizedView' import { QrCode } from 'src/send/types' import colors from 'src/styles/colors' import { typeScale } from 'src/styles/fonts' interface QRScannerProps { onQRCodeDetected: (qrCode: QrCode) => void } const SeeThroughOverlay = () => { const { width, height } = useSafeAreaFrame() const margin = 40 const centerBoxSize = width - margin * 2 const centerBoxBorderRadius = 8 // TODO(jeanregisser): Investigate why the mask is pixelated on iOS. // It's visible on the rounded corners but since they are small, I'm ignoring it for now. // Node that the Mask component is using hard coded color values solely to // create the "cutout" effect. return ( ) } export default function QRScanner({ onQRCodeDetected }: QRScannerProps) { const { t } = useTranslation() const inset = useSafeAreaInsets() // eslint-disable-next-line react-hooks/rules-of-hooks const isEmulator = DeviceInfo.useIsEmulator ? DeviceInfo.useIsEmulator().result : false /** * Emulator only. When in the emulator we want to be able * to enter QR codes manually. */ const [value, setValue] = useState('') const [displayEntryModal, setDisplayEntryModal] = useState(false) const openModal = () => { setDisplayEntryModal(true) } const closeModal = () => { setDisplayEntryModal(false) setValue('') } const submitModal = () => { Keyboard.dismiss() closeModal() // add a delay to allow modal to close before calling onQRCodeDetected, // otherwise nothing is clickable in the next screen this navigates to. A // better solution is to use onModalHide prop of Modal, but this is an // emulator only feature, so this is good enough. setTimeout(() => { onQRCodeDetected({ type: '', data: value }) }, 500) } const onModalTextChange = (text: string) => { setValue(text) } const cameraScanInfo = ( {t('cameraScanInfo')} ) return ( } testID={'Camera'} > {isEmulator ? ( {cameraScanInfo} ) : ( cameraScanInfo )} {t('enterQRCode')} {t('cancel')} {t('submit')} ) } const styles = StyleSheet.create({ camera: { flex: 1, overflow: 'hidden', }, infoText: { position: 'absolute', left: 9, right: 9, bottom: 32, ...typeScale.labelSemiBoldSmall, lineHeight: undefined, color: colors.qrTabBarSecondary, textAlign: 'center', paddingHorizontal: 30, }, manualInput: { ...typeScale.bodyMedium, marginBottom: 12, paddingHorizontal: 12, paddingVertical: 0, marginTop: 8, alignItems: 'flex-start', borderColor: colors.contentSecondary, borderRadius: 4, borderWidth: 1.5, height: 80, maxHeight: 150, }, manualTitle: { marginBottom: 6, ...typeScale.titleSmall, }, actions: { flexDirection: 'row', justifyContent: 'space-around', maxWidth: '100%', flexWrap: 'wrap', }, cancelButton: { color: colors.contentSecondary, }, })