@trustchex/react-native-sdk 1.409.0 → 1.472.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/android/src/main/java/com/trustchex/reactnativesdk/TrustchexSDKModule.kt +2 -8
- package/android/src/main/java/com/trustchex/reactnativesdk/camera/TrustchexCameraView.kt +102 -4
- package/ios/Camera/TrustchexCameraView.swift +151 -18
- package/ios/Permission/PermissionModule.m +22 -0
- package/ios/Permission/PermissionModule.swift +67 -0
- package/lib/module/Screens/Debug/NFCScanTestScreen.js +635 -0
- package/lib/module/Screens/Dynamic/ContractAcceptanceScreen.js +1 -4
- package/lib/module/Screens/Dynamic/IdentityDocumentEIDScanningScreen.js +17 -4
- package/lib/module/Screens/Dynamic/LivenessDetectionScreen.js +125 -25
- package/lib/module/Screens/Dynamic/VerbalConsentScreen.js +1079 -0
- package/lib/module/Screens/Dynamic/VideoCallScreen.js +10 -13
- package/lib/module/Screens/Static/ResultScreen.js +131 -22
- package/lib/module/Screens/Static/VerificationSessionCheckScreen.js +8 -0
- package/lib/module/Shared/Animations/recording.json +1 -0
- package/lib/module/Shared/Components/DebugNavigationPanel.js +69 -71
- package/lib/module/Shared/Components/EIDScanner.js +222 -115
- package/lib/module/Shared/Components/FaceCamera.js +14 -8
- package/lib/module/Shared/Components/IdentityDocumentCamera.flows.js +5 -3
- package/lib/module/Shared/Components/IdentityDocumentCamera.js +60 -42
- package/lib/module/Shared/Components/IdentityDocumentCamera.utils.js +13 -4
- package/lib/module/Shared/Components/NavigationManager.js +24 -16
- package/lib/module/Shared/EIDReader/aesSecureMessagingWrapper.js +51 -0
- package/lib/module/Shared/EIDReader/apduLevelPACECapable.js +3 -0
- package/lib/module/Shared/EIDReader/bacKey.js +16 -2
- package/lib/module/Shared/EIDReader/eidReader.js +354 -13
- package/lib/module/Shared/EIDReader/eidService.js +25 -1
- package/lib/module/Shared/EIDReader/nfcManagerCardService.js +4 -7
- package/lib/module/Shared/EIDReader/paceInfo.js +85 -0
- package/lib/module/Shared/EIDReader/paceKeySpec.js +51 -0
- package/lib/module/Shared/EIDReader/protocol/paceAPDUSender.js +100 -0
- package/lib/module/Shared/EIDReader/protocol/paceProtocol.js +655 -0
- package/lib/module/Shared/EIDReader/protocol/paceResult.js +37 -0
- package/lib/module/Shared/EIDReader/secureMessagingWrapper.js +27 -4
- package/lib/module/Shared/EIDReader/smartcards/commandAPDU.js +2 -1
- package/lib/module/Shared/EIDReader/tlv/tlv.helpers.js +1 -1
- package/lib/module/Shared/EIDReader/tlv/tlv.utils.js +6 -3
- package/lib/module/Shared/EIDReader/utils/aesCrypto.utils.js +189 -0
- package/lib/module/Shared/Libs/PERMISSIONS_MANAGER.md +268 -0
- package/lib/module/Shared/Libs/analytics.utils.js +4 -0
- package/lib/module/Shared/Libs/contains.js +1 -40
- package/lib/module/Shared/Libs/country-display.utils.js +34 -0
- package/lib/module/Shared/Libs/demo.utils.js +8 -0
- package/lib/module/Shared/Libs/index.js +20 -0
- package/lib/module/Shared/Libs/mrz.utils.js +3 -2
- package/lib/module/Shared/Libs/permissions.utils.js +199 -0
- package/lib/module/Shared/Libs/status-bar.utils.js +4 -2
- package/lib/module/Shared/Types/analytics.types.js +2 -0
- package/lib/module/Translation/Resources/en.js +42 -2
- package/lib/module/Translation/Resources/tr.js +42 -2
- package/lib/module/Trustchex.js +54 -20
- package/lib/module/version.js +1 -1
- package/lib/typescript/src/Screens/Debug/NFCScanTestScreen.d.ts +3 -0
- package/lib/typescript/src/Screens/Debug/NFCScanTestScreen.d.ts.map +1 -0
- package/lib/typescript/src/Screens/Dynamic/ContractAcceptanceScreen.d.ts.map +1 -1
- package/lib/typescript/src/Screens/Dynamic/IdentityDocumentEIDScanningScreen.d.ts.map +1 -1
- package/lib/typescript/src/Screens/Dynamic/LivenessDetectionScreen.d.ts.map +1 -1
- package/lib/typescript/src/Screens/Dynamic/VerbalConsentScreen.d.ts +3 -0
- package/lib/typescript/src/Screens/Dynamic/VerbalConsentScreen.d.ts.map +1 -0
- package/lib/typescript/src/Screens/Dynamic/VideoCallScreen.d.ts.map +1 -1
- package/lib/typescript/src/Screens/Static/ResultScreen.d.ts.map +1 -1
- package/lib/typescript/src/Screens/Static/VerificationSessionCheckScreen.d.ts.map +1 -1
- package/lib/typescript/src/Shared/Components/DebugNavigationPanel.d.ts.map +1 -1
- package/lib/typescript/src/Shared/Components/EIDScanner.d.ts.map +1 -1
- package/lib/typescript/src/Shared/Components/FaceCamera.d.ts.map +1 -1
- package/lib/typescript/src/Shared/Components/IdentityDocumentCamera.d.ts.map +1 -1
- package/lib/typescript/src/Shared/Components/IdentityDocumentCamera.flows.d.ts +1 -1
- package/lib/typescript/src/Shared/Components/IdentityDocumentCamera.flows.d.ts.map +1 -1
- package/lib/typescript/src/Shared/Components/IdentityDocumentCamera.utils.d.ts +5 -0
- package/lib/typescript/src/Shared/Components/IdentityDocumentCamera.utils.d.ts.map +1 -1
- package/lib/typescript/src/Shared/Components/NavigationManager.d.ts.map +1 -1
- package/lib/typescript/src/Shared/EIDReader/aesSecureMessagingWrapper.d.ts +18 -0
- package/lib/typescript/src/Shared/EIDReader/aesSecureMessagingWrapper.d.ts.map +1 -0
- package/lib/typescript/src/Shared/EIDReader/apduLevelPACECapable.d.ts +23 -0
- package/lib/typescript/src/Shared/EIDReader/apduLevelPACECapable.d.ts.map +1 -0
- package/lib/typescript/src/Shared/EIDReader/bacKey.d.ts +6 -0
- package/lib/typescript/src/Shared/EIDReader/bacKey.d.ts.map +1 -1
- package/lib/typescript/src/Shared/EIDReader/eidReader.d.ts.map +1 -1
- package/lib/typescript/src/Shared/EIDReader/eidService.d.ts +9 -0
- package/lib/typescript/src/Shared/EIDReader/eidService.d.ts.map +1 -1
- package/lib/typescript/src/Shared/EIDReader/nfcManagerCardService.d.ts.map +1 -1
- package/lib/typescript/src/Shared/EIDReader/paceInfo.d.ts +50 -0
- package/lib/typescript/src/Shared/EIDReader/paceInfo.d.ts.map +1 -0
- package/lib/typescript/src/Shared/EIDReader/paceKeySpec.d.ts +30 -0
- package/lib/typescript/src/Shared/EIDReader/paceKeySpec.d.ts.map +1 -0
- package/lib/typescript/src/Shared/EIDReader/protocol/paceAPDUSender.d.ts +17 -0
- package/lib/typescript/src/Shared/EIDReader/protocol/paceAPDUSender.d.ts.map +1 -0
- package/lib/typescript/src/Shared/EIDReader/protocol/paceProtocol.d.ts +105 -0
- package/lib/typescript/src/Shared/EIDReader/protocol/paceProtocol.d.ts.map +1 -0
- package/lib/typescript/src/Shared/EIDReader/protocol/paceResult.d.ts +24 -0
- package/lib/typescript/src/Shared/EIDReader/protocol/paceResult.d.ts.map +1 -0
- package/lib/typescript/src/Shared/EIDReader/secureMessagingWrapper.d.ts +15 -0
- package/lib/typescript/src/Shared/EIDReader/secureMessagingWrapper.d.ts.map +1 -1
- package/lib/typescript/src/Shared/EIDReader/smartcards/commandAPDU.d.ts.map +1 -1
- package/lib/typescript/src/Shared/EIDReader/tlv/tlv.utils.d.ts.map +1 -1
- package/lib/typescript/src/Shared/EIDReader/utils/aesCrypto.utils.d.ts +39 -0
- package/lib/typescript/src/Shared/EIDReader/utils/aesCrypto.utils.d.ts.map +1 -0
- package/lib/typescript/src/Shared/Libs/analytics.utils.d.ts.map +1 -1
- package/lib/typescript/src/Shared/Libs/contains.d.ts +0 -7
- package/lib/typescript/src/Shared/Libs/contains.d.ts.map +1 -1
- package/lib/typescript/src/Shared/Libs/country-display.utils.d.ts +2 -0
- package/lib/typescript/src/Shared/Libs/country-display.utils.d.ts.map +1 -0
- package/lib/typescript/src/Shared/Libs/demo.utils.d.ts.map +1 -1
- package/lib/typescript/src/Shared/Libs/http-client.d.ts +1 -1
- package/lib/typescript/src/Shared/Libs/http-client.d.ts.map +1 -1
- package/lib/typescript/src/Shared/Libs/index.d.ts +20 -0
- package/lib/typescript/src/Shared/Libs/index.d.ts.map +1 -0
- package/lib/typescript/src/Shared/Libs/mrz.utils.d.ts.map +1 -1
- package/lib/typescript/src/Shared/Libs/permissions.utils.d.ts +58 -0
- package/lib/typescript/src/Shared/Libs/permissions.utils.d.ts.map +1 -0
- package/lib/typescript/src/Shared/Libs/status-bar.utils.d.ts.map +1 -1
- package/lib/typescript/src/Shared/Types/analytics.types.d.ts +2 -0
- package/lib/typescript/src/Shared/Types/analytics.types.d.ts.map +1 -1
- package/lib/typescript/src/Shared/Types/identificationInfo.d.ts +10 -1
- package/lib/typescript/src/Shared/Types/identificationInfo.d.ts.map +1 -1
- package/lib/typescript/src/Translation/Resources/en.d.ts +41 -1
- package/lib/typescript/src/Translation/Resources/en.d.ts.map +1 -1
- package/lib/typescript/src/Translation/Resources/tr.d.ts +41 -1
- package/lib/typescript/src/Translation/Resources/tr.d.ts.map +1 -1
- package/lib/typescript/src/Trustchex.d.ts.map +1 -1
- package/lib/typescript/src/version.d.ts +1 -1
- package/package.json +7 -4
- package/src/Screens/Debug/NFCScanTestScreen.tsx +692 -0
- package/src/Screens/Dynamic/ContractAcceptanceScreen.tsx +1 -4
- package/src/Screens/Dynamic/IdentityDocumentEIDScanningScreen.tsx +21 -4
- package/src/Screens/Dynamic/LivenessDetectionScreen.tsx +165 -24
- package/src/Screens/Dynamic/VerbalConsentScreen.tsx +1401 -0
- package/src/Screens/Dynamic/VideoCallScreen.tsx +11 -20
- package/src/Screens/Static/ResultScreen.tsx +187 -31
- package/src/Screens/Static/VerificationSessionCheckScreen.tsx +9 -0
- package/src/Shared/Animations/recording.json +1 -0
- package/src/Shared/Components/DebugNavigationPanel.tsx +73 -48
- package/src/Shared/Components/EIDScanner.tsx +280 -119
- package/src/Shared/Components/FaceCamera.tsx +19 -16
- package/src/Shared/Components/IdentityDocumentCamera.flows.ts +7 -4
- package/src/Shared/Components/IdentityDocumentCamera.tsx +206 -191
- package/src/Shared/Components/IdentityDocumentCamera.utils.ts +13 -4
- package/src/Shared/Components/NavigationManager.tsx +27 -18
- package/src/Shared/EIDReader/aesSecureMessagingWrapper.ts +69 -0
- package/src/Shared/EIDReader/apduLevelPACECapable.ts +34 -0
- package/src/Shared/EIDReader/bacKey.ts +24 -8
- package/src/Shared/EIDReader/eidReader.ts +398 -12
- package/src/Shared/EIDReader/eidService.ts +49 -1
- package/src/Shared/EIDReader/nfcManagerCardService.ts +4 -6
- package/src/Shared/EIDReader/paceInfo.ts +159 -0
- package/src/Shared/EIDReader/paceKeySpec.ts +56 -0
- package/src/Shared/EIDReader/protocol/paceAPDUSender.ts +163 -0
- package/src/Shared/EIDReader/protocol/paceProtocol.ts +946 -0
- package/src/Shared/EIDReader/protocol/paceResult.ts +62 -0
- package/src/Shared/EIDReader/secureMessagingWrapper.ts +28 -10
- package/src/Shared/EIDReader/smartcards/commandAPDU.ts +2 -1
- package/src/Shared/EIDReader/tlv/tlv.helpers.ts +1 -1
- package/src/Shared/EIDReader/tlv/tlv.utils.ts +8 -5
- package/src/Shared/EIDReader/utils/aesCrypto.utils.ts +217 -0
- package/src/Shared/Libs/PERMISSIONS_MANAGER.md +268 -0
- package/src/Shared/Libs/analytics.utils.ts +4 -0
- package/src/Shared/Libs/contains.ts +0 -53
- package/src/Shared/Libs/country-display.utils.ts +55 -0
- package/src/Shared/Libs/crypto.utils.ts +2 -2
- package/src/Shared/Libs/demo.utils.ts +10 -0
- package/src/Shared/Libs/http-client.ts +12 -4
- package/src/Shared/Libs/index.ts +63 -0
- package/src/Shared/Libs/mrz.utils.ts +3 -2
- package/src/Shared/Libs/permissions.utils.ts +251 -0
- package/src/Shared/Libs/status-bar.utils.ts +4 -2
- package/src/Shared/Services/VideoSessionService.ts +1 -1
- package/src/Shared/Types/analytics.types.ts +2 -0
- package/src/Shared/Types/identificationInfo.ts +11 -0
- package/src/Translation/Resources/en.ts +64 -3
- package/src/Translation/Resources/tr.ts +63 -3
- package/src/Trustchex.tsx +53 -17
- package/src/version.ts +1 -1
|
@@ -3,13 +3,12 @@
|
|
|
3
3
|
import Svg, { Rect as SvgRect, Circle, Mask } from 'react-native-svg';
|
|
4
4
|
import { useNavigation } from '@react-navigation/native';
|
|
5
5
|
import React, { useState, useReducer, useContext, useEffect, useCallback, useRef } from 'react';
|
|
6
|
-
import { StyleSheet, Text, View, Dimensions, Vibration, StatusBar } from 'react-native';
|
|
6
|
+
import { Animated, Easing, StyleSheet, Text, View, Dimensions, Platform, Vibration, StatusBar } from 'react-native';
|
|
7
7
|
import { useSafeAreaInsets, SafeAreaView } from 'react-native-safe-area-context';
|
|
8
8
|
import NativeCircularProgress from "../../Shared/Components/NativeCircularProgress.js";
|
|
9
9
|
import FaceCamera from "../../Shared/Components/FaceCamera.js";
|
|
10
10
|
import NavigationManager from "../../Shared/Components/NavigationManager.js";
|
|
11
11
|
import AppContext from "../../Shared/Contexts/AppContext.js";
|
|
12
|
-
import { contains } from "../../Shared/Libs/contains.js";
|
|
13
12
|
import { useTranslation } from 'react-i18next';
|
|
14
13
|
import StyledButton from "../../Shared/Components/StyledButton.js";
|
|
15
14
|
import LottieView from 'lottie-react-native';
|
|
@@ -22,7 +21,7 @@ const {
|
|
|
22
21
|
width: windowWidth,
|
|
23
22
|
height: windowHeight
|
|
24
23
|
} = Dimensions.get('window');
|
|
25
|
-
const PREVIEW_SIZE = windowWidth * 0.
|
|
24
|
+
const PREVIEW_SIZE = windowWidth * 0.95;
|
|
26
25
|
const PREVIEW_RECT = {
|
|
27
26
|
minX: (windowWidth - PREVIEW_SIZE) / 2,
|
|
28
27
|
minY: (windowHeight - PREVIEW_SIZE) / 2,
|
|
@@ -44,9 +43,29 @@ const LivenessDetectionScreen = () => {
|
|
|
44
43
|
const [isRecording, setIsRecording] = useState(false);
|
|
45
44
|
const insets = useSafeAreaInsets();
|
|
46
45
|
const referenceFaceTrackingId = useRef(null);
|
|
46
|
+
const recordingDotOpacity = useRef(new Animated.Value(1)).current;
|
|
47
47
|
|
|
48
48
|
// Track screen view and exit
|
|
49
49
|
useScreenTracking('liveness_detection');
|
|
50
|
+
useEffect(() => {
|
|
51
|
+
if (isRecording) {
|
|
52
|
+
const pulse = Animated.loop(Animated.sequence([Animated.timing(recordingDotOpacity, {
|
|
53
|
+
toValue: 0.2,
|
|
54
|
+
duration: 600,
|
|
55
|
+
easing: Easing.inOut(Easing.ease),
|
|
56
|
+
useNativeDriver: true
|
|
57
|
+
}), Animated.timing(recordingDotOpacity, {
|
|
58
|
+
toValue: 1,
|
|
59
|
+
duration: 600,
|
|
60
|
+
easing: Easing.inOut(Easing.ease),
|
|
61
|
+
useNativeDriver: true
|
|
62
|
+
})]));
|
|
63
|
+
pulse.start();
|
|
64
|
+
return () => pulse.stop();
|
|
65
|
+
} else {
|
|
66
|
+
recordingDotOpacity.setValue(1);
|
|
67
|
+
}
|
|
68
|
+
}, [isRecording, recordingDotOpacity]);
|
|
50
69
|
|
|
51
70
|
// Configure status bar for white background
|
|
52
71
|
useStatusBarWhiteBackground();
|
|
@@ -98,7 +117,6 @@ const LivenessDetectionScreen = () => {
|
|
|
98
117
|
instruction: t('livenessDetectionScreen.finish')
|
|
99
118
|
}
|
|
100
119
|
});
|
|
101
|
-
const [instructionList, setInstructionList] = useState([]);
|
|
102
120
|
const [hasGuideShown, setHasGuideShown] = useState(false);
|
|
103
121
|
const stoppingRecordingRef = useRef(false); // Track if we're already stopping to prevent multiple calls
|
|
104
122
|
|
|
@@ -113,7 +131,9 @@ const LivenessDetectionScreen = () => {
|
|
|
113
131
|
} else {
|
|
114
132
|
// Guide screen with white background - use dark icons
|
|
115
133
|
StatusBar.setBarStyle('dark-content', true);
|
|
116
|
-
|
|
134
|
+
if (Platform.OS === 'android') {
|
|
135
|
+
StatusBar.setBackgroundColor('#ffffff', true);
|
|
136
|
+
}
|
|
117
137
|
}
|
|
118
138
|
}, [hasGuideShown]);
|
|
119
139
|
useEffect(() => {
|
|
@@ -122,7 +142,6 @@ const LivenessDetectionScreen = () => {
|
|
|
122
142
|
instruction === 'LOOK_STRAIGHT_AND_BLINK' || !appContext.currentWorkflowStep?.data?.allowedLivenessInstructionTypes || appContext.currentWorkflowStep?.data?.allowedLivenessInstructionTypes.length === 0 || appContext.currentWorkflowStep?.data?.allowedLivenessInstructionTypes.includes(instruction))).sort(() => Math.random() - 0.5);
|
|
123
143
|
il.unshift('START');
|
|
124
144
|
il.push('FINISH');
|
|
125
|
-
setInstructionList(il);
|
|
126
145
|
setInitialState({
|
|
127
146
|
brightnessLow: false,
|
|
128
147
|
faceDetected: false,
|
|
@@ -195,6 +214,13 @@ const LivenessDetectionScreen = () => {
|
|
|
195
214
|
const rightOpen = face.rightEyeOpenProbability ?? 0;
|
|
196
215
|
return leftOpen >= 0.8 && rightOpen >= 0.8;
|
|
197
216
|
};
|
|
217
|
+
const areEyesVisible = face => {
|
|
218
|
+
// Relaxed check: eyes just need to be detected (not fully closed).
|
|
219
|
+
// Smiling naturally causes squinting, so a lower threshold is used.
|
|
220
|
+
const leftOpen = face.leftEyeOpenProbability ?? 0;
|
|
221
|
+
const rightOpen = face.rightEyeOpenProbability ?? 0;
|
|
222
|
+
return leftOpen >= 0.3 && rightOpen >= 0.3;
|
|
223
|
+
};
|
|
198
224
|
const instructionReducer = (state, action) => {
|
|
199
225
|
switch (action.type) {
|
|
200
226
|
case 'RESET':
|
|
@@ -386,25 +412,56 @@ const LivenessDetectionScreen = () => {
|
|
|
386
412
|
});
|
|
387
413
|
}
|
|
388
414
|
|
|
389
|
-
//
|
|
390
|
-
//
|
|
391
|
-
|
|
415
|
+
// Map the on-screen circle into frame coordinates.
|
|
416
|
+
// Camera uses FILL_CENTER / resizeAspectFill (cover): uniform scale filling
|
|
417
|
+
// the view, cropping overflow symmetrically.
|
|
418
|
+
const coverScale = Math.max(windowWidth / frameWidth, windowHeight / frameHeight);
|
|
419
|
+
const offsetX = (frameWidth - windowWidth / coverScale) / 2;
|
|
420
|
+
const offsetY = (frameHeight - windowHeight / coverScale) / 2;
|
|
392
421
|
const previewRectInFrame = {
|
|
393
|
-
minX:
|
|
394
|
-
minY:
|
|
395
|
-
width:
|
|
396
|
-
height:
|
|
397
|
-
};
|
|
398
|
-
const faceRectSmaller = {
|
|
399
|
-
width: face.bounds.width - PREVIEW_EDGE_OFFSET,
|
|
400
|
-
height: face.bounds.height - PREVIEW_EDGE_OFFSET,
|
|
401
|
-
minY: face.bounds.y + PREVIEW_EDGE_OFFSET / 2,
|
|
402
|
-
minX: face.bounds.x + PREVIEW_EDGE_OFFSET / 2
|
|
422
|
+
minX: PREVIEW_RECT.minX / coverScale + offsetX,
|
|
423
|
+
minY: PREVIEW_RECT.minY / coverScale + offsetY,
|
|
424
|
+
width: PREVIEW_RECT.width / coverScale,
|
|
425
|
+
height: PREVIEW_RECT.height / coverScale
|
|
403
426
|
};
|
|
404
|
-
const
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
427
|
+
const previewSizeInFrame = PREVIEW_RECT.width / coverScale;
|
|
428
|
+
|
|
429
|
+
// Check containment using face center + yaw-stable core radius.
|
|
430
|
+
// When the head turns (yaw), the bounding box grows wider but height stays
|
|
431
|
+
// constant — so min(width, height)/2 gives a stable size that doesn't
|
|
432
|
+
// falsely trigger an outside-circle reset during TURN_HEAD_LEFT/RIGHT.
|
|
433
|
+
const faceCenterX = face.bounds.x + face.bounds.width / 2;
|
|
434
|
+
const faceCenterY = face.bounds.y + face.bounds.height / 2;
|
|
435
|
+
const faceCoreRadius = Math.max(0, Math.min(face.bounds.width, face.bounds.height) / 2 - PREVIEW_EDGE_OFFSET / 2);
|
|
436
|
+
const circleCX = previewRectInFrame.minX + previewRectInFrame.width / 2;
|
|
437
|
+
const circleCY = previewRectInFrame.minY + previewRectInFrame.height / 2;
|
|
438
|
+
const circleR = previewSizeInFrame / 2;
|
|
439
|
+
const faceDx = faceCenterX - circleCX;
|
|
440
|
+
const faceDy = faceCenterY - circleCY;
|
|
441
|
+
const yawAbs = Math.abs(face.yawAngle || 0);
|
|
442
|
+
const yawFactor = Math.min(1, yawAbs / TURN_ANGLE_LIMIT);
|
|
443
|
+
|
|
444
|
+
// General bound tolerance (instruction-agnostic): adapt to head pose and
|
|
445
|
+
// face box deformation so containment remains stable across all actions.
|
|
446
|
+
const faceWidthGrowth = Math.max(0, face.bounds.width - face.bounds.height);
|
|
447
|
+
|
|
448
|
+
// On iOS, close faces tend to appear larger in-frame and lateral head
|
|
449
|
+
// turns shift center more aggressively. Apply an iOS-only proximity boost
|
|
450
|
+
// to horizontal tolerance to avoid false outside-circle resets.
|
|
451
|
+
const faceRadiusRatio = Math.min(1, faceCoreRadius / Math.max(1, circleR));
|
|
452
|
+
const iosProximityBoost = Platform.OS === 'ios' ? Math.max(0, faceRadiusRatio - 0.5) : 0;
|
|
453
|
+
const baseToleranceX = previewSizeInFrame * 0.05;
|
|
454
|
+
const yawToleranceX = face.bounds.width * 0.12 * yawFactor;
|
|
455
|
+
const shapeToleranceX = faceWidthGrowth * 0.1;
|
|
456
|
+
const iosToleranceX = face.bounds.width * 0.2 * iosProximityBoost;
|
|
457
|
+
const toleranceX = Math.max(0, baseToleranceX + yawToleranceX + shapeToleranceX + iosToleranceX, face.bounds.width * 0.05);
|
|
458
|
+
const pitchAbs = Math.abs(face.pitchAngle || 0);
|
|
459
|
+
const pitchFactor = Math.min(1, pitchAbs / TURN_ANGLE_LIMIT);
|
|
460
|
+
const toleranceY = Math.max(0, previewSizeInFrame * 0.03 + face.bounds.height * 0.03 * pitchFactor, face.bounds.height * 0.04);
|
|
461
|
+
const allowedRadiusX = Math.max(1, circleR - faceCoreRadius + toleranceX);
|
|
462
|
+
const allowedRadiusY = Math.max(1, circleR - faceCoreRadius + toleranceY);
|
|
463
|
+
const normalizedDistance = faceDx * faceDx / (allowedRadiusX * allowedRadiusX) + faceDy * faceDy / (allowedRadiusY * allowedRadiusY);
|
|
464
|
+
const previewContainsFace = normalizedDistance <= 1;
|
|
408
465
|
const multipleFacesDetected = faces.length > 1;
|
|
409
466
|
if (!isImageBright) {
|
|
410
467
|
// Brightness too low - reset progress if we've started the flow
|
|
@@ -564,8 +621,9 @@ const LivenessDetectionScreen = () => {
|
|
|
564
621
|
// Ensure user is looking at camera (face direction check)
|
|
565
622
|
const isFacingCamera = instructions.SMILE.minAngle < face.yawAngle && face.yawAngle < instructions.SMILE.maxAngle && instructions.SMILE.minAngle < face.pitchAngle && face.pitchAngle < instructions.SMILE.maxAngle;
|
|
566
623
|
|
|
567
|
-
// Check if smiling with sufficient probability AND looking at camera AND eyes
|
|
568
|
-
|
|
624
|
+
// Check if smiling with sufficient probability AND looking at camera AND eyes visible
|
|
625
|
+
// Use relaxed eye check — smiling naturally causes squinting
|
|
626
|
+
if (smilingProb >= instructions.SMILE.minProbability && isFacingCamera && areEyesVisible(face)) {
|
|
569
627
|
instructions.SMILE.photo = image;
|
|
570
628
|
dispatch({
|
|
571
629
|
type: 'NEXT_INSTRUCTION',
|
|
@@ -711,6 +769,21 @@ const LivenessDetectionScreen = () => {
|
|
|
711
769
|
fill: "white",
|
|
712
770
|
mask: "url(#hole-mask)"
|
|
713
771
|
})]
|
|
772
|
+
}), isRecording && /*#__PURE__*/_jsx(View, {
|
|
773
|
+
style: [styles.recordingIndicatorContainer, {
|
|
774
|
+
top: PREVIEW_RECT.minY - 40
|
|
775
|
+
}],
|
|
776
|
+
children: /*#__PURE__*/_jsxs(View, {
|
|
777
|
+
style: styles.recordingIndicator,
|
|
778
|
+
children: [/*#__PURE__*/_jsx(Animated.View, {
|
|
779
|
+
style: [styles.recordingDot, {
|
|
780
|
+
opacity: recordingDotOpacity
|
|
781
|
+
}]
|
|
782
|
+
}), /*#__PURE__*/_jsx(Text, {
|
|
783
|
+
style: styles.recordingText,
|
|
784
|
+
children: "REC"
|
|
785
|
+
})]
|
|
786
|
+
})
|
|
714
787
|
}), /*#__PURE__*/_jsx(View, {
|
|
715
788
|
style: [styles.instructionsContainerBottom, {
|
|
716
789
|
top: PREVIEW_RECT.minY + PREVIEW_SIZE + 20
|
|
@@ -836,6 +909,33 @@ const styles = StyleSheet.create({
|
|
|
836
909
|
width: '100%',
|
|
837
910
|
zIndex: 1
|
|
838
911
|
},
|
|
912
|
+
recordingIndicatorContainer: {
|
|
913
|
+
position: 'absolute',
|
|
914
|
+
width: '100%',
|
|
915
|
+
alignItems: 'center',
|
|
916
|
+
zIndex: 2
|
|
917
|
+
},
|
|
918
|
+
recordingIndicator: {
|
|
919
|
+
flexDirection: 'row',
|
|
920
|
+
alignItems: 'center',
|
|
921
|
+
gap: 8,
|
|
922
|
+
backgroundColor: 'rgba(0, 0, 0, 0.6)',
|
|
923
|
+
paddingVertical: 6,
|
|
924
|
+
paddingHorizontal: 14,
|
|
925
|
+
borderRadius: 20
|
|
926
|
+
},
|
|
927
|
+
recordingDot: {
|
|
928
|
+
width: 10,
|
|
929
|
+
height: 10,
|
|
930
|
+
borderRadius: 5,
|
|
931
|
+
backgroundColor: '#ef4444'
|
|
932
|
+
},
|
|
933
|
+
recordingText: {
|
|
934
|
+
color: '#ffffff',
|
|
935
|
+
fontSize: 14,
|
|
936
|
+
fontWeight: '700',
|
|
937
|
+
letterSpacing: 1
|
|
938
|
+
},
|
|
839
939
|
guide: {
|
|
840
940
|
flex: 1,
|
|
841
941
|
display: 'flex',
|