omnipay-reactnative-sdk 1.2.1 → 1.2.2-beta.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/README.md +136 -45
- package/lib/commonjs/components/FaceVerification.js +755 -0
- package/lib/commonjs/components/FaceVerification.js.map +1 -0
- package/lib/commonjs/components/OmnipayProvider.js +60 -1
- package/lib/commonjs/components/OmnipayProvider.js.map +1 -1
- package/lib/commonjs/types/faceVerification.js +2 -0
- package/lib/commonjs/types/faceVerification.js.map +1 -0
- package/lib/commonjs/types/index.js +17 -0
- package/lib/commonjs/types/index.js.map +1 -0
- package/lib/module/components/FaceVerification.js +746 -0
- package/lib/module/components/FaceVerification.js.map +1 -0
- package/lib/module/components/OmnipayProvider.js +60 -1
- package/lib/module/components/OmnipayProvider.js.map +1 -1
- package/lib/module/types/faceVerification.js +2 -0
- package/lib/module/types/faceVerification.js.map +1 -0
- package/lib/module/types/index.js +2 -0
- package/lib/module/types/index.js.map +1 -0
- package/lib/typescript/components/FaceVerification.d.ts +10 -0
- package/lib/typescript/components/FaceVerification.d.ts.map +1 -0
- package/lib/typescript/components/OmnipayProvider.d.ts.map +1 -1
- package/lib/typescript/types/faceVerification.d.ts +18 -0
- package/lib/typescript/types/faceVerification.d.ts.map +1 -0
- package/lib/typescript/types/index.d.ts +2 -0
- package/lib/typescript/types/index.d.ts.map +1 -0
- package/package.json +10 -4
- package/src/components/FaceVerification.tsx +884 -0
- package/src/components/OmnipayProvider.tsx +69 -0
- package/src/types/faceVerification.ts +27 -0
- package/src/types/index.ts +1 -0
|
@@ -0,0 +1,755 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = void 0;
|
|
7
|
+
var _react = _interopRequireWildcard(require("react"));
|
|
8
|
+
var _reactNative = require("react-native");
|
|
9
|
+
var _reactNativeVisionCamera = require("react-native-vision-camera");
|
|
10
|
+
var _reactNativeVisionCameraFaceDetector = require("react-native-vision-camera-face-detector");
|
|
11
|
+
var _reactNativeSvg = _interopRequireWildcard(require("react-native-svg"));
|
|
12
|
+
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
|
|
13
|
+
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
|
|
14
|
+
const AnimatedCircle = _reactNative.Animated.createAnimatedComponent(_reactNativeSvg.Circle);
|
|
15
|
+
const FaceVerification = _ref => {
|
|
16
|
+
let {
|
|
17
|
+
onSuccess,
|
|
18
|
+
onFailure,
|
|
19
|
+
onCancel,
|
|
20
|
+
onImageCaptured
|
|
21
|
+
} = _ref;
|
|
22
|
+
const device = (0, _reactNativeVisionCamera.useCameraDevice)('front');
|
|
23
|
+
const faceDetectionOptions = (0, _react.useRef)({
|
|
24
|
+
landmarkMode: 'all',
|
|
25
|
+
classificationMode: 'all'
|
|
26
|
+
}).current;
|
|
27
|
+
const photoFormat = (0, _reactNativeVisionCamera.useCameraFormat)(device, [{
|
|
28
|
+
photoResolution: {
|
|
29
|
+
width: 1280,
|
|
30
|
+
height: 720
|
|
31
|
+
}
|
|
32
|
+
}]);
|
|
33
|
+
const {
|
|
34
|
+
hasPermission,
|
|
35
|
+
requestPermission
|
|
36
|
+
} = (0, _reactNativeVisionCamera.useCameraPermission)();
|
|
37
|
+
const spinValue = (0, _react.useRef)(new _reactNative.Animated.Value(0)).current;
|
|
38
|
+
const progressValue = (0, _react.useRef)(new _reactNative.Animated.Value(955)).current; // 955 = circle circumference for r=152
|
|
39
|
+
|
|
40
|
+
const [isCameraActive, setIsCameraActive] = (0, _react.useState)(false);
|
|
41
|
+
const [isLoading, setIsLoading] = (0, _react.useState)(false);
|
|
42
|
+
const [permissionDenied, setPermissionDenied] = (0, _react.useState)(false);
|
|
43
|
+
const [isInitializingCamera, setIsInitializingCamera] = (0, _react.useState)(true);
|
|
44
|
+
const [currentStep, setCurrentStep] = (0, _react.useState)('position_face');
|
|
45
|
+
const [isCapturing, setIsCapturing] = (0, _react.useState)(false);
|
|
46
|
+
const [capturedImage, setCapturedImage] = (0, _react.useState)(null);
|
|
47
|
+
const frameCountRef = (0, _react.useRef)(0);
|
|
48
|
+
const finalPositionFrameCountRef = (0, _react.useRef)(0);
|
|
49
|
+
const faceHistoryRef = (0, _react.useRef)([]);
|
|
50
|
+
const cameraRef = (0, _react.useRef)(null);
|
|
51
|
+
|
|
52
|
+
// RAF optimization: buffer latest face data and process on animation frames
|
|
53
|
+
const latestFaceDataRef = (0, _react.useRef)(null);
|
|
54
|
+
const rafIdRef = (0, _react.useRef)(null);
|
|
55
|
+
const isProcessingRef = (0, _react.useRef)(false);
|
|
56
|
+
|
|
57
|
+
// Handle camera device initialization and auto-start
|
|
58
|
+
(0, _react.useEffect)(() => {
|
|
59
|
+
if (device !== undefined) {
|
|
60
|
+
setIsInitializingCamera(false);
|
|
61
|
+
|
|
62
|
+
// If permissions are already granted, start camera immediately
|
|
63
|
+
if (hasPermission && !isCameraActive && !permissionDenied && !capturedImage) {
|
|
64
|
+
setIsCameraActive(true);
|
|
65
|
+
progressValue.setValue(955);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}, [device, hasPermission, isCameraActive, permissionDenied, capturedImage, progressValue]);
|
|
69
|
+
|
|
70
|
+
// Start loading animation during camera initialization
|
|
71
|
+
(0, _react.useEffect)(() => {
|
|
72
|
+
if (isInitializingCamera) {
|
|
73
|
+
setIsLoading(true);
|
|
74
|
+
} else {
|
|
75
|
+
setIsLoading(false);
|
|
76
|
+
}
|
|
77
|
+
}, [isInitializingCamera]);
|
|
78
|
+
(0, _react.useEffect)(() => {
|
|
79
|
+
const spin = _reactNative.Animated.loop(_reactNative.Animated.timing(spinValue, {
|
|
80
|
+
toValue: 1,
|
|
81
|
+
duration: 1000,
|
|
82
|
+
useNativeDriver: true
|
|
83
|
+
}));
|
|
84
|
+
if (isLoading) {
|
|
85
|
+
spin.start();
|
|
86
|
+
} else {
|
|
87
|
+
spin.stop();
|
|
88
|
+
spinValue.setValue(0);
|
|
89
|
+
}
|
|
90
|
+
return () => spin.stop();
|
|
91
|
+
}, [isLoading, spinValue]);
|
|
92
|
+
(0, _react.useEffect)(() => {
|
|
93
|
+
const progressPercentage = calculateProgress();
|
|
94
|
+
const strokeDasharray = 955;
|
|
95
|
+
const targetOffset = strokeDasharray - progressPercentage / 100 * strokeDasharray;
|
|
96
|
+
if (isCameraActive && progressPercentage >= 0) {
|
|
97
|
+
_reactNative.Animated.timing(progressValue, {
|
|
98
|
+
toValue: targetOffset,
|
|
99
|
+
duration: 800,
|
|
100
|
+
useNativeDriver: false
|
|
101
|
+
}).start();
|
|
102
|
+
}
|
|
103
|
+
}, [currentStep, progressValue, isCameraActive]);
|
|
104
|
+
|
|
105
|
+
// RAF-based face processing to throttle heavy computations
|
|
106
|
+
const processFaceData = () => {
|
|
107
|
+
if (!latestFaceDataRef.current || isProcessingRef.current) {
|
|
108
|
+
rafIdRef.current = null;
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
isProcessingRef.current = true;
|
|
112
|
+
const {
|
|
113
|
+
faces
|
|
114
|
+
} = latestFaceDataRef.current;
|
|
115
|
+
|
|
116
|
+
// Clear the buffer since we're processing this data
|
|
117
|
+
latestFaceDataRef.current = null;
|
|
118
|
+
try {
|
|
119
|
+
handleFaceDetectionLogic(faces);
|
|
120
|
+
} finally {
|
|
121
|
+
isProcessingRef.current = false;
|
|
122
|
+
rafIdRef.current = null;
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
// Cleanup RAF on unmount
|
|
127
|
+
(0, _react.useEffect)(() => {
|
|
128
|
+
return () => {
|
|
129
|
+
if (rafIdRef.current) {
|
|
130
|
+
cancelAnimationFrame(rafIdRef.current);
|
|
131
|
+
}
|
|
132
|
+
};
|
|
133
|
+
}, []);
|
|
134
|
+
const getInstructionText = () => {
|
|
135
|
+
switch (currentStep) {
|
|
136
|
+
case 'position_face':
|
|
137
|
+
return 'Position your face in the frame';
|
|
138
|
+
case 'blink':
|
|
139
|
+
return 'Please blink your eyes';
|
|
140
|
+
case 'smile':
|
|
141
|
+
return 'Now smile';
|
|
142
|
+
case 'final_position':
|
|
143
|
+
return 'Look straight at the camera and hold still';
|
|
144
|
+
case 'complete':
|
|
145
|
+
return '';
|
|
146
|
+
default:
|
|
147
|
+
return 'Position your face in the frame';
|
|
148
|
+
}
|
|
149
|
+
};
|
|
150
|
+
const calculateProgress = () => {
|
|
151
|
+
switch (currentStep) {
|
|
152
|
+
case 'position_face':
|
|
153
|
+
return 10;
|
|
154
|
+
case 'blink':
|
|
155
|
+
return 30;
|
|
156
|
+
case 'smile':
|
|
157
|
+
return 60;
|
|
158
|
+
case 'final_position':
|
|
159
|
+
return 80;
|
|
160
|
+
case 'complete':
|
|
161
|
+
return 100;
|
|
162
|
+
default:
|
|
163
|
+
return 0;
|
|
164
|
+
}
|
|
165
|
+
};
|
|
166
|
+
const detectBlink = () => {
|
|
167
|
+
if (frameCountRef.current < 20 || faceHistoryRef.current.length < 4) return false;
|
|
168
|
+
const threshold = {
|
|
169
|
+
eyeOpen: 0.5,
|
|
170
|
+
eyeClosed: 0.3
|
|
171
|
+
};
|
|
172
|
+
const recentFrames = faceHistoryRef.current.slice(-4);
|
|
173
|
+
for (let i = 0; i < recentFrames.length - 1; i++) {
|
|
174
|
+
const frame1 = recentFrames[i];
|
|
175
|
+
const frame2 = recentFrames[i + 1];
|
|
176
|
+
if (!frame1 || !frame2) continue;
|
|
177
|
+
const eyesWereOpen = frame1.leftEyeOpenProbability > threshold.eyeOpen && frame1.rightEyeOpenProbability > threshold.eyeOpen;
|
|
178
|
+
const eyesAreClosed = frame2.leftEyeOpenProbability < threshold.eyeClosed && frame2.rightEyeOpenProbability < threshold.eyeClosed;
|
|
179
|
+
if (eyesWereOpen && eyesAreClosed) {
|
|
180
|
+
return true;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
return false;
|
|
184
|
+
};
|
|
185
|
+
const detectSmile = face => {
|
|
186
|
+
if (frameCountRef.current < 20 || faceHistoryRef.current.length < 3) return false;
|
|
187
|
+
const threshold = 0.7;
|
|
188
|
+
const currentSmiling = face.smilingProbability > threshold;
|
|
189
|
+
const recentFrames = faceHistoryRef.current.slice(-3);
|
|
190
|
+
const hadNotSmilingFrames = recentFrames.some(frame => frame.smilingProbability < 0.4);
|
|
191
|
+
return currentSmiling && hadNotSmilingFrames;
|
|
192
|
+
};
|
|
193
|
+
const isInFinalPosition = face => {
|
|
194
|
+
const isLookingStraight = Math.abs(face.yawAngle) < 15;
|
|
195
|
+
const eyesOpen = face.leftEyeOpenProbability > 0.5 && face.rightEyeOpenProbability > 0.5;
|
|
196
|
+
const isNotSmiling = face.smilingProbability < 0.1;
|
|
197
|
+
return isLookingStraight && eyesOpen && isNotSmiling;
|
|
198
|
+
};
|
|
199
|
+
|
|
200
|
+
// Fast callback that just buffers data - called by camera at high frequency
|
|
201
|
+
function handleFacesDetection(faces, frame) {
|
|
202
|
+
// Store the latest face data
|
|
203
|
+
latestFaceDataRef.current = {
|
|
204
|
+
faces,
|
|
205
|
+
frame
|
|
206
|
+
};
|
|
207
|
+
|
|
208
|
+
// Schedule processing on next animation frame if not already scheduled
|
|
209
|
+
if (!rafIdRef.current) {
|
|
210
|
+
rafIdRef.current = requestAnimationFrame(processFaceData);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// Heavy processing logic - called at animation frame rate (60fps max)
|
|
215
|
+
function handleFaceDetectionLogic(faces) {
|
|
216
|
+
if (faces.length === 0) {
|
|
217
|
+
if (currentStep !== 'position_face' && currentStep !== 'complete') {
|
|
218
|
+
setCurrentStep('position_face');
|
|
219
|
+
frameCountRef.current = 0;
|
|
220
|
+
faceHistoryRef.current = [];
|
|
221
|
+
finalPositionFrameCountRef.current = 0;
|
|
222
|
+
}
|
|
223
|
+
return;
|
|
224
|
+
}
|
|
225
|
+
const face = faces[0];
|
|
226
|
+
if (!face) return;
|
|
227
|
+
frameCountRef.current++;
|
|
228
|
+
faceHistoryRef.current = [...faceHistoryRef.current.slice(-7), face];
|
|
229
|
+
switch (currentStep) {
|
|
230
|
+
case 'position_face':
|
|
231
|
+
if (frameCountRef.current > 10) {
|
|
232
|
+
setCurrentStep('blink');
|
|
233
|
+
}
|
|
234
|
+
break;
|
|
235
|
+
case 'blink':
|
|
236
|
+
if (detectBlink()) {
|
|
237
|
+
setCurrentStep('smile');
|
|
238
|
+
}
|
|
239
|
+
break;
|
|
240
|
+
case 'smile':
|
|
241
|
+
if (detectSmile(face)) {
|
|
242
|
+
setCurrentStep('final_position');
|
|
243
|
+
}
|
|
244
|
+
break;
|
|
245
|
+
case 'final_position':
|
|
246
|
+
if (isInFinalPosition(face)) {
|
|
247
|
+
finalPositionFrameCountRef.current++;
|
|
248
|
+
// Require 5 consecutive frames for stability before capturing
|
|
249
|
+
if (finalPositionFrameCountRef.current >= 5) {
|
|
250
|
+
setCurrentStep('complete');
|
|
251
|
+
captureCurrentFrame();
|
|
252
|
+
}
|
|
253
|
+
} else {
|
|
254
|
+
finalPositionFrameCountRef.current = 0;
|
|
255
|
+
}
|
|
256
|
+
break;
|
|
257
|
+
default:
|
|
258
|
+
break;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
const captureCurrentFrame = async () => {
|
|
262
|
+
if (isCapturing || !cameraRef.current) return;
|
|
263
|
+
try {
|
|
264
|
+
setIsCapturing(true);
|
|
265
|
+
const photo = await cameraRef.current.takePhoto({
|
|
266
|
+
enableShutterSound: false
|
|
267
|
+
});
|
|
268
|
+
const response = await fetch(`file://${photo.path}`);
|
|
269
|
+
const blob = await response.blob();
|
|
270
|
+
const reader = new FileReader();
|
|
271
|
+
reader.onloadend = () => {
|
|
272
|
+
const base64String = reader.result;
|
|
273
|
+
setCapturedImage(base64String);
|
|
274
|
+
setIsCameraActive(false);
|
|
275
|
+
};
|
|
276
|
+
reader.readAsDataURL(blob);
|
|
277
|
+
} catch (error) {
|
|
278
|
+
onFailure === null || onFailure === void 0 ? void 0 : onFailure();
|
|
279
|
+
} finally {
|
|
280
|
+
setIsCapturing(false);
|
|
281
|
+
}
|
|
282
|
+
};
|
|
283
|
+
const handleContinue = () => {
|
|
284
|
+
if (capturedImage) {
|
|
285
|
+
const base64String = capturedImage.replace(/^data:image\/[a-z]+;base64,/, '');
|
|
286
|
+
|
|
287
|
+
// Call onImageCaptured immediately for UI feedback
|
|
288
|
+
onImageCaptured === null || onImageCaptured === void 0 ? void 0 : onImageCaptured(base64String);
|
|
289
|
+
|
|
290
|
+
// Still call onSuccess for backward compatibility
|
|
291
|
+
onSuccess === null || onSuccess === void 0 ? void 0 : onSuccess(base64String);
|
|
292
|
+
}
|
|
293
|
+
};
|
|
294
|
+
const handleRetake = () => {
|
|
295
|
+
setCurrentStep('position_face');
|
|
296
|
+
faceHistoryRef.current = [];
|
|
297
|
+
frameCountRef.current = 0;
|
|
298
|
+
setCapturedImage(null);
|
|
299
|
+
finalPositionFrameCountRef.current = 0;
|
|
300
|
+
progressValue.setValue(955);
|
|
301
|
+
setIsCameraActive(true);
|
|
302
|
+
setIsLoading(true);
|
|
303
|
+
setTimeout(() => {
|
|
304
|
+
setIsLoading(false);
|
|
305
|
+
}, 1000);
|
|
306
|
+
};
|
|
307
|
+
const startCamera = async () => {
|
|
308
|
+
setIsLoading(true);
|
|
309
|
+
setPermissionDenied(false);
|
|
310
|
+
try {
|
|
311
|
+
const permission = await requestPermission();
|
|
312
|
+
if (permission === true) {
|
|
313
|
+
setIsCameraActive(true);
|
|
314
|
+
progressValue.setValue(955);
|
|
315
|
+
setTimeout(() => {
|
|
316
|
+
setIsLoading(false);
|
|
317
|
+
}, 1000);
|
|
318
|
+
} else {
|
|
319
|
+
setPermissionDenied(true);
|
|
320
|
+
setIsLoading(false);
|
|
321
|
+
}
|
|
322
|
+
} catch (error) {
|
|
323
|
+
setPermissionDenied(true);
|
|
324
|
+
setIsLoading(false);
|
|
325
|
+
}
|
|
326
|
+
};
|
|
327
|
+
const openSettings = () => {
|
|
328
|
+
if (_reactNative.Platform.OS === 'ios') {
|
|
329
|
+
_reactNative.Linking.openURL('app-settings:');
|
|
330
|
+
} else {
|
|
331
|
+
_reactNative.Linking.openSettings();
|
|
332
|
+
}
|
|
333
|
+
};
|
|
334
|
+
if (permissionDenied) {
|
|
335
|
+
return /*#__PURE__*/_react.default.createElement(_reactNative.View, {
|
|
336
|
+
style: [styles.container]
|
|
337
|
+
}, /*#__PURE__*/_react.default.createElement(_reactNative.View, {
|
|
338
|
+
style: styles.centeredContainer
|
|
339
|
+
}, /*#__PURE__*/_react.default.createElement(_reactNative.View, {
|
|
340
|
+
style: styles.permissionDeniedContainer
|
|
341
|
+
}, /*#__PURE__*/_react.default.createElement(_reactNative.Text, {
|
|
342
|
+
style: styles.permissionDeniedTitle
|
|
343
|
+
}, "Camera Access Required"), /*#__PURE__*/_react.default.createElement(_reactNative.Text, {
|
|
344
|
+
style: styles.permissionDeniedText
|
|
345
|
+
}, "This app needs camera access to verify your identity. Please allow camera permission in your device settings."), /*#__PURE__*/_react.default.createElement(_reactNative.View, {
|
|
346
|
+
style: styles.permissionActions
|
|
347
|
+
}, /*#__PURE__*/_react.default.createElement(_reactNative.TouchableOpacity, {
|
|
348
|
+
style: styles.settingsButton,
|
|
349
|
+
onPress: openSettings
|
|
350
|
+
}, /*#__PURE__*/_react.default.createElement(_reactNative.Text, {
|
|
351
|
+
style: styles.settingsButtonText
|
|
352
|
+
}, "Open Settings")), /*#__PURE__*/_react.default.createElement(_reactNative.TouchableOpacity, {
|
|
353
|
+
style: styles.retryButton,
|
|
354
|
+
onPress: () => setPermissionDenied(false)
|
|
355
|
+
}, /*#__PURE__*/_react.default.createElement(_reactNative.Text, {
|
|
356
|
+
style: styles.retryButtonText
|
|
357
|
+
}, "Try Again"))))));
|
|
358
|
+
}
|
|
359
|
+
if (isInitializingCamera || device === undefined) {
|
|
360
|
+
const spin = spinValue.interpolate({
|
|
361
|
+
inputRange: [0, 1],
|
|
362
|
+
outputRange: ['0deg', '360deg']
|
|
363
|
+
});
|
|
364
|
+
return /*#__PURE__*/_react.default.createElement(_reactNative.View, {
|
|
365
|
+
style: [styles.container]
|
|
366
|
+
}, /*#__PURE__*/_react.default.createElement(_reactNative.View, {
|
|
367
|
+
style: styles.centeredContainer
|
|
368
|
+
}, /*#__PURE__*/_react.default.createElement(_reactNative.View, {
|
|
369
|
+
style: styles.loadingContainer
|
|
370
|
+
}, /*#__PURE__*/_react.default.createElement(_reactNative.Animated.View, {
|
|
371
|
+
style: [styles.loadingSpinner, {
|
|
372
|
+
transform: [{
|
|
373
|
+
rotate: spin
|
|
374
|
+
}]
|
|
375
|
+
}]
|
|
376
|
+
}), /*#__PURE__*/_react.default.createElement(_reactNative.Text, {
|
|
377
|
+
style: styles.loadingText
|
|
378
|
+
}, isInitializingCamera ? 'Initializing camera...' : 'No camera device available'))));
|
|
379
|
+
}
|
|
380
|
+
const strokeDasharray = 955;
|
|
381
|
+
const spin = spinValue.interpolate({
|
|
382
|
+
inputRange: [0, 1],
|
|
383
|
+
outputRange: ['0deg', '360deg']
|
|
384
|
+
});
|
|
385
|
+
return /*#__PURE__*/_react.default.createElement(_reactNative.View, {
|
|
386
|
+
style: [styles.container]
|
|
387
|
+
}, /*#__PURE__*/_react.default.createElement(_reactNative.View, {
|
|
388
|
+
style: styles.centeredContainer
|
|
389
|
+
}, isLoading ? /*#__PURE__*/_react.default.createElement(_reactNative.View, {
|
|
390
|
+
style: styles.loadingContainer
|
|
391
|
+
}, /*#__PURE__*/_react.default.createElement(_reactNative.Animated.View, {
|
|
392
|
+
style: [styles.loadingSpinner, {
|
|
393
|
+
transform: [{
|
|
394
|
+
rotate: spin
|
|
395
|
+
}]
|
|
396
|
+
}]
|
|
397
|
+
})) : /*#__PURE__*/_react.default.createElement(_reactNative.View, {
|
|
398
|
+
style: styles.contentContainer
|
|
399
|
+
}, capturedImage ? /*#__PURE__*/_react.default.createElement(_reactNative.View, {
|
|
400
|
+
style: styles.capturedImageContainer
|
|
401
|
+
}, /*#__PURE__*/_react.default.createElement(_reactNative.View, {
|
|
402
|
+
style: styles.capturedImageWrapper
|
|
403
|
+
}, /*#__PURE__*/_react.default.createElement(_reactNative.Image, {
|
|
404
|
+
source: {
|
|
405
|
+
uri: capturedImage
|
|
406
|
+
},
|
|
407
|
+
style: styles.capturedImage,
|
|
408
|
+
resizeMode: "cover"
|
|
409
|
+
})), /*#__PURE__*/_react.default.createElement(_reactNative.View, {
|
|
410
|
+
style: styles.capturedImageActions
|
|
411
|
+
}, /*#__PURE__*/_react.default.createElement(_reactNative.TouchableOpacity, {
|
|
412
|
+
style: styles.continueButton,
|
|
413
|
+
onPress: handleContinue
|
|
414
|
+
}, /*#__PURE__*/_react.default.createElement(_reactNative.Text, {
|
|
415
|
+
style: styles.continueButtonText
|
|
416
|
+
}, "Continue")), /*#__PURE__*/_react.default.createElement(_reactNative.TouchableOpacity, {
|
|
417
|
+
style: styles.retakeButton,
|
|
418
|
+
onPress: handleRetake
|
|
419
|
+
}, /*#__PURE__*/_react.default.createElement(_reactNative.Text, {
|
|
420
|
+
style: styles.retakeButtonText
|
|
421
|
+
}, "Retake")))) : /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement(_reactNative.View, {
|
|
422
|
+
style: styles.captureSection
|
|
423
|
+
}, /*#__PURE__*/_react.default.createElement(_reactNative.View, {
|
|
424
|
+
style: styles.captureBackground
|
|
425
|
+
}, isCameraActive ? /*#__PURE__*/_react.default.createElement(_reactNativeVisionCameraFaceDetector.Camera, {
|
|
426
|
+
ref: cameraRef,
|
|
427
|
+
device: device,
|
|
428
|
+
isActive: true,
|
|
429
|
+
style: styles.camera,
|
|
430
|
+
faceDetectionCallback: handleFacesDetection,
|
|
431
|
+
faceDetectionOptions: faceDetectionOptions,
|
|
432
|
+
photo: true,
|
|
433
|
+
format: photoFormat
|
|
434
|
+
}) : /*#__PURE__*/_react.default.createElement(_reactNative.View, {
|
|
435
|
+
style: styles.avatarPlaceholder
|
|
436
|
+
}, /*#__PURE__*/_react.default.createElement(_reactNative.Text, {
|
|
437
|
+
style: styles.avatarText
|
|
438
|
+
}, "\uD83D\uDC64"))), isCameraActive && /*#__PURE__*/_react.default.createElement(_reactNative.View, {
|
|
439
|
+
style: styles.progressRingContainer
|
|
440
|
+
}, /*#__PURE__*/_react.default.createElement(_reactNativeSvg.default, {
|
|
441
|
+
width: 320,
|
|
442
|
+
height: 320,
|
|
443
|
+
viewBox: "0 0 320 320",
|
|
444
|
+
style: styles.progressRing
|
|
445
|
+
}, /*#__PURE__*/_react.default.createElement(_reactNativeSvg.Circle, {
|
|
446
|
+
cx: 160,
|
|
447
|
+
cy: 160,
|
|
448
|
+
r: 150,
|
|
449
|
+
stroke: "#E5E7EB",
|
|
450
|
+
strokeWidth: "0",
|
|
451
|
+
fill: "none"
|
|
452
|
+
}), /*#__PURE__*/_react.default.createElement(AnimatedCircle, {
|
|
453
|
+
cx: 160,
|
|
454
|
+
cy: 160,
|
|
455
|
+
r: 152,
|
|
456
|
+
stroke: "#214287",
|
|
457
|
+
strokeWidth: 6,
|
|
458
|
+
fill: "none",
|
|
459
|
+
strokeDasharray: strokeDasharray,
|
|
460
|
+
strokeDashoffset: progressValue,
|
|
461
|
+
strokeLinecap: "round"
|
|
462
|
+
}))), !isCameraActive && /*#__PURE__*/_react.default.createElement(_reactNative.View, {
|
|
463
|
+
style: styles.cameraIconSection
|
|
464
|
+
}, /*#__PURE__*/_react.default.createElement(_reactNative.View, {
|
|
465
|
+
style: styles.cameraIconContainer
|
|
466
|
+
}, /*#__PURE__*/_react.default.createElement(_reactNative.Text, {
|
|
467
|
+
style: styles.cameraIcon
|
|
468
|
+
}, "\uD83D\uDCF7")))), isCameraActive && /*#__PURE__*/_react.default.createElement(_reactNative.View, {
|
|
469
|
+
style: styles.instructionContainer
|
|
470
|
+
}, /*#__PURE__*/_react.default.createElement(_reactNative.Text, {
|
|
471
|
+
style: styles.instructionText
|
|
472
|
+
}, getInstructionText())), !isCameraActive && !hasPermission && /*#__PURE__*/_react.default.createElement(_reactNative.View, {
|
|
473
|
+
style: styles.startContainer
|
|
474
|
+
}, /*#__PURE__*/_react.default.createElement(_reactNative.TouchableOpacity, {
|
|
475
|
+
style: styles.startButton,
|
|
476
|
+
onPress: startCamera
|
|
477
|
+
}, /*#__PURE__*/_react.default.createElement(_reactNative.Text, {
|
|
478
|
+
style: styles.startButtonText
|
|
479
|
+
}, "Proceed")))))), /*#__PURE__*/_react.default.createElement(_reactNative.TouchableOpacity, {
|
|
480
|
+
style: styles.closeButton,
|
|
481
|
+
onPress: onCancel
|
|
482
|
+
}, /*#__PURE__*/_react.default.createElement(_reactNative.Text, {
|
|
483
|
+
style: styles.closeButtonText
|
|
484
|
+
}, "\u2715")));
|
|
485
|
+
};
|
|
486
|
+
const styles = _reactNative.StyleSheet.create({
|
|
487
|
+
container: {
|
|
488
|
+
flex: 1,
|
|
489
|
+
marginHorizontal: 'auto',
|
|
490
|
+
width: '100%'
|
|
491
|
+
},
|
|
492
|
+
centeredContainer: {
|
|
493
|
+
flex: 1,
|
|
494
|
+
alignSelf: 'center',
|
|
495
|
+
justifyContent: 'center',
|
|
496
|
+
width: '100%',
|
|
497
|
+
paddingHorizontal: 0,
|
|
498
|
+
paddingBottom: 40,
|
|
499
|
+
paddingTop: 20
|
|
500
|
+
},
|
|
501
|
+
contentContainer: {
|
|
502
|
+
flex: 1,
|
|
503
|
+
alignItems: 'center',
|
|
504
|
+
justifyContent: 'flex-start',
|
|
505
|
+
gap: 16
|
|
506
|
+
},
|
|
507
|
+
captureSection: {
|
|
508
|
+
justifyContent: 'flex-start',
|
|
509
|
+
alignItems: 'center',
|
|
510
|
+
position: 'relative',
|
|
511
|
+
width: 320
|
|
512
|
+
},
|
|
513
|
+
captureBackground: {
|
|
514
|
+
width: 300,
|
|
515
|
+
height: 300,
|
|
516
|
+
backgroundColor: '#F1F5F9',
|
|
517
|
+
overflow: 'hidden',
|
|
518
|
+
position: 'relative',
|
|
519
|
+
justifyContent: 'center',
|
|
520
|
+
alignItems: 'center',
|
|
521
|
+
borderRadius: 150
|
|
522
|
+
},
|
|
523
|
+
camera: {
|
|
524
|
+
width: '100%',
|
|
525
|
+
height: '100%',
|
|
526
|
+
transform: [{
|
|
527
|
+
scaleX: -1
|
|
528
|
+
}]
|
|
529
|
+
},
|
|
530
|
+
avatarFrame: {
|
|
531
|
+
width: 140,
|
|
532
|
+
height: 140
|
|
533
|
+
},
|
|
534
|
+
avatarPlaceholder: {
|
|
535
|
+
width: 140,
|
|
536
|
+
height: 140,
|
|
537
|
+
justifyContent: 'center',
|
|
538
|
+
alignItems: 'center'
|
|
539
|
+
},
|
|
540
|
+
avatarText: {
|
|
541
|
+
fontSize: 80
|
|
542
|
+
},
|
|
543
|
+
progressRingContainer: {
|
|
544
|
+
position: 'absolute',
|
|
545
|
+
top: '50%',
|
|
546
|
+
left: '50%',
|
|
547
|
+
transform: [{
|
|
548
|
+
translateX: -160
|
|
549
|
+
}, {
|
|
550
|
+
translateY: -160
|
|
551
|
+
}],
|
|
552
|
+
width: 320,
|
|
553
|
+
height: 320
|
|
554
|
+
},
|
|
555
|
+
progressRing: {
|
|
556
|
+
width: '100%',
|
|
557
|
+
height: '100%'
|
|
558
|
+
},
|
|
559
|
+
cameraIconSection: {
|
|
560
|
+
position: 'absolute',
|
|
561
|
+
top: 240,
|
|
562
|
+
right: 40,
|
|
563
|
+
width: 42,
|
|
564
|
+
height: 42,
|
|
565
|
+
borderRadius: 21,
|
|
566
|
+
backgroundColor: '#ffffff',
|
|
567
|
+
justifyContent: 'center',
|
|
568
|
+
alignItems: 'center'
|
|
569
|
+
},
|
|
570
|
+
cameraIconContainer: {
|
|
571
|
+
width: 38,
|
|
572
|
+
height: 38,
|
|
573
|
+
borderRadius: 19,
|
|
574
|
+
backgroundColor: '#214287',
|
|
575
|
+
justifyContent: 'center',
|
|
576
|
+
alignItems: 'center'
|
|
577
|
+
},
|
|
578
|
+
cameraIcon: {
|
|
579
|
+
fontSize: 16,
|
|
580
|
+
color: '#ffffff'
|
|
581
|
+
},
|
|
582
|
+
instructionContainer: {
|
|
583
|
+
marginBottom: 16,
|
|
584
|
+
paddingHorizontal: 20,
|
|
585
|
+
alignItems: 'center'
|
|
586
|
+
},
|
|
587
|
+
instructionText: {
|
|
588
|
+
fontSize: 16,
|
|
589
|
+
color: '#667085',
|
|
590
|
+
textAlign: 'center',
|
|
591
|
+
lineHeight: 24
|
|
592
|
+
},
|
|
593
|
+
startContainer: {
|
|
594
|
+
alignItems: 'center',
|
|
595
|
+
marginTop: 24
|
|
596
|
+
},
|
|
597
|
+
startButton: {
|
|
598
|
+
backgroundColor: '#214287',
|
|
599
|
+
borderRadius: 10,
|
|
600
|
+
padding: 15,
|
|
601
|
+
alignItems: 'center',
|
|
602
|
+
minWidth: 250
|
|
603
|
+
},
|
|
604
|
+
startButtonText: {
|
|
605
|
+
color: '#ffffff',
|
|
606
|
+
fontSize: 16,
|
|
607
|
+
fontWeight: '600',
|
|
608
|
+
textAlign: 'center'
|
|
609
|
+
},
|
|
610
|
+
loadingContainer: {
|
|
611
|
+
flex: 1,
|
|
612
|
+
justifyContent: 'center',
|
|
613
|
+
alignItems: 'center',
|
|
614
|
+
paddingVertical: 50
|
|
615
|
+
},
|
|
616
|
+
loadingSpinner: {
|
|
617
|
+
width: 48,
|
|
618
|
+
height: 48,
|
|
619
|
+
borderRadius: 24,
|
|
620
|
+
borderWidth: 4,
|
|
621
|
+
borderColor: '#e5e7eb',
|
|
622
|
+
borderTopColor: '#214287',
|
|
623
|
+
marginBottom: 16
|
|
624
|
+
},
|
|
625
|
+
loadingText: {
|
|
626
|
+
fontSize: 16,
|
|
627
|
+
color: '#667085',
|
|
628
|
+
textAlign: 'center'
|
|
629
|
+
},
|
|
630
|
+
capturedImageContainer: {
|
|
631
|
+
alignItems: 'center',
|
|
632
|
+
justifyContent: 'center',
|
|
633
|
+
gap: 24,
|
|
634
|
+
width: '100%'
|
|
635
|
+
},
|
|
636
|
+
capturedImageWrapper: {
|
|
637
|
+
width: '100%',
|
|
638
|
+
height: 300,
|
|
639
|
+
borderRadius: 12,
|
|
640
|
+
overflow: 'hidden',
|
|
641
|
+
backgroundColor: '#F1F5F9',
|
|
642
|
+
shadowColor: '#000',
|
|
643
|
+
shadowOffset: {
|
|
644
|
+
width: 0,
|
|
645
|
+
height: 4
|
|
646
|
+
},
|
|
647
|
+
shadowOpacity: 0.1,
|
|
648
|
+
shadowRadius: 8,
|
|
649
|
+
elevation: 5
|
|
650
|
+
},
|
|
651
|
+
capturedImage: {
|
|
652
|
+
width: '100%',
|
|
653
|
+
height: '100%'
|
|
654
|
+
},
|
|
655
|
+
capturedImageActions: {
|
|
656
|
+
width: '100%',
|
|
657
|
+
gap: 12
|
|
658
|
+
},
|
|
659
|
+
continueButton: {
|
|
660
|
+
backgroundColor: '#214287',
|
|
661
|
+
borderRadius: 10,
|
|
662
|
+
padding: 15,
|
|
663
|
+
alignItems: 'center',
|
|
664
|
+
width: '100%'
|
|
665
|
+
},
|
|
666
|
+
continueButtonText: {
|
|
667
|
+
color: '#ffffff',
|
|
668
|
+
fontSize: 16,
|
|
669
|
+
fontWeight: '600',
|
|
670
|
+
textAlign: 'center'
|
|
671
|
+
},
|
|
672
|
+
retakeButton: {
|
|
673
|
+
borderWidth: 1,
|
|
674
|
+
borderColor: '#214287',
|
|
675
|
+
borderRadius: 10,
|
|
676
|
+
padding: 15,
|
|
677
|
+
alignItems: 'center',
|
|
678
|
+
backgroundColor: 'transparent',
|
|
679
|
+
width: '100%'
|
|
680
|
+
},
|
|
681
|
+
retakeButtonText: {
|
|
682
|
+
color: '#214287',
|
|
683
|
+
fontSize: 16,
|
|
684
|
+
fontWeight: '600',
|
|
685
|
+
textAlign: 'center'
|
|
686
|
+
},
|
|
687
|
+
permissionDeniedContainer: {
|
|
688
|
+
alignItems: 'center'
|
|
689
|
+
},
|
|
690
|
+
permissionDeniedTitle: {
|
|
691
|
+
fontSize: 20,
|
|
692
|
+
fontWeight: '600',
|
|
693
|
+
color: '#333333',
|
|
694
|
+
textAlign: 'center',
|
|
695
|
+
marginBottom: 15
|
|
696
|
+
},
|
|
697
|
+
permissionDeniedText: {
|
|
698
|
+
fontSize: 16,
|
|
699
|
+
color: '#666666',
|
|
700
|
+
textAlign: 'center',
|
|
701
|
+
lineHeight: 24,
|
|
702
|
+
marginBottom: 30
|
|
703
|
+
},
|
|
704
|
+
permissionActions: {
|
|
705
|
+
width: '100%',
|
|
706
|
+
gap: 12
|
|
707
|
+
},
|
|
708
|
+
settingsButton: {
|
|
709
|
+
backgroundColor: '#214287',
|
|
710
|
+
borderRadius: 10,
|
|
711
|
+
padding: 15,
|
|
712
|
+
alignItems: 'center',
|
|
713
|
+
width: '100%'
|
|
714
|
+
},
|
|
715
|
+
settingsButtonText: {
|
|
716
|
+
color: '#ffffff',
|
|
717
|
+
fontSize: 16,
|
|
718
|
+
fontWeight: '600',
|
|
719
|
+
textAlign: 'center'
|
|
720
|
+
},
|
|
721
|
+
retryButton: {
|
|
722
|
+
borderWidth: 1,
|
|
723
|
+
borderColor: '#214287',
|
|
724
|
+
borderRadius: 10,
|
|
725
|
+
padding: 15,
|
|
726
|
+
alignItems: 'center',
|
|
727
|
+
backgroundColor: 'transparent',
|
|
728
|
+
width: '100%'
|
|
729
|
+
},
|
|
730
|
+
retryButtonText: {
|
|
731
|
+
color: '#214287',
|
|
732
|
+
fontSize: 16,
|
|
733
|
+
fontWeight: '600',
|
|
734
|
+
textAlign: 'center'
|
|
735
|
+
},
|
|
736
|
+
closeButton: {
|
|
737
|
+
position: 'absolute',
|
|
738
|
+
top: 50,
|
|
739
|
+
right: 20,
|
|
740
|
+
width: 44,
|
|
741
|
+
height: 44,
|
|
742
|
+
borderRadius: 22,
|
|
743
|
+
backgroundColor: 'rgba(0,0,0,0.5)',
|
|
744
|
+
justifyContent: 'center',
|
|
745
|
+
alignItems: 'center'
|
|
746
|
+
},
|
|
747
|
+
closeButtonText: {
|
|
748
|
+
color: 'white',
|
|
749
|
+
fontSize: 18,
|
|
750
|
+
fontWeight: 'bold'
|
|
751
|
+
}
|
|
752
|
+
});
|
|
753
|
+
var _default = FaceVerification;
|
|
754
|
+
exports.default = _default;
|
|
755
|
+
//# sourceMappingURL=FaceVerification.js.map
|