Skip to content
Original file line number Diff line number Diff line change
@@ -1,23 +1,29 @@
import {useIsFocused} from '@react-navigation/native';
import React from 'react';
import React, {useState} from 'react';
import type {ForwardedRef} from 'react';
import {View} from 'react-native';
import type {Camera} from 'react-native-vision-camera';
import Webcam from 'react-webcam';
import useThemeStyles from '@hooks/useThemeStyles';
import type {NavigationAwareCameraProps} from './types';

// Wraps a camera that will only be active when the tab is focused or as soon as it starts to become focused.
function WebCamera({torchOn, onTorchAvailability, cameraTabIndex, ...props}: NavigationAwareCameraProps, ref: ForwardedRef<Webcam | Camera>) {
function WebCamera(props: NavigationAwareCameraProps, ref: ForwardedRef<Webcam | Camera>) {
const [isInitialized, setIsInitialized] = useState(false);
const shouldShowCamera = useIsFocused();
const styles = useThemeStyles();

if (!shouldShowCamera) {
return null;
}

return (
<View>
// Hide the camera during initialization to prevent random failures on some iOS versions.
<View style={isInitialized ? styles.dFlex : styles.dNone}>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing flex: 1 caused this issue #64049

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the comment! But this PR didn't cause that. We already used <View> without flex: 1 on purpose before to solve an issue (commit: 98519f0) and dFlex was the default. This PR only added dNone.

<Webcam
// eslint-disable-next-line react/jsx-props-no-spreading
{...props}
onResize={() => setIsInitialized(true)}
ref={ref as unknown as ForwardedRef<Webcam>}
/>
</View>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,7 @@
import type {CameraProps} from 'react-native-vision-camera';
import type {WebcamProps} from 'react-webcam';

type NavigationAwareCameraProps = WebcamProps & {
/** Flag to turn on/off the torch/flashlight - if available */
torchOn?: boolean;

/** The index of the tab that contains this camera */
onTorchAvailability?: (torchAvailable: boolean) => void;

/** Callback function when media stream becomes available - user granted camera permissions and camera starts to work */
cameraTabIndex: number;
};
type NavigationAwareCameraProps = WebcamProps;

type NavigationAwareCameraNativeProps = Omit<CameraProps, 'isActive'> & {
cameraTabIndex: number;
Expand Down
8 changes: 3 additions & 5 deletions src/pages/iou/request/step/IOURequestStepScan/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,6 @@ function IOURequestStepScan({
const [isLoadingReceipt, setIsLoadingReceipt] = useState(false);

const [videoConstraints, setVideoConstraints] = useState<MediaTrackConstraints>();
const tabIndex = 1;
const isTabActive = useIsFocused();

const isEditing = action === CONST.IOU.ACTION.EDIT;
Expand All @@ -118,7 +117,7 @@ function IOURequestStepScan({
* The last deviceId is of regular len camera.
*/
const requestCameraPermission = useCallback(() => {
if (!isEmptyObject(videoConstraints) || !Browser.isMobile()) {
if (!Browser.isMobile()) {
return;
}

Expand All @@ -129,7 +128,7 @@ function IOURequestStepScan({
setCameraPermissionState('granted');
stream.getTracks().forEach((track) => track.stop());
// Only Safari 17+ supports zoom constraint
if (Browser.isMobileSafari() && stream.getTracks().length > 0) {
if (Browser.isMobileWebKit() && stream.getTracks().length > 0) {
let deviceId;
for (const track of stream.getTracks()) {
const setting = track.getSettings();
Expand Down Expand Up @@ -167,11 +166,11 @@ function IOURequestStepScan({
setVideoConstraints(defaultConstraints);
setCameraPermissionState('denied');
});
// eslint-disable-next-line react-compiler/react-compiler, react-hooks/exhaustive-deps
}, []);

useEffect(() => {
if (!Browser.isMobile() || !isTabActive) {
setVideoConstraints(undefined);
return;
}
navigator.permissions
Expand Down Expand Up @@ -665,7 +664,6 @@ function IOURequestStepScan({
screenshotFormat="image/png"
videoConstraints={videoConstraints}
forceScreenshotSourceSize
cameraTabIndex={tabIndex}
audio={false}
disablePictureInPicture={false}
imageSmoothing={false}
Expand Down