From 1d01abc7dafe955c2eb77bd83cefac50ea25fe13 Mon Sep 17 00:00:00 2001 From: Alie Langston Date: Wed, 16 Sep 2020 09:16:30 -0400 Subject: [PATCH] added feedback for screenreaders moved settings state back to original fixed status updates updated message for more clarity renamed variables for clarity added comment fixed variables fixed variable again decreased delay between feedbacks updated comment --- src/id-verification/Camera.jsx | 103 +++++++++++++++++- .../IdVerification.messages.js | 60 ++++++++++ 2 files changed, 157 insertions(+), 6 deletions(-) diff --git a/src/id-verification/Camera.jsx b/src/id-verification/Camera.jsx index 8876f16..e42c386 100644 --- a/src/id-verification/Camera.jsx +++ b/src/id-verification/Camera.jsx @@ -20,14 +20,16 @@ class Camera extends React.Component { videoHasLoaded: false, shouldDetect: false, isFinishedLoadingDetection: true, + shouldGiveFeedback: true, + feedback: '', }; } componentDidMount() { this.cameraPhoto = new CameraPhoto(this.videoRef.current); this.cameraPhoto.startCamera( - this.props.isPortrait ? FACING_MODES.USER : FACING_MODES.ENVIRONMENT, - { width: 640, height: 480 } + this.props.isPortrait ? FACING_MODES.USER : FACING_MODES.ENVIRONMENT, + { width: 640, height: 480 }, ); } @@ -97,11 +99,14 @@ class Camera extends React.Component { const x = features[j][0]; const y = features[j][1]; + let isInRange; if (this.props.isPortrait) { - isInPosition = isInPosition && this.isInRangeForPortrait(x, y); + isInRange = this.isInRangeForPortrait(x, y); } else { - isInPosition = isInPosition && this.isInRangeForID(x, y); + isInRange = this.isInRangeForID(x, y); } + // if it is not in range, give feedback depending on which feature is out of range + isInPosition = isInPosition && isInRange; } // draw a box depending on if all landmarks are in position @@ -109,11 +114,81 @@ class Camera extends React.Component { canvasContext.strokeStyle = '#00ffff'; canvasContext.lineWidth = 6; canvasContext.strokeRect(start[0], start[1], size[0], size[1]); + // give positive feedback here if user is in correct position + this.giveFeedback(predictions.length, [], true); } else { canvasContext.fillStyle = 'rgba(255, 51, 0, 0.75)'; canvasContext.fillRect(start[0], start[1], size[0], size[1]); + this.giveFeedback(predictions.length, features[0], false); } }); + + if (predictions.length === 0) { + this.giveFeedback(predictions.length, [], false); + } + } + + giveFeedback(numFaces, rightEye, isCorrect) { + if (this.state.shouldGiveFeedback) { + const currentFeedback = this.state.feedback; + let newFeedback = ''; + if (numFaces === 1) { + // only give feedback if one face is detected otherwise + // it would be difficult to tell a user which face to move + if (isCorrect) { + newFeedback = this.props.intl.formatMessage(messages['id.verification.photo.feedback.correct']); + } else { + // give feedback based on where user is + newFeedback = this.props.intl.formatMessage(messages[this.getGridPosition(rightEye)]); + } + } else if (numFaces > 1) { + newFeedback = this.props.intl.formatMessage(messages['id.verification.photo.feedback.two.faces']); + } else { + newFeedback = this.props.intl.formatMessage(messages['id.verification.photo.feedback.no.faces']); + } + if (currentFeedback !== newFeedback) { + // only update status if it is different, so we don't overload the user with status updates + this.setState({ feedback: newFeedback }); + } + // turn off feedback for one to ensure that instructions aren't disruptive/interrupting + this.setState({ shouldGiveFeedback: false }); + setTimeout(() => { + this.setState({ shouldGiveFeedback: true }); + }, 1000); + } + } + + getGridPosition(coordinates) { + // Used to determine where a face is (i.e. top-left, center-right, bottom-center, etc.) + + const x = coordinates[0]; + const y = coordinates[1]; + + let messageBase = 'id.verification.photo.feedback'; + + const heightUpperLimit = 320; + const heightMiddleLimit = 160; + + if (y < heightMiddleLimit) { + messageBase += '.top'; + } else if (y < heightUpperLimit && y >= heightMiddleLimit) { + messageBase += '.center'; + } else { + messageBase += '.bottom'; + } + + const widthRightLimit = 213; + const widthMiddleLimit = 427; + + if (x < widthRightLimit) { + messageBase += '.right'; + } else if (x >= widthRightLimit && x < widthMiddleLimit) { + messageBase += '.center'; + } else { + messageBase += '.left'; + } + + return messageBase; } isInRangeForPortrait(x, y) { @@ -207,16 +282,32 @@ class Camera extends React.Component { autoPlay className="camera-video" onLoadedData={() => { this.setVideoHasLoaded(); }} - style={{ display: this.state.dataUri ? 'none' : 'block' }} + style={{ + display: this.state.dataUri ? 'none' : 'block', + WebkitTransform: 'scaleX(-1)', + transform: 'scaleX(-1)', + }} playsInline /> - + imgCamera +
{this.state.feedback}