import { type BarcodeScanningResult, Camera, CameraView } from 'expo-camera'; import { useCallback, useEffect, useState } from 'react'; import { Pressable, StyleSheet, Text, View } from 'react-native'; import { cancelQrCodeScan, completeQrCodeScan, failQrCodeScan, subscribeQrScannerState, } from '../host-bridge/scanner'; function logQrScannerPermissionFailure(_error: unknown) { console.warn('mobile QR scanner permission request failed'); } export function QrScannerOverlay() { const [isActive, setIsActive] = useState(false); const [requestKey, setRequestKey] = useState(0); const [hasPermission, setHasPermission] = useState(false); const [scanCompleted, setScanCompleted] = useState(false); useEffect( () => subscribeQrScannerState((state) => { setIsActive(state.active); setRequestKey(state.requestKey); }), [], ); useEffect(() => { if (!isActive) { setHasPermission(false); setScanCompleted(false); return; } let disposed = false; setHasPermission(false); setScanCompleted(false); void Camera.requestCameraPermissionsAsync() .then((permission) => { if (disposed) { return; } if (!permission.granted) { failQrCodeScan(); return; } setHasPermission(true); }) .catch((error: unknown) => { if (!disposed) { logQrScannerPermissionFailure(error); failQrCodeScan(); } }); return () => { disposed = true; }; }, [isActive, requestKey]); const handleBarcodeScanned = useCallback( (result: BarcodeScanningResult) => { if (scanCompleted || result.type !== 'qr') { return; } if (completeQrCodeScan(result.data)) { setScanCompleted(true); } }, [scanCompleted], ); if (!isActive) { return null; } return ( {hasPermission ? ( ) : null} 关闭 ); } const styles = StyleSheet.create({ root: { position: 'absolute', top: 0, right: 0, bottom: 0, left: 0, backgroundColor: '#0c0a09', }, camera: { flex: 1, }, frame: { position: 'absolute', top: '22%', right: 42, bottom: '22%', left: 42, borderWidth: 2, borderColor: '#fffdf9', borderRadius: 8, }, closeButton: { position: 'absolute', top: 20, right: 20, minWidth: 76, minHeight: 40, alignItems: 'center', justifyContent: 'center', borderRadius: 8, backgroundColor: '#fffdf9', paddingHorizontal: 16, }, closeButtonText: { color: '#211a16', fontSize: 15, fontWeight: '700', lineHeight: 20, }, });