omnipay-reactnative-sdk 1.2.2-beta.9 → 1.2.3-beta.10

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.
Files changed (97) hide show
  1. package/README.md +58 -48
  2. package/android/build.gradle +4 -7
  3. package/android/src/main/AndroidManifest.xml +0 -5
  4. package/android/src/main/java/com/omniretail/omnipay/FaceVerificationFrameProcessor.kt +111 -0
  5. package/android/src/main/java/com/omniretail/omnipay/OmnipayActivityPackage.java +6 -4
  6. package/ios/FaceVerificationFrameProcessor.swift +138 -0
  7. package/ios/FaceVerificationFrameProcessorPlugin.m +4 -0
  8. package/ios/OmnipayReactnativeSdk.m +5 -0
  9. package/ios/OmnipayReactnativeSdk.swift +10 -0
  10. package/ios/omnipay_reactnative_sdk.h +6 -0
  11. package/lib/commonjs/components/Button.js +68 -0
  12. package/lib/commonjs/components/Button.js.map +1 -0
  13. package/lib/commonjs/components/OmnipayProvider.js +7 -23
  14. package/lib/commonjs/components/OmnipayProvider.js.map +1 -1
  15. package/lib/commonjs/components/biometrics/FaceVerification.js +294 -270
  16. package/lib/commonjs/components/biometrics/FaceVerification.js.map +1 -1
  17. package/lib/commonjs/components/biometrics/useFaceVerification.js +85 -0
  18. package/lib/commonjs/components/biometrics/useFaceVerification.js.map +1 -0
  19. package/lib/commonjs/components/biometrics/useFaceVerificationFlow.js +157 -0
  20. package/lib/commonjs/components/biometrics/useFaceVerificationFlow.js.map +1 -0
  21. package/lib/commonjs/index.js +0 -33
  22. package/lib/commonjs/index.js.map +1 -1
  23. package/lib/module/components/Button.js +61 -0
  24. package/lib/module/components/Button.js.map +1 -0
  25. package/lib/module/components/OmnipayProvider.js +7 -23
  26. package/lib/module/components/OmnipayProvider.js.map +1 -1
  27. package/lib/module/components/biometrics/FaceVerification.js +294 -271
  28. package/lib/module/components/biometrics/FaceVerification.js.map +1 -1
  29. package/lib/module/components/biometrics/useFaceVerification.js +78 -0
  30. package/lib/module/components/biometrics/useFaceVerification.js.map +1 -0
  31. package/lib/module/components/biometrics/useFaceVerificationFlow.js +150 -0
  32. package/lib/module/components/biometrics/useFaceVerificationFlow.js.map +1 -0
  33. package/lib/module/index.js +0 -6
  34. package/lib/module/index.js.map +1 -1
  35. package/lib/typescript/components/Button.d.ts +17 -0
  36. package/lib/typescript/components/Button.d.ts.map +1 -0
  37. package/lib/typescript/components/OmnipayProvider.d.ts.map +1 -1
  38. package/lib/typescript/components/biometrics/FaceVerification.d.ts +1 -3
  39. package/lib/typescript/components/biometrics/FaceVerification.d.ts.map +1 -1
  40. package/lib/typescript/components/biometrics/useFaceVerification.d.ts +38 -0
  41. package/lib/typescript/components/biometrics/useFaceVerification.d.ts.map +1 -0
  42. package/lib/typescript/components/biometrics/useFaceVerificationFlow.d.ts +29 -0
  43. package/lib/typescript/components/biometrics/useFaceVerificationFlow.d.ts.map +1 -0
  44. package/lib/typescript/index.d.ts +0 -2
  45. package/lib/typescript/index.d.ts.map +1 -1
  46. package/omnipay_reactnative_sdk.podspec +46 -0
  47. package/package.json +5 -8
  48. package/src/components/Button.tsx +86 -0
  49. package/src/components/OmnipayProvider.tsx +7 -24
  50. package/src/components/biometrics/FaceVerification.tsx +315 -309
  51. package/src/components/biometrics/useFaceVerification.ts +120 -0
  52. package/src/components/biometrics/useFaceVerificationFlow.ts +224 -0
  53. package/src/index.tsx +0 -7
  54. package/android/src/main/java/com/omniretail/omnipay/OmnipayLivenessCameraView.java +0 -153
  55. package/android/src/main/java/com/omniretail/omnipay/OmnipayLivenessCameraViewManager.java +0 -49
  56. package/android/src/main/java/com/omniretail/omnipay/OmnipayLivenessModule.java +0 -557
  57. package/ios/OmnipayLivenessCameraView.h +0 -15
  58. package/ios/OmnipayLivenessCameraView.m +0 -80
  59. package/ios/OmnipayLivenessCameraViewManager.m +0 -19
  60. package/ios/OmnipayLivenessModule.h +0 -38
  61. package/ios/OmnipayLivenessModule.m +0 -615
  62. package/lib/commonjs/components/biometrics/LivenessDetection.js +0 -149
  63. package/lib/commonjs/components/biometrics/LivenessDetection.js.map +0 -1
  64. package/lib/commonjs/components/biometrics/OmnipayLivenessCameraView.js +0 -15
  65. package/lib/commonjs/components/biometrics/OmnipayLivenessCameraView.js.map +0 -1
  66. package/lib/commonjs/components/biometrics/PermissionManager.js +0 -279
  67. package/lib/commonjs/components/biometrics/PermissionManager.js.map +0 -1
  68. package/lib/commonjs/components/biometrics/index.js +0 -45
  69. package/lib/commonjs/components/biometrics/index.js.map +0 -1
  70. package/lib/commonjs/components/biometrics/types.js +0 -17
  71. package/lib/commonjs/components/biometrics/types.js.map +0 -1
  72. package/lib/module/components/biometrics/LivenessDetection.js +0 -129
  73. package/lib/module/components/biometrics/LivenessDetection.js.map +0 -1
  74. package/lib/module/components/biometrics/OmnipayLivenessCameraView.js +0 -7
  75. package/lib/module/components/biometrics/OmnipayLivenessCameraView.js.map +0 -1
  76. package/lib/module/components/biometrics/PermissionManager.js +0 -272
  77. package/lib/module/components/biometrics/PermissionManager.js.map +0 -1
  78. package/lib/module/components/biometrics/index.js +0 -12
  79. package/lib/module/components/biometrics/index.js.map +0 -1
  80. package/lib/module/components/biometrics/types.js +0 -16
  81. package/lib/module/components/biometrics/types.js.map +0 -1
  82. package/lib/typescript/components/biometrics/LivenessDetection.d.ts +0 -33
  83. package/lib/typescript/components/biometrics/LivenessDetection.d.ts.map +0 -1
  84. package/lib/typescript/components/biometrics/OmnipayLivenessCameraView.d.ts +0 -18
  85. package/lib/typescript/components/biometrics/OmnipayLivenessCameraView.d.ts.map +0 -1
  86. package/lib/typescript/components/biometrics/PermissionManager.d.ts +0 -58
  87. package/lib/typescript/components/biometrics/PermissionManager.d.ts.map +0 -1
  88. package/lib/typescript/components/biometrics/index.d.ts +0 -5
  89. package/lib/typescript/components/biometrics/index.d.ts.map +0 -1
  90. package/lib/typescript/components/biometrics/types.d.ts +0 -73
  91. package/lib/typescript/components/biometrics/types.d.ts.map +0 -1
  92. package/omnipay-reactnative-sdk.podspec +0 -50
  93. package/src/components/biometrics/LivenessDetection.ts +0 -178
  94. package/src/components/biometrics/OmnipayLivenessCameraView.tsx +0 -19
  95. package/src/components/biometrics/PermissionManager.ts +0 -317
  96. package/src/components/biometrics/index.ts +0 -11
  97. package/src/components/biometrics/types.ts +0 -86
