Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Chrome mWeb - scan button provides no feedback #30094

Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 46 additions & 5 deletions src/pages/iou/ReceiptSelector/NavigationAwareCamera.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,20 @@
import React, {useEffect, useRef} from 'react';
import React, {useEffect, useRef, useState} from 'react';
import Webcam from 'react-webcam';
import {useIsFocused} from '@react-navigation/native';
import PropTypes from 'prop-types';
import {View} from 'react-native';
import {useTabAnimation} from '@react-navigation/material-top-tabs';

const propTypes = {
/* Flag to turn on/off the torch/flashlight - if available */
torchOn: PropTypes.bool,

/* The index of the tab that contains this camera */
cameraTabIndex: PropTypes.number.isRequired,
Copy link
Contributor

Choose a reason for hiding this comment

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

Can you please update these comments (and the existing ones) to use the format /** */. This is so that storybook can automatically parse them.


/* Whether we're in a tab navigator */
isInTabNavigator: PropTypes.bool.isRequired,

/* Callback function when media stream becomes available - user granted camera permissions and camera starts to work */
onUserMedia: PropTypes.func,

Expand All @@ -21,10 +28,40 @@ const defaultProps = {
torchOn: false,
};

function useTabNavigatorFocus({cameraTabIndex, isInTabNavigator}) {
// Get navigation to get initial isFocused value (only needed once during init!)
Copy link
Contributor

Choose a reason for hiding this comment

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

I would suggest moving this to its own file and having it be defined as a proper hook.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

agree!

const isPageFocused = useIsFocused();
Copy link
Contributor

Choose a reason for hiding this comment

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

This sentence doesn't really make sense, the first two words seem out of place.

const [isTabFocused, setIsTabFocused] = useState(false);

// Retrieve the animation value from the tab navigator, which ranges from 0 to the total number of pages displayed.
// Even a minimal scroll towards the camera page (e.g., a value of 0.001 at start) should activate the camera for immediate responsiveness.

// STOP!!!!!!! This is not a pattern to be followed! We are conditionally rendering this hook becase when used in the edit flow we'll never be inside a tab navigator.
// eslint-disable-next-line react-hooks/rules-of-hooks
Copy link
Contributor

Choose a reason for hiding this comment

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

This comment is nice, but it sure makes me think that this is built wrong. It sounds like there should be two different components.

Copy link
Contributor

Choose a reason for hiding this comment

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

I didn't request this change because there's already separate GH for this.

Copy link
Contributor

Choose a reason for hiding this comment

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

OK, thank you for making me aware of it.

const tabPositionAnimation = isInTabNavigator ? useTabAnimation() : null;

useEffect(() => {
if (!isInTabNavigator) {
return;
}

const listenerId = tabPositionAnimation.addListener(({value}) => {
// Activate camera as soon the index is animating towards the `cameraTabIndex`
setIsTabFocused(value > cameraTabIndex - 1 && value < cameraTabIndex + 1);
});

return () => {
tabPositionAnimation.removeListener(listenerId);
};
}, [cameraTabIndex, tabPositionAnimation, isInTabNavigator]);

return isTabFocused && isPageFocused;
}

// Wraps a camera that will only be active when the tab is focused or as soon as it starts to become focused.
const NavigationAwareCamera = React.forwardRef(({torchOn, onTorchAvailability, ...props}, ref) => {
const NavigationAwareCamera = React.forwardRef(({torchOn, onTorchAvailability, cameraTabIndex, isInTabNavigator, ...props}, ref) => {
const trackRef = useRef(null);
const isCameraActive = useIsFocused();
const showCamera = useTabNavigatorFocus({cameraTabIndex, isInTabNavigator});

lukemorawski marked this conversation as resolved.
Show resolved Hide resolved
const handleOnUserMedia = (stream) => {
if (props.onUserMedia) {
Expand All @@ -47,11 +84,15 @@ const NavigationAwareCamera = React.forwardRef(({torchOn, onTorchAvailability, .
}

trackRef.current.applyConstraints({
advanced: [{torch: torchOn}],
advanced: [
{
torch: torchOn,
},
],
});
}, [torchOn]);

if (!isCameraActive) {
if (!showCamera) {
return null;
}
return (
Expand Down
7 changes: 5 additions & 2 deletions src/pages/iou/ReceiptSelector/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,9 @@ const defaultProps = {
isInTabNavigator: true,
};

function ReceiptSelector({route, transactionID, iou, report}) {
function ReceiptSelector({route, transactionID, iou, report, isInTabNavigator}) {
const iouType = lodashGet(route, 'params.iouType', '');
const pageIndex = lodashGet(route, 'params.pageIndex', 1);

// Grouping related states
const [isAttachmentInvalid, setIsAttachmentInvalid] = useState(false);
Expand All @@ -82,7 +83,7 @@ function ReceiptSelector({route, transactionID, iou, report}) {

const [cameraPermissionState, setCameraPermissionState] = useState('prompt');
const [isFlashLightOn, toggleFlashlight] = useReducer((state) => !state, false);
const [isTorchAvailable, setIsTorchAvailable] = useState(true);
const [isTorchAvailable, setIsTorchAvailable] = useState(false);
const cameraRef = useRef(null);

const hideReciptModal = () => {
Expand Down Expand Up @@ -201,6 +202,8 @@ function ReceiptSelector({route, transactionID, iou, report}) {
torchOn={isFlashLightOn}
onTorchAvailability={setIsTorchAvailable}
forceScreenshotSourceSize
cameraTabIndex={pageIndex}
isInTabNavigator={isInTabNavigator}
/>
</View>

Expand Down
Loading