fix: refresh camera device list after permission grant

useCameraDevices fetches once on mount. First-run flow grants the
camera permission after the viewfinder mounted, so the device list
stays empty until remount/restart and the UI shows 'Camera not
available on this device'. Poll Camera.getAvailableCameraDevices()
for up to 6s after permission is granted and prefer the found device.
This commit is contained in:
2026-09-07 17:30:41 +07:00
parent 200be77903
commit 674fe9d1e2
+28 -3
View File
@@ -1,6 +1,6 @@
import React, { useEffect } from 'react';
import React, { useEffect, useState } from 'react';
import { View, Text, StyleSheet, Dimensions, TouchableOpacity } from 'react-native';
import { Camera, useCameraDevice, useSkiaFrameProcessor } from 'react-native-vision-camera';
import { Camera, useCameraDevice, useSkiaFrameProcessor, type CameraDevice } from 'react-native-vision-camera';
import { useSharedValue } from 'react-native-reanimated';
import {
Canvas,
@@ -55,7 +55,32 @@ export default function Viewfinder({
onRequestCameraPermission,
cameraRef,
}: ViewfinderProps) {
const device = useCameraDevice('back');
const hookedDevice = useCameraDevice('back');
// VisionCamera fetches the device list once when this component mounts. When the
// camera permission is granted *after* mount (first-run flow: GRANT button, then
// OS dialog), that list stays empty until remount/restart, so the camera would
// report "not available". Poll the native list briefly after permission is
// granted and prefer a freshly found device.
const [grantedDevice, setGrantedDevice] = useState<CameraDevice | undefined>();
useEffect(() => {
if (!cameraPermissionGranted) return;
let stop = false;
const iv = setInterval(() => {
const back = Camera.getAvailableCameraDevices().find((d) => d.position === 'back');
if (back && !stop) {
setGrantedDevice(back);
clearInterval(iv);
clearTimeout(to);
}
}, 250);
const to = setTimeout(() => clearInterval(iv), 6000);
return () => {
stop = true;
clearInterval(iv);
clearTimeout(to);
};
}, [cameraPermissionGranted]);
const device = grantedDevice ?? hookedDevice;
const skiaImage = useImage(libraryImageUri || '');
const customFont = useFont(
require('../../assets/CourierPrime-Regular.ttf'),