@@ -3,209 +3,161 @@ import {
3
3
  View,
4
4
  Modal,
5
5
  Dimensions,
6
+ Platform,
6
7
  StyleSheet,
7
8
  TouchableOpacity,
8
9
  Image,
9
10
  Text,
10
- ActivityIndicator,
11
11
  } from 'react-native';
12
- import { LivenessDetection } from './LivenessDetection';
13
- import { OmnipayLivenessCameraView } from './OmnipayLivenessCameraView';
14
- import { CameraPermissionManager, PermissionResult } from './PermissionManager';
15
- import { LivenessChallenge, type LivenessConfig } from './types';
12
+ import {
13
+ Camera,
14
+ useCameraDevice,
15
+ useCameraPermission,
16
+ } from 'react-native-vision-camera';
17
+ import Button from '../Button';
18
+ import { useFaceVerification } from './useFaceVerification';
19
+ import { useFaceVerificationFlow } from './useFaceVerificationFlow';
16
20
 
17
21
  type FaceVerificationProps = {
18
22
  onClose: () => void;
19
- onSuccess: (result?: any) => void;
23
+ onSuccess: () => void;
20
24
  primaryColor: string;
21
- config?: Partial<LivenessConfig>;
22
25
  };
23
26
 
24
- type DetectionState =
25
- | 'initializing'
26
- | 'starting'
27
- | 'running'
28
- | 'completed'
29
- | 'failed';
30
-
31
27
  const FaceVerification: React.FC<FaceVerificationProps> = ({
32
28
  onClose,
33
29
  onSuccess,
34
30
  primaryColor,
35
- config,
36
31
  }) => {
37
- const [state, setState] = useState<DetectionState>('initializing');
38
- const [error, setError] = useState<string | null>(null);
39
- const [isSupported, setIsSupported] = useState<boolean>(false);
40
- const [currentChallenge, setCurrentChallenge] =
41
- useState<LivenessChallenge | null>(null);
42
- const [challengeProgress, setChallengeProgress] = useState<string>('');
32
+ const device = useCameraDevice('front');
33
+ const { hasPermission, requestPermission } = useCameraPermission();
34
+ const [isRequestingPermission, setIsRequestingPermission] = useState(false);
43
35
 
44
- useEffect(() => {
45
- checkSupport();
46
- // eslint-disable-next-line react-hooks/exhaustive-deps
47
- }, []);
48
-
49
- const checkSupport = async () => {
50
- try {
51
- console.log('🔍 Starting liveness detection initialization...');
36
+ // Face verification flow
37
+ const {
38
+ state: flowState,
39
+ resetFlow,
40
+ isCompleted,
41
+ isFailed,
42
+ } = useFaceVerificationFlow();
52
43
 
53
- // Step 1: Request camera permission first
54
- console.log('📹 Requesting camera permission...');
55
- const permissionResponse =
56
- await CameraPermissionManager.requestCameraPermission();
44
+ // Frame processor
45
+ const frameProcessor = useFaceVerification();
57
46
 
58
- if (permissionResponse.result !== PermissionResult.GRANTED) {
59
- console.log('❌ Camera permission denied:', permissionResponse.result);
60
- setState('failed');
61
- setError(
62
- permissionResponse.result === PermissionResult.BLOCKED
63
- ? 'Camera permission is blocked. Please enable it in device settings.'
64
- : 'Camera permission is required for face verification.'
65
- );
66
- return;
67
- }
68
-
69
- console.log('✅ Camera permission granted');
70
-
71
- // Step 2: Check device support (hardware/framework capability)
72
- console.log('🔍 Checking device capabilities...');
73
- const supported = await LivenessDetection.isSupported();
74
- console.log('📱 Device support result:', supported);
75
-
76
- setIsSupported(supported);
77
- if (supported) {
78
- console.log('✅ Device supports liveness detection, starting...');
79
- await startDetection();
80
- } else {
81
- console.log('❌ Device does not support liveness detection');
82
- setState('failed');
83
- setError('Liveness detection is not supported on this device');
84
- }
85
- } catch (err) {
86
- console.error('💥 Error during initialization:', err);
87
- setState('failed');
88
- setError('Failed to initialize liveness detection');
47
+ // Handle completion
48
+ useEffect(() => {
49
+ if (isCompleted) {
50
+ setTimeout(() => {
51
+ onSuccess();
52
+ }, 1000); // Show success message briefly
89
53
  }
90
- };
54
+ }, [isCompleted, onSuccess]);
91
55
 
92
- const startDetection = async () => {
93
- if (!isSupported) {
94
- return;
56
+ const handleRequestPermission = async () => {
57
+ setIsRequestingPermission(true);
58
+ try {
59
+ await requestPermission();
60
+ } catch (error) {
61
+ console.error('Error requesting camera permission:', error);
62
+ } finally {
63
+ setIsRequestingPermission(false);
95
64
  }
65
+ };
96
66
 
97
- setState('starting');
98
- setError(null);
67
+ const renderPermissionRequest = () => (
68
+ <View style={styles.permissionContainer}>
69
+ <View style={styles.permissionIconContainer}>
70
+ <Text style={styles.permissionIcon}>📷</Text>
71
+ </View>
72
+ <Text style={styles.permissionTitle}>Camera Permission Required</Text>
73
+ <Text style={styles.permissionDescription}>
74
+ To verify your identity, we need access to your camera. This allows us
75
+ to capture your face for secure verification.
76
+ </Text>
77
+ <Button
78
+ title="Allow Camera Access"
79
+ onPress={handleRequestPermission}
80
+ backgroundColor={primaryColor}
81
+ loading={isRequestingPermission}
82
+ />
83
+ </View>
84
+ );
99
85
 
100
- try {
101
- // Permission already checked in checkSupport(), proceed with detection
102
- console.log('🚀 Starting liveness detection with config...');
86
+ const renderNoDevice = () => (
87
+ <View style={styles.errorContainer}>
88
+ <Text style={styles.errorTitle}>Camera Not Available</Text>
89
+ <Text style={styles.errorSubtitle}>
90
+ No front camera detected on this device. Face verification requires a
91
+ front-facing camera.
92
+ </Text>
93
+ </View>
94
+ );
103
95
 
104
- const livenessConfig = {
105
- ...LivenessDetection.getDefaultConfig(),
106
- ...config,
107
- };
96
+ const renderCamera = () => {
97
+ if (!device) return null;
108
98
 
109
- const result = await LivenessDetection.startDetection(livenessConfig, {
110
- onChallengeStart: (challenge) => {
111
- setCurrentChallenge(challenge);
112
- setState('running');
113
- setChallengeProgress(getChallengeInstruction(challenge));
114
- },
115
- onChallengeSuccess: (challenge, _challengeResult) => {
116
- setChallengeProgress(
117
- `✓ ${getChallengeInstruction(challenge)} completed`
118
- );
119
- },
120
- onChallengeFailure: (challenge, reason) => {
121
- setError(`Failed: ${reason}, ${challenge}`);
122
- },
123
- onAllChallengesComplete: () => {
124
- setChallengeProgress(
125
- 'All challenges completed! Taking final photo...'
126
- );
127
- },
128
- onScreenshotCaptured: (_screenshot) => {
129
- // Screenshot captured, detection will complete soon
130
- },
131
- onDetectionFailed: (reason) => {
132
- setError(reason);
133
- setState('failed');
134
- },
135
- });
99
+ return (
100
+ <View style={styles.cameraContainer}>
101
+ <Camera
102
+ device={device}
103
+ style={styles.camera}
104
+ isActive={true}
105
+ frameProcessor={frameProcessor}
106
+ />
107
+ <View style={styles.cameraOverlay}>
108
+ <View style={styles.faceFrame} />
136
109
 
137
- if (result.success) {
138
- setState('completed');
139
- setTimeout(() => {
140
- onSuccess(result);
141
- }, 1000); // Brief delay to show success state
142
- } else {
143
- setState('failed');
144
- setError(result.failureReason || 'Face verification failed');
145
- }
146
- } catch (err) {
147
- setState('failed');
148
- setError(err instanceof Error ? err.message : 'Unknown error occurred');
149
- }
150
- };
110
+ {/* Progress indicator */}
111
+ <View style={styles.progressContainer}>
112
+ <View
113
+ style={[
114
+ styles.progressBar,
115
+ {
116
+ width: `${flowState.progress}%`,
117
+ backgroundColor: primaryColor,
118
+ },
119
+ ]}
120
+ />
121
+ </View>
151
122
 
152
- const getChallengeInstruction = (challenge: LivenessChallenge): string => {
153
- switch (challenge) {
154
- case LivenessChallenge.SMILE:
155
- return 'Please smile';
156
- case LivenessChallenge.BLINK:
157
- return 'Please blink';
158
- case LivenessChallenge.TURN_LEFT:
159
- return 'Please turn your head left';
160
- case LivenessChallenge.TURN_RIGHT:
161
- return 'Please turn your head right';
162
- default:
163
- return 'Follow the instruction';
164
- }
165
- };
123
+ {/* Current instruction */}
124
+ <Text style={styles.instructionText}>{flowState.instruction}</Text>
166
125
 
167
- const getStateMessage = (): string => {
168
- switch (state) {
169
- case 'initializing':
170
- return 'Initializing camera...';
171
- case 'starting':
172
- return 'Starting face verification...';
173
- case 'running':
174
- return challengeProgress || 'Look at the camera';
175
- case 'completed':
176
- return 'Face verification completed!';
177
- case 'failed':
178
- return error || 'Face verification failed';
179
- default:
180
- return 'Please wait...';
181
- }
182
- };
126
+ {/* Step indicator */}
127
+ <Text style={styles.stepIndicator}>
128
+ Step {flowState.completedSteps.length + 1} of 5
129
+ </Text>
183
130
 
184
- const getStateColor = (): string => {
185
- switch (state) {
186
- case 'completed':
187
- return '#4CAF50';
188
- case 'failed':
189
- return '#F44336';
190
- case 'running':
191
- return primaryColor;
192
- default:
193
- return '#666';
194
- }
195
- };
131
+ {/* Success/Failure messages */}
132
+ {isCompleted && (
133
+ <View
134
+ style={[
135
+ styles.statusContainer,
136
+ { backgroundColor: primaryColor },
137
+ ]}
138
+ >
139
+ <Text style={styles.statusText}>✓ Verification Complete!</Text>
140
+ </View>
141
+ )}
196
142
 
197
- const handleRetry = () => {
198
- setState('initializing');
199
- setError(null);
200
- setCurrentChallenge(null);
201
- setChallengeProgress('');
202
- checkSupport();
143
+ {isFailed && (
144
+ <View style={[styles.statusContainer, styles.statusContainerError]}>
145
+ <Text style={styles.statusText}>✗ Verification Failed</Text>
146
+ <Button
147
+ title="Try Again"
148
+ onPress={resetFlow}
149
+ backgroundColor="white"
150
+ textColor="#ff4444"
151
+ style={styles.retryButton}
152
+ />
153
+ </View>
154
+ )}
155
+ </View>
156
+ </View>
157
+ );
203
158
  };
204
159
 
205
- const showRetryButton =
206
- state === 'failed' &&
207
- error !==
208
- 'Camera permission is blocked. Please enable it in device settings.';
160
+ console.log(onSuccess, primaryColor);
209
161
 
210
162
  return (
211
163
  <Modal
@@ -217,7 +169,7 @@ const FaceVerification: React.FC<FaceVerificationProps> = ({
217
169
  <TouchableOpacity
218
170
  style={styles.backdrop}
219
171
  activeOpacity={1}
220
- onPress={() => {}}
172
+ onPress={onClose}
221
173
  >
222
174
  <View style={[styles.container]}>
223
175
  <TouchableOpacity style={styles.close} onPress={onClose}>
@@ -226,61 +178,10 @@ const FaceVerification: React.FC<FaceVerificationProps> = ({
226
178
  style={styles.closeIcon}
227
179
  />
228
180
  </TouchableOpacity>
229
-
230
181
  <View style={styles.contentContainer}>
231
- <Text style={styles.title}>Face Verification</Text>
232
-
233
- {/* Camera Preview */}
234
- <View style={styles.cameraContainer}>
235
- {state === 'running' && isSupported ? (
236
- <OmnipayLivenessCameraView style={styles.camera} />
237
- ) : (
238
- <View style={[styles.camera, styles.cameraPlaceholder]}>
239
- {state === 'initializing' || state === 'starting' ? (
240
- <ActivityIndicator size="large" color={primaryColor} />
241
- ) : state === 'completed' ? (
242
- <View style={styles.successIcon}>
243
- <Text style={styles.successText}>✓</Text>
244
- </View>
245
- ) : (
246
- <View style={styles.errorIcon}>
247
- <Text style={styles.errorText}>!</Text>
248
- </View>
249
- )}
250
- </View>
251
- )}
252
-
253
- {/* Overlay with instructions */}
254
- <View style={styles.overlay}>
255
- <Text style={[styles.instruction, { color: getStateColor() }]}>
256
- {getStateMessage()}
257
- </Text>
258
- </View>
259
- </View>
260
-
261
- {/* Progress indicator for challenges */}
262
- {state === 'running' && currentChallenge && (
263
- <View style={styles.progressContainer}>
264
- <Text style={styles.challengeText}>
265
- {getChallengeInstruction(currentChallenge)}
266
- </Text>
267
- </View>
268
- )}
269
-
270
- {/* Action buttons */}
271
- <View style={styles.buttonContainer}>
272
- {showRetryButton && (
273
- <TouchableOpacity
274
- style={[
275
- styles.retryButton,
276
- { backgroundColor: primaryColor },
277
- ]}
278
- onPress={handleRetry}
279
- >
280
- <Text style={styles.retryButtonText}>Try Again</Text>
281
- </TouchableOpacity>
282
- )}
283
- </View>
182
+ {!hasPermission && renderPermissionRequest()}
183
+ {hasPermission && !device && renderNoDevice()}
184
+ {hasPermission && device && renderCamera()}
284
185
  </View>
285
186
  </View>
286
187
  </TouchableOpacity>
@@ -288,136 +189,241 @@ const FaceVerification: React.FC<FaceVerificationProps> = ({
288
189
  );
289
190
  };
290
191
 
291
- const { width: screenWidth, height: screenHeight } = Dimensions.get('window');
192
+ export default FaceVerification;
292
193
 
293
194
  const styles = StyleSheet.create({
294
- modal: {
295
- margin: 0,
195
+ hide: {
196
+ display: 'none',
296
197
  },
297
- backdrop: {
198
+ full: {
298
199
  flex: 1,
299
- backgroundColor: 'rgba(0, 0, 0, 0.8)',
300
- justifyContent: 'center',
200
+ width: '100%',
201
+ height: '100%',
202
+ },
203
+ webview: {
204
+ flex: 1,
205
+ width: '100%',
206
+ height: Dimensions.get('window').height - 40,
207
+ backgroundColor: 'white',
208
+ borderTopRightRadius: 20,
209
+ borderTopLeftRadius: 20,
210
+ paddingTop: 150,
211
+ },
212
+ webviewLoader: {
213
+ zIndex: 3,
214
+ backgroundColor: 'white',
301
215
  alignItems: 'center',
216
+ justifyContent: 'center',
217
+ flex: 1,
218
+ width: '100%',
219
+ height: '100%',
220
+ position: 'absolute',
221
+ top: 0,
222
+ left: 0,
223
+ borderTopRightRadius: 20,
224
+ borderTopLeftRadius: 20,
225
+ },
226
+ backdrop: {
227
+ backgroundColor: 'rgba(0,0,0,0.3)',
228
+ flex: 1,
229
+ justifyContent: 'flex-end',
230
+ position: 'relative',
231
+ height: '100%',
302
232
  },
303
233
  container: {
304
- width: screenWidth * 0.9,
305
- maxHeight: screenHeight * 0.8,
306
234
  backgroundColor: 'white',
307
- borderRadius: 16,
308
- padding: 20,
309
- alignItems: 'center',
235
+ borderTopRightRadius: 20,
236
+ borderTopLeftRadius: 20,
237
+ maxHeight: Dimensions.get('window').height - 120,
238
+ flex: 1,
239
+ position: 'relative',
240
+ ...(Platform.OS === 'android' && { overflow: 'hidden' }),
241
+ },
242
+ modal: {
243
+ flex: 1,
244
+ backgroundColor: 'rgba(0,0,0,0.48)',
245
+ height: '100%',
246
+ width: '100%',
310
247
  },
311
248
  close: {
312
249
  position: 'absolute',
313
- top: 15,
314
- right: 15,
315
- zIndex: 10,
316
- padding: 5,
250
+ top: 10,
251
+ right: 10,
252
+ backgroundColor: 'white',
253
+ height: 24,
254
+ width: 24,
255
+ borderRadius: 1000,
256
+ alignItems: 'center',
257
+ justifyContent: 'center',
258
+ zIndex: 2,
317
259
  },
318
260
  closeIcon: {
319
- width: 20,
320
- height: 20,
321
- tintColor: '#666',
261
+ height: 12,
262
+ width: 12,
322
263
  },
323
264
  contentContainer: {
324
- width: '100%',
325
- alignItems: 'center',
326
- paddingTop: 20,
265
+ height: '100%',
266
+ position: 'relative',
267
+ borderTopRightRadius: 20,
268
+ borderTopLeftRadius: 20,
269
+ padding: 16,
327
270
  },
328
- title: {
329
- fontSize: 24,
330
- fontWeight: 'bold',
331
- color: '#333',
332
- marginBottom: 20,
333
- textAlign: 'center',
271
+ testContent: {
272
+ paddingTop: 30,
273
+ paddingLeft: 16,
334
274
  },
335
- cameraContainer: {
336
- width: screenWidth * 0.7,
337
- height: screenWidth * 0.9,
338
- borderRadius: 12,
339
- overflow: 'hidden',
340
- backgroundColor: '#f0f0f0',
341
- position: 'relative',
275
+ testTwoContent: {
276
+ paddingTop: 10,
277
+ paddingLeft: 16,
278
+ },
279
+ errorSubtitle: {
280
+ textAlign: 'center',
281
+ fontSize: 14,
282
+ color: '#5e7079',
342
283
  marginBottom: 20,
284
+ paddingHorizontal: 8,
285
+ marginTop: 14,
343
286
  },
344
- camera: {
287
+ errorContainer: {
345
288
  flex: 1,
289
+ justifyContent: 'center',
290
+ alignItems: 'center',
291
+ width: Dimensions.get('window').width,
292
+ height: Dimensions.get('window').height,
293
+ zIndex: 2,
294
+ backgroundColor: 'white',
295
+ },
296
+
297
+ camera: {
346
298
  width: '100%',
347
- height: '100%',
299
+ height: 400,
348
300
  },
349
- cameraPlaceholder: {
301
+ // Permission request styles
302
+ permissionContainer: {
303
+ flex: 1,
350
304
  justifyContent: 'center',
351
305
  alignItems: 'center',
352
- backgroundColor: '#f5f5f5',
306
+ paddingHorizontal: 24,
307
+ paddingVertical: 40,
353
308
  },
354
- overlay: {
355
- position: 'absolute',
356
- bottom: 0,
357
- left: 0,
358
- right: 0,
359
- backgroundColor: 'rgba(0, 0, 0, 0.7)',
360
- padding: 15,
309
+ permissionIconContainer: {
310
+ width: 80,
311
+ height: 80,
312
+ borderRadius: 40,
313
+ backgroundColor: '#f0f0f0',
314
+ justifyContent: 'center',
361
315
  alignItems: 'center',
316
+ marginBottom: 24,
362
317
  },
363
- instruction: {
364
- fontSize: 16,
318
+ permissionIcon: {
319
+ fontSize: 40,
320
+ },
321
+ permissionTitle: {
322
+ fontSize: 20,
365
323
  fontWeight: '600',
324
+ color: '#1a1a1a',
366
325
  textAlign: 'center',
367
- color: 'white',
326
+ marginBottom: 12,
368
327
  },
369
- progressContainer: {
370
- marginBottom: 20,
371
- alignItems: 'center',
328
+ permissionDescription: {
329
+ fontSize: 16,
330
+ color: '#666',
331
+ textAlign: 'center',
332
+ lineHeight: 22,
333
+ marginBottom: 32,
372
334
  },
373
- challengeText: {
335
+
336
+ // Error styles
337
+ errorTitle: {
374
338
  fontSize: 18,
375
339
  fontWeight: '600',
376
- color: '#333',
340
+ color: '#1a1a1a',
377
341
  textAlign: 'center',
342
+ marginBottom: 8,
378
343
  },
379
- buttonContainer: {
380
- flexDirection: 'row',
381
- justifyContent: 'center',
382
- gap: 15,
344
+ // Camera styles
345
+ cameraContainer: {
346
+ flex: 1,
347
+ position: 'relative',
348
+ marginTop: 60,
383
349
  },
384
- retryButton: {
385
- paddingHorizontal: 30,
386
- paddingVertical: 12,
387
- borderRadius: 8,
350
+ cameraOverlay: {
351
+ position: 'absolute',
352
+ top: 0,
353
+ left: 0,
354
+ right: 0,
355
+ bottom: 0,
356
+ justifyContent: 'center',
388
357
  alignItems: 'center',
389
358
  },
390
- retryButtonText: {
359
+ faceFrame: {
360
+ width: 200,
361
+ height: 250,
362
+ borderWidth: 3,
363
+ borderColor: 'white',
364
+ borderRadius: 100,
365
+ borderStyle: 'dashed',
366
+ backgroundColor: 'transparent',
367
+ },
368
+ instructionText: {
391
369
  color: 'white',
392
370
  fontSize: 16,
393
- fontWeight: '600',
371
+ fontWeight: '500',
372
+ textAlign: 'center',
373
+ marginTop: 20,
374
+ backgroundColor: 'rgba(0,0,0,0.7)',
375
+ paddingHorizontal: 16,
376
+ paddingVertical: 8,
377
+ borderRadius: 20,
394
378
  },
395
- successIcon: {
396
- width: 60,
397
- height: 60,
398
- borderRadius: 30,
399
- backgroundColor: '#4CAF50',
400
- justifyContent: 'center',
401
- alignItems: 'center',
379
+ // Verification flow styles
380
+ progressContainer: {
381
+ position: 'absolute',
382
+ top: 20,
383
+ left: 20,
384
+ right: 20,
385
+ height: 4,
386
+ backgroundColor: 'rgba(255,255,255,0.3)',
387
+ borderRadius: 2,
388
+ overflow: 'hidden',
389
+ },
390
+ progressBar: {
391
+ height: '100%',
392
+ borderRadius: 2,
402
393
  },
403
- successText: {
404
- fontSize: 30,
394
+ stepIndicator: {
405
395
  color: 'white',
406
- fontWeight: 'bold',
396
+ fontSize: 14,
397
+ fontWeight: '400',
398
+ textAlign: 'center',
399
+ marginTop: 8,
400
+ backgroundColor: 'rgba(0,0,0,0.5)',
401
+ paddingHorizontal: 12,
402
+ paddingVertical: 4,
403
+ borderRadius: 12,
404
+ alignSelf: 'center',
407
405
  },
408
- errorIcon: {
409
- width: 60,
410
- height: 60,
411
- borderRadius: 30,
412
- backgroundColor: '#F44336',
413
- justifyContent: 'center',
406
+ statusContainer: {
407
+ position: 'absolute',
408
+ bottom: 40,
409
+ left: 20,
410
+ right: 20,
411
+ padding: 20,
412
+ borderRadius: 12,
414
413
  alignItems: 'center',
415
414
  },
416
- errorText: {
417
- fontSize: 30,
415
+ statusContainerError: {
416
+ backgroundColor: '#ff4444',
417
+ },
418
+ statusText: {
418
419
  color: 'white',
419
- fontWeight: 'bold',
420
+ fontSize: 18,
421
+ fontWeight: '600',
422
+ textAlign: 'center',
423
+ marginBottom: 8,
424
+ },
425
+ retryButton: {
426
+ marginTop: 12,
427
+ minWidth: 120,
420
428
  },
421
429
  });
422
-
423
- export default FaceVerification;