@trustchex/react-native-sdk 1.362.6 → 1.374.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/TrustchexSDK.podspec +3 -3
- package/android/build.gradle +3 -3
- package/android/src/main/java/com/trustchex/reactnativesdk/camera/TrustchexCameraView.kt +71 -17
- package/ios/Camera/TrustchexCameraView.swift +166 -119
- package/lib/module/Shared/Components/FaceCamera.js +1 -0
- package/lib/module/Shared/Components/IdentityDocumentCamera.js +344 -207
- package/lib/module/Shared/Components/QrCodeScannerCamera.js +1 -8
- package/lib/module/Shared/Libs/mrz.utils.js +202 -9
- package/lib/module/Translation/Resources/en.js +0 -4
- package/lib/module/Translation/Resources/tr.js +0 -4
- package/lib/module/version.js +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/QrCodeScannerCamera.d.ts.map +1 -1
- package/lib/typescript/src/Shared/Components/TrustchexCamera.d.ts +1 -0
- package/lib/typescript/src/Shared/Components/TrustchexCamera.d.ts.map +1 -1
- package/lib/typescript/src/Shared/Libs/mrz.utils.d.ts +8 -0
- package/lib/typescript/src/Shared/Libs/mrz.utils.d.ts.map +1 -1
- package/lib/typescript/src/Translation/Resources/en.d.ts +0 -4
- package/lib/typescript/src/Translation/Resources/en.d.ts.map +1 -1
- package/lib/typescript/src/Translation/Resources/tr.d.ts +0 -4
- package/lib/typescript/src/Translation/Resources/tr.d.ts.map +1 -1
- package/lib/typescript/src/version.d.ts +1 -1
- package/package.json +1 -1
- package/src/Shared/Components/FaceCamera.tsx +1 -0
- package/src/Shared/Components/IdentityDocumentCamera.tsx +443 -265
- package/src/Shared/Components/QrCodeScannerCamera.tsx +1 -9
- package/src/Shared/Components/TrustchexCamera.tsx +1 -0
- package/src/Shared/Libs/mrz.utils.ts +238 -26
- package/src/Translation/Resources/en.ts +0 -4
- package/src/Translation/Resources/tr.ts +0 -4
- package/src/version.ts +1 -1
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
PermissionsAndroid,
|
|
14
14
|
Dimensions,
|
|
15
15
|
ScrollView,
|
|
16
|
+
Animated,
|
|
16
17
|
type NativeSyntheticEvent,
|
|
17
18
|
type ViewStyle,
|
|
18
19
|
} from 'react-native';
|
|
@@ -38,6 +39,8 @@ import { useTheme } from '../Contexts/ThemeContext';
|
|
|
38
39
|
|
|
39
40
|
const { OpenCVModule } = NativeModules;
|
|
40
41
|
|
|
42
|
+
const AnimatedText = Animated.createAnimatedComponent(TextView);
|
|
43
|
+
|
|
41
44
|
export type DocumentScannedData = {
|
|
42
45
|
documentType: 'ID_FRONT' | 'ID_BACK' | 'PASSPORT' | 'UNKNOWN';
|
|
43
46
|
image: string;
|
|
@@ -125,7 +128,6 @@ interface Barcode {
|
|
|
125
128
|
const HOLOGRAM_IMAGE_COUNT = 12;
|
|
126
129
|
const HOLOGRAM_DETECTION_THRESHOLD = 1000; // Lowered for better sensitivity while still filtering noise
|
|
127
130
|
const HOLOGRAM_DETECTION_RETRY_COUNT = 3; // More attempts but faster each (~1s per attempt)
|
|
128
|
-
const SECOND_FACE_DETECTION_RETRY_COUNT = 10;
|
|
129
131
|
const MIN_BRIGHTNESS_THRESHOLD = 45;
|
|
130
132
|
const MAX_CONSECUTIVE_QUALITY_FAILURES = 30;
|
|
131
133
|
|
|
@@ -206,6 +208,9 @@ const IdentityDocumentCamera = ({
|
|
|
206
208
|
// Barcode caching - persist detected barcode across frames for reliability
|
|
207
209
|
const cachedBarcode = useRef<Barcode | null>(null);
|
|
208
210
|
|
|
211
|
+
// Error message flash animation
|
|
212
|
+
const errorFlashAnim = useRef(new Animated.Value(1)).current;
|
|
213
|
+
|
|
209
214
|
// Test mode tracking
|
|
210
215
|
const [testModeData, setTestModeData] = useState<{
|
|
211
216
|
mrzText: string;
|
|
@@ -451,25 +456,16 @@ const IdentityDocumentCamera = ({
|
|
|
451
456
|
// Generate message - match UI display logic exactly for consistency
|
|
452
457
|
let message = '';
|
|
453
458
|
|
|
454
|
-
if (
|
|
455
|
-
message =
|
|
456
|
-
completedStep === 'SCAN_ID_FRONT_OR_PASSPORT'
|
|
457
|
-
? detectedDocumentType === 'PASSPORT'
|
|
458
|
-
? t('identityDocumentCamera.passportScanned')
|
|
459
|
-
: t('identityDocumentCamera.frontSideScanned')
|
|
460
|
-
: completedStep === 'SCAN_ID_BACK'
|
|
461
|
-
? t('identityDocumentCamera.backSideScanned')
|
|
462
|
-
: completedStep === 'SCAN_HOLOGRAM'
|
|
463
|
-
? t('identityDocumentCamera.hologramVerified')
|
|
464
|
-
: t('identityDocumentCamera.scanCompleted');
|
|
459
|
+
if (nextStep === 'COMPLETED') {
|
|
460
|
+
message = t('identityDocumentCamera.scanCompleted');
|
|
465
461
|
} else if (status === 'INCORRECT') {
|
|
466
462
|
message =
|
|
467
463
|
nextStep === 'SCAN_ID_FRONT_OR_PASSPORT'
|
|
468
|
-
? t('identityDocumentCamera.
|
|
464
|
+
? t('identityDocumentCamera.alignIDFront')
|
|
469
465
|
: nextStep === 'SCAN_ID_BACK'
|
|
470
|
-
? t('identityDocumentCamera.
|
|
466
|
+
? t('identityDocumentCamera.alignIDBack')
|
|
471
467
|
: nextStep === 'SCAN_HOLOGRAM'
|
|
472
|
-
? t('identityDocumentCamera.
|
|
468
|
+
? t('identityDocumentCamera.alignIDFront')
|
|
473
469
|
: t('identityDocumentCamera.alignPhotoSide');
|
|
474
470
|
} else if (isBrightnessLow) {
|
|
475
471
|
message = t('identityDocumentCamera.lowBrightness');
|
|
@@ -567,6 +563,27 @@ const IdentityDocumentCamera = ({
|
|
|
567
563
|
}
|
|
568
564
|
}, [nextStep]);
|
|
569
565
|
|
|
566
|
+
// Error flash animation - flash red text when wrong side detected
|
|
567
|
+
useEffect(() => {
|
|
568
|
+
if (status === 'INCORRECT') {
|
|
569
|
+
errorFlashAnim.setValue(1);
|
|
570
|
+
Animated.loop(
|
|
571
|
+
Animated.sequence([
|
|
572
|
+
Animated.timing(errorFlashAnim, {
|
|
573
|
+
toValue: 0.3,
|
|
574
|
+
duration: 300,
|
|
575
|
+
useNativeDriver: false,
|
|
576
|
+
}),
|
|
577
|
+
Animated.timing(errorFlashAnim, {
|
|
578
|
+
toValue: 1,
|
|
579
|
+
duration: 300,
|
|
580
|
+
useNativeDriver: false,
|
|
581
|
+
}),
|
|
582
|
+
])
|
|
583
|
+
).start();
|
|
584
|
+
}
|
|
585
|
+
}, [status, errorFlashAnim]);
|
|
586
|
+
|
|
570
587
|
// Native OpenCV: detect hologram from sequence of face images
|
|
571
588
|
const detectHologramNative = useCallback(
|
|
572
589
|
async (images: string[]): Promise<[string, string] | []> => {
|
|
@@ -1918,10 +1935,11 @@ const IdentityDocumentCamera = ({
|
|
|
1918
1935
|
nextStep,
|
|
1919
1936
|
frameDimensions,
|
|
1920
1937
|
currentHologramImage,
|
|
1938
|
+
detectedDocumentType,
|
|
1921
1939
|
currentFaceImage,
|
|
1940
|
+
testMode,
|
|
1922
1941
|
hasRequiredMRZFields,
|
|
1923
1942
|
areMRZFieldsEqual,
|
|
1924
|
-
detectedDocumentType,
|
|
1925
1943
|
onlyMRZScan,
|
|
1926
1944
|
isTorchOn,
|
|
1927
1945
|
setIsTorchOn,
|
|
@@ -1931,7 +1949,6 @@ const IdentityDocumentCamera = ({
|
|
|
1931
1949
|
logMRZValidationFailure,
|
|
1932
1950
|
currentSecondaryFaceImage,
|
|
1933
1951
|
detectHologramNative,
|
|
1934
|
-
mrzUtils,
|
|
1935
1952
|
]
|
|
1936
1953
|
);
|
|
1937
1954
|
|
|
@@ -3188,14 +3205,17 @@ const IdentityDocumentCamera = ({
|
|
|
3188
3205
|
</TextView>
|
|
3189
3206
|
)}
|
|
3190
3207
|
|
|
3191
|
-
<
|
|
3208
|
+
<AnimatedText
|
|
3192
3209
|
style={[
|
|
3193
3210
|
styles.topZoneText,
|
|
3194
3211
|
// Priority order for coloring (later styles override earlier ones)
|
|
3195
3212
|
// 1. Success (green) - scan completed
|
|
3196
|
-
|
|
3197
|
-
// 2. Error (red) - wrong side
|
|
3213
|
+
nextStep === 'COMPLETED' && styles.topZoneTextSuccess,
|
|
3214
|
+
// 2. Error (red) - wrong side - with flash opacity
|
|
3198
3215
|
status === 'INCORRECT' && styles.topZoneTextError,
|
|
3216
|
+
status === 'INCORRECT' && {
|
|
3217
|
+
opacity: errorFlashAnim,
|
|
3218
|
+
},
|
|
3199
3219
|
// 3. Warning (yellow) - quality issues
|
|
3200
3220
|
(isBrightnessLow || isFrameBlurry) && styles.topZoneTextWarning,
|
|
3201
3221
|
// 4. Scanning (green) - all elements detected AND inside scan area
|
|
@@ -3208,23 +3228,15 @@ const IdentityDocumentCamera = ({
|
|
|
3208
3228
|
// 5. Default (white) - aligning (not all detected OR elements outside scan area)
|
|
3209
3229
|
]}
|
|
3210
3230
|
>
|
|
3211
|
-
{
|
|
3212
|
-
?
|
|
3213
|
-
? detectedDocumentType === 'PASSPORT'
|
|
3214
|
-
? t('identityDocumentCamera.passportScanned')
|
|
3215
|
-
: t('identityDocumentCamera.frontSideScanned')
|
|
3216
|
-
: completedStep === 'SCAN_ID_BACK'
|
|
3217
|
-
? t('identityDocumentCamera.backSideScanned')
|
|
3218
|
-
: completedStep === 'SCAN_HOLOGRAM'
|
|
3219
|
-
? t('identityDocumentCamera.hologramVerified')
|
|
3220
|
-
: t('identityDocumentCamera.scanCompleted')
|
|
3231
|
+
{nextStep === 'COMPLETED'
|
|
3232
|
+
? t('identityDocumentCamera.scanCompleted')
|
|
3221
3233
|
: status === 'INCORRECT'
|
|
3222
3234
|
? nextStep === 'SCAN_ID_FRONT_OR_PASSPORT'
|
|
3223
|
-
? t('identityDocumentCamera.
|
|
3235
|
+
? t('identityDocumentCamera.alignIDFront')
|
|
3224
3236
|
: nextStep === 'SCAN_ID_BACK'
|
|
3225
|
-
? t('identityDocumentCamera.
|
|
3237
|
+
? t('identityDocumentCamera.alignIDBack')
|
|
3226
3238
|
: nextStep === 'SCAN_HOLOGRAM'
|
|
3227
|
-
? t('identityDocumentCamera.
|
|
3239
|
+
? t('identityDocumentCamera.alignIDFront')
|
|
3228
3240
|
: t('identityDocumentCamera.alignPhotoSide')
|
|
3229
3241
|
: isBrightnessLow
|
|
3230
3242
|
? t('identityDocumentCamera.lowBrightness')
|
|
@@ -3274,200 +3286,17 @@ const IdentityDocumentCamera = ({
|
|
|
3274
3286
|
: nextStep === 'COMPLETED'
|
|
3275
3287
|
? t('identityDocumentCamera.scanCompleted')
|
|
3276
3288
|
: ''}
|
|
3277
|
-
</
|
|
3289
|
+
</AnimatedText>
|
|
3278
3290
|
</View>
|
|
3279
3291
|
<View style={styles.leftZone} />
|
|
3280
3292
|
<View style={styles.rightZone} />
|
|
3281
|
-
<View style={styles.bottomZone}
|
|
3282
|
-
<View style={styles.debugImagesRow}>
|
|
3283
|
-
{isDebugEnabled() && (
|
|
3284
|
-
<View style={styles.imageContainer}>
|
|
3285
|
-
{currentFaceImage ? (
|
|
3286
|
-
<Image
|
|
3287
|
-
source={{
|
|
3288
|
-
uri: `data:image/jpeg;base64,${currentFaceImage}`,
|
|
3289
|
-
}}
|
|
3290
|
-
style={styles.faceImage}
|
|
3291
|
-
/>
|
|
3292
|
-
) : (
|
|
3293
|
-
<View
|
|
3294
|
-
style={[
|
|
3295
|
-
styles.faceImage,
|
|
3296
|
-
{ backgroundColor: '#333', justifyContent: 'center' },
|
|
3297
|
-
]}
|
|
3298
|
-
>
|
|
3299
|
-
<TextView
|
|
3300
|
-
style={{
|
|
3301
|
-
color: '#666',
|
|
3302
|
-
fontSize: 10,
|
|
3303
|
-
textAlign: 'center',
|
|
3304
|
-
}}
|
|
3305
|
-
>
|
|
3306
|
-
Waiting...
|
|
3307
|
-
</TextView>
|
|
3308
|
-
</View>
|
|
3309
|
-
)}
|
|
3310
|
-
<TextView
|
|
3311
|
-
style={[
|
|
3312
|
-
styles.imageContainerText,
|
|
3313
|
-
currentFaceImage && { color: '#4CAF50' },
|
|
3314
|
-
]}
|
|
3315
|
-
>
|
|
3316
|
-
{`${currentFaceImage ? '✓ ' : ''}Face`}
|
|
3317
|
-
</TextView>
|
|
3318
|
-
</View>
|
|
3319
|
-
)}
|
|
3320
|
-
{isDebugEnabled() && (
|
|
3321
|
-
<View style={styles.imageContainer}>
|
|
3322
|
-
{currentSecondaryFaceImage ? (
|
|
3323
|
-
<Image
|
|
3324
|
-
source={{
|
|
3325
|
-
uri: `data:image/jpeg;base64,${currentSecondaryFaceImage}`,
|
|
3326
|
-
}}
|
|
3327
|
-
style={styles.faceImage}
|
|
3328
|
-
/>
|
|
3329
|
-
) : (
|
|
3330
|
-
<View
|
|
3331
|
-
style={[
|
|
3332
|
-
styles.faceImage,
|
|
3333
|
-
{ backgroundColor: '#333', justifyContent: 'center' },
|
|
3334
|
-
]}
|
|
3335
|
-
>
|
|
3336
|
-
<TextView
|
|
3337
|
-
style={{
|
|
3338
|
-
color: '#666',
|
|
3339
|
-
fontSize: 10,
|
|
3340
|
-
textAlign: 'center',
|
|
3341
|
-
}}
|
|
3342
|
-
>
|
|
3343
|
-
Waiting...
|
|
3344
|
-
</TextView>
|
|
3345
|
-
</View>
|
|
3346
|
-
)}
|
|
3347
|
-
<TextView
|
|
3348
|
-
style={[
|
|
3349
|
-
styles.imageContainerText,
|
|
3350
|
-
currentSecondaryFaceImage && { color: '#4CAF50' },
|
|
3351
|
-
]}
|
|
3352
|
-
>
|
|
3353
|
-
{`${currentSecondaryFaceImage ? '✓ ' : ''}2nd Face`}
|
|
3354
|
-
</TextView>
|
|
3355
|
-
</View>
|
|
3356
|
-
)}
|
|
3357
|
-
{isDebugEnabled() && (
|
|
3358
|
-
<View style={styles.imageContainer}>
|
|
3359
|
-
{currentHologramImage ? (
|
|
3360
|
-
<Image
|
|
3361
|
-
source={{
|
|
3362
|
-
uri: `data:image/jpeg;base64,${currentHologramImage}`,
|
|
3363
|
-
}}
|
|
3364
|
-
style={styles.faceImage}
|
|
3365
|
-
/>
|
|
3366
|
-
) : latestHologramFaceImage && hologramImageCount > 0 ? (
|
|
3367
|
-
<View style={{ position: 'relative' }}>
|
|
3368
|
-
<Image
|
|
3369
|
-
source={{
|
|
3370
|
-
uri: `data:image/jpeg;base64,${latestHologramFaceImage}`,
|
|
3371
|
-
}}
|
|
3372
|
-
style={[styles.faceImage, { opacity: 0.7 }]}
|
|
3373
|
-
/>
|
|
3374
|
-
<View
|
|
3375
|
-
style={{
|
|
3376
|
-
position: 'absolute',
|
|
3377
|
-
bottom: 0,
|
|
3378
|
-
left: 0,
|
|
3379
|
-
right: 0,
|
|
3380
|
-
backgroundColor: 'rgba(0,0,0,0.7)',
|
|
3381
|
-
padding: 2,
|
|
3382
|
-
}}
|
|
3383
|
-
>
|
|
3384
|
-
<TextView
|
|
3385
|
-
style={{
|
|
3386
|
-
color: '#FFA500',
|
|
3387
|
-
fontSize: 8,
|
|
3388
|
-
textAlign: 'center',
|
|
3389
|
-
fontWeight: 'bold',
|
|
3390
|
-
}}
|
|
3391
|
-
>
|
|
3392
|
-
{hologramImageCount}/{HOLOGRAM_IMAGE_COUNT}
|
|
3393
|
-
</TextView>
|
|
3394
|
-
</View>
|
|
3395
|
-
</View>
|
|
3396
|
-
) : (
|
|
3397
|
-
<View
|
|
3398
|
-
style={[
|
|
3399
|
-
styles.faceImage,
|
|
3400
|
-
{ backgroundColor: '#333', justifyContent: 'center' },
|
|
3401
|
-
]}
|
|
3402
|
-
>
|
|
3403
|
-
<TextView
|
|
3404
|
-
style={{
|
|
3405
|
-
color: '#666',
|
|
3406
|
-
fontSize: 10,
|
|
3407
|
-
textAlign: 'center',
|
|
3408
|
-
}}
|
|
3409
|
-
>
|
|
3410
|
-
Waiting...
|
|
3411
|
-
</TextView>
|
|
3412
|
-
</View>
|
|
3413
|
-
)}
|
|
3414
|
-
<TextView
|
|
3415
|
-
style={[
|
|
3416
|
-
styles.imageContainerText,
|
|
3417
|
-
currentHologramImage && { color: '#4CAF50' },
|
|
3418
|
-
latestHologramFaceImage &&
|
|
3419
|
-
!currentHologramImage && { color: '#FFA500' },
|
|
3420
|
-
]}
|
|
3421
|
-
>
|
|
3422
|
-
{`${currentHologramImage ? '✓ ' : latestHologramFaceImage ? '⏳ ' : ''}Hologram`}
|
|
3423
|
-
</TextView>
|
|
3424
|
-
</View>
|
|
3425
|
-
)}
|
|
3426
|
-
{isDebugEnabled() && (
|
|
3427
|
-
<View style={styles.imageContainer}>
|
|
3428
|
-
{_currentHologramMaskImage ? (
|
|
3429
|
-
<Image
|
|
3430
|
-
source={{
|
|
3431
|
-
uri: `data:image/jpeg;base64,${_currentHologramMaskImage}`,
|
|
3432
|
-
}}
|
|
3433
|
-
style={styles.faceImage}
|
|
3434
|
-
/>
|
|
3435
|
-
) : (
|
|
3436
|
-
<View
|
|
3437
|
-
style={[
|
|
3438
|
-
styles.faceImage,
|
|
3439
|
-
{ backgroundColor: '#333', justifyContent: 'center' },
|
|
3440
|
-
]}
|
|
3441
|
-
>
|
|
3442
|
-
<TextView
|
|
3443
|
-
style={{
|
|
3444
|
-
color: '#666',
|
|
3445
|
-
fontSize: 10,
|
|
3446
|
-
textAlign: 'center',
|
|
3447
|
-
}}
|
|
3448
|
-
>
|
|
3449
|
-
Waiting...
|
|
3450
|
-
</TextView>
|
|
3451
|
-
</View>
|
|
3452
|
-
)}
|
|
3453
|
-
<TextView
|
|
3454
|
-
style={[
|
|
3455
|
-
styles.imageContainerText,
|
|
3456
|
-
_currentHologramMaskImage && { color: '#4CAF50' },
|
|
3457
|
-
]}
|
|
3458
|
-
>
|
|
3459
|
-
{`${_currentHologramMaskImage ? '✓ ' : ''}Mask`}
|
|
3460
|
-
</TextView>
|
|
3461
|
-
</View>
|
|
3462
|
-
)}
|
|
3463
|
-
</View>
|
|
3464
|
-
</View>
|
|
3293
|
+
<View style={styles.bottomZone} />
|
|
3465
3294
|
<View
|
|
3466
3295
|
style={[
|
|
3467
3296
|
styles.scanArea,
|
|
3468
3297
|
{
|
|
3469
3298
|
borderColor:
|
|
3470
|
-
|
|
3299
|
+
nextStep === 'COMPLETED'
|
|
3471
3300
|
? '#4CAF50'
|
|
3472
3301
|
: status === 'INCORRECT'
|
|
3473
3302
|
? '#f44336'
|
|
@@ -3480,7 +3309,7 @@ const IdentityDocumentCamera = ({
|
|
|
3480
3309
|
},
|
|
3481
3310
|
]}
|
|
3482
3311
|
>
|
|
3483
|
-
{nextStep === 'COMPLETED'
|
|
3312
|
+
{nextStep === 'COMPLETED' ? (
|
|
3484
3313
|
<LottieView
|
|
3485
3314
|
source={require('../../Shared/Animations/success.json')}
|
|
3486
3315
|
style={styles.animation}
|
|
@@ -3501,13 +3330,6 @@ const IdentityDocumentCamera = ({
|
|
|
3501
3330
|
loop={true}
|
|
3502
3331
|
autoPlay
|
|
3503
3332
|
/>
|
|
3504
|
-
) : status === 'SCANNING' ? (
|
|
3505
|
-
<LottieView
|
|
3506
|
-
source={require('../../Shared/Animations/scanning.json')}
|
|
3507
|
-
style={styles.animation}
|
|
3508
|
-
loop={true}
|
|
3509
|
-
autoPlay
|
|
3510
|
-
/>
|
|
3511
3333
|
) : null}
|
|
3512
3334
|
</View>
|
|
3513
3335
|
{isDebugEnabled() && (
|
|
@@ -3523,59 +3345,415 @@ const IdentityDocumentCamera = ({
|
|
|
3523
3345
|
>
|
|
3524
3346
|
<View
|
|
3525
3347
|
style={{
|
|
3526
|
-
marginTop:
|
|
3527
|
-
|
|
3528
|
-
|
|
3529
|
-
|
|
3348
|
+
marginTop: 8,
|
|
3349
|
+
marginHorizontal: 8,
|
|
3350
|
+
backgroundColor: 'rgba(0, 0, 0, 0.9)',
|
|
3351
|
+
padding: 8,
|
|
3352
|
+
borderRadius: 6,
|
|
3530
3353
|
borderWidth: 1,
|
|
3531
|
-
borderColor: '
|
|
3532
|
-
minWidth:
|
|
3354
|
+
borderColor: 'rgba(255, 82, 82, 0.5)',
|
|
3355
|
+
minWidth: 220,
|
|
3356
|
+
maxWidth: '92%',
|
|
3533
3357
|
}}
|
|
3534
3358
|
>
|
|
3535
|
-
|
|
3359
|
+
{/* Status & State Row */}
|
|
3360
|
+
<View
|
|
3536
3361
|
style={{
|
|
3537
|
-
|
|
3538
|
-
|
|
3539
|
-
|
|
3540
|
-
marginBottom: 6,
|
|
3541
|
-
textAlign: 'center',
|
|
3362
|
+
flexDirection: 'row',
|
|
3363
|
+
justifyContent: 'space-between',
|
|
3364
|
+
marginBottom: 4,
|
|
3542
3365
|
}}
|
|
3543
3366
|
>
|
|
3544
|
-
|
|
3545
|
-
|
|
3546
|
-
|
|
3547
|
-
|
|
3548
|
-
|
|
3549
|
-
|
|
3550
|
-
|
|
3551
|
-
|
|
3552
|
-
|
|
3367
|
+
<TextView
|
|
3368
|
+
style={{
|
|
3369
|
+
color: '#88D8B0',
|
|
3370
|
+
fontSize: 10,
|
|
3371
|
+
fontWeight: 'bold',
|
|
3372
|
+
}}
|
|
3373
|
+
>
|
|
3374
|
+
{`Status: ${status}`}
|
|
3375
|
+
</TextView>
|
|
3376
|
+
<TextView
|
|
3377
|
+
style={{
|
|
3378
|
+
color: '#FFEB3B',
|
|
3379
|
+
fontSize: 10,
|
|
3380
|
+
fontWeight: 'bold',
|
|
3381
|
+
}}
|
|
3382
|
+
>
|
|
3383
|
+
{`Step: ${nextStep}`}
|
|
3384
|
+
</TextView>
|
|
3385
|
+
</View>
|
|
3386
|
+
|
|
3387
|
+
{/* Quality Info - Badges */}
|
|
3388
|
+
<View
|
|
3389
|
+
style={{
|
|
3390
|
+
flexDirection: 'row',
|
|
3391
|
+
justifyContent: 'space-between',
|
|
3392
|
+
marginBottom: 4,
|
|
3393
|
+
gap: 3,
|
|
3394
|
+
}}
|
|
3553
3395
|
>
|
|
3554
|
-
|
|
3555
|
-
|
|
3396
|
+
<View
|
|
3397
|
+
style={{
|
|
3398
|
+
backgroundColor: isBrightnessLow ? '#f44336' : '#4CAF50',
|
|
3399
|
+
paddingHorizontal: 6,
|
|
3400
|
+
paddingVertical: 1,
|
|
3401
|
+
borderRadius: 3,
|
|
3402
|
+
}}
|
|
3403
|
+
>
|
|
3404
|
+
<TextView
|
|
3405
|
+
style={{
|
|
3406
|
+
color: '#FFFFFF',
|
|
3407
|
+
fontSize: 8,
|
|
3408
|
+
fontWeight: 'bold',
|
|
3409
|
+
}}
|
|
3410
|
+
>
|
|
3411
|
+
{isBrightnessLow ? 'Low Light' : 'Good Light'}
|
|
3412
|
+
</TextView>
|
|
3413
|
+
</View>
|
|
3414
|
+
<View
|
|
3415
|
+
style={{
|
|
3416
|
+
backgroundColor: isFrameBlurry ? '#f44336' : '#4CAF50',
|
|
3417
|
+
paddingHorizontal: 6,
|
|
3418
|
+
paddingVertical: 1,
|
|
3419
|
+
borderRadius: 3,
|
|
3420
|
+
}}
|
|
3421
|
+
>
|
|
3422
|
+
<TextView
|
|
3423
|
+
style={{
|
|
3424
|
+
color: '#FFFFFF',
|
|
3425
|
+
fontSize: 8,
|
|
3426
|
+
fontWeight: 'bold',
|
|
3427
|
+
}}
|
|
3428
|
+
>
|
|
3429
|
+
{isFrameBlurry ? 'Blurry' : 'Sharp'}
|
|
3430
|
+
</TextView>
|
|
3431
|
+
</View>
|
|
3432
|
+
</View>
|
|
3433
|
+
|
|
3434
|
+
{/* Elements Status */}
|
|
3556
3435
|
<TextView
|
|
3557
|
-
style={{
|
|
3436
|
+
style={{
|
|
3437
|
+
color:
|
|
3438
|
+
elementsOutsideScanArea.length === 0
|
|
3439
|
+
? '#4CAF50'
|
|
3440
|
+
: '#FFA500',
|
|
3441
|
+
fontSize: 8,
|
|
3442
|
+
marginBottom: 3,
|
|
3443
|
+
}}
|
|
3558
3444
|
>
|
|
3559
|
-
{
|
|
3445
|
+
{elementsOutsideScanArea.length === 0
|
|
3446
|
+
? 'All elements in frame'
|
|
3447
|
+
: `Outside: ${elementsOutsideScanArea.join(', ')}`}
|
|
3560
3448
|
</TextView>
|
|
3449
|
+
|
|
3450
|
+
{/* Detection Info */}
|
|
3561
3451
|
<TextView
|
|
3562
|
-
style={{
|
|
3452
|
+
style={{
|
|
3453
|
+
color: 'rgba(255, 255, 255, 0.7)',
|
|
3454
|
+
fontSize: 8,
|
|
3455
|
+
marginBottom: 3,
|
|
3456
|
+
}}
|
|
3563
3457
|
>
|
|
3564
|
-
{`
|
|
3458
|
+
{`Face: ${documentPlaneBounds ? '✓' : '✗'}, MRZ: ${mrzBounds ? '✓' : '✗'}, Sig: ${signatureBounds ? '✓' : '✗'}`}
|
|
3565
3459
|
</TextView>
|
|
3566
|
-
|
|
3567
|
-
|
|
3460
|
+
|
|
3461
|
+
{/* Hologram Count */}
|
|
3462
|
+
{nextStep === 'SCAN_HOLOGRAM' && hologramImageCount > 0 && (
|
|
3463
|
+
<TextView
|
|
3464
|
+
style={{
|
|
3465
|
+
color: '#9C27B0',
|
|
3466
|
+
fontSize: 8,
|
|
3467
|
+
fontWeight: 'bold',
|
|
3468
|
+
marginBottom: 3,
|
|
3469
|
+
}}
|
|
3470
|
+
>
|
|
3471
|
+
{`Hologram: ${hologramImageCount}/${HOLOGRAM_IMAGE_COUNT}`}
|
|
3472
|
+
</TextView>
|
|
3473
|
+
)}
|
|
3474
|
+
|
|
3475
|
+
{/* Additional Info Row */}
|
|
3476
|
+
<View
|
|
3477
|
+
style={{
|
|
3478
|
+
flexDirection: 'row',
|
|
3479
|
+
gap: 8,
|
|
3480
|
+
paddingTop: 3,
|
|
3481
|
+
borderTopWidth: 1,
|
|
3482
|
+
borderTopColor: 'rgba(255, 255, 255, 0.2)',
|
|
3483
|
+
marginBottom: 4,
|
|
3484
|
+
}}
|
|
3568
3485
|
>
|
|
3569
|
-
|
|
3570
|
-
|
|
3571
|
-
|
|
3572
|
-
|
|
3486
|
+
<TextView
|
|
3487
|
+
style={{
|
|
3488
|
+
color: 'rgba(255, 255, 255, 0.7)',
|
|
3489
|
+
fontSize: 8,
|
|
3490
|
+
marginTop: 3,
|
|
3491
|
+
}}
|
|
3492
|
+
>
|
|
3493
|
+
{`Doc: ${detectedDocumentType}`}
|
|
3494
|
+
</TextView>
|
|
3495
|
+
<TextView
|
|
3496
|
+
style={{
|
|
3497
|
+
color: 'rgba(255, 255, 255, 0.7)',
|
|
3498
|
+
fontSize: 8,
|
|
3499
|
+
marginTop: 3,
|
|
3500
|
+
}}
|
|
3501
|
+
>
|
|
3502
|
+
{`Flash: ${isTorchOn ? '🔦' : '○'}`}
|
|
3503
|
+
</TextView>
|
|
3504
|
+
</View>
|
|
3505
|
+
|
|
3506
|
+
{/* Debug Images Grid - Compact */}
|
|
3507
|
+
<View
|
|
3508
|
+
style={{
|
|
3509
|
+
flexDirection: 'row',
|
|
3510
|
+
flexWrap: 'wrap',
|
|
3511
|
+
gap: 4,
|
|
3512
|
+
justifyContent: 'center',
|
|
3513
|
+
}}
|
|
3573
3514
|
>
|
|
3574
|
-
{
|
|
3575
|
-
|
|
3576
|
-
|
|
3577
|
-
|
|
3578
|
-
|
|
3515
|
+
{/* Face Image */}
|
|
3516
|
+
<View style={{ alignItems: 'center' }}>
|
|
3517
|
+
{currentFaceImage ? (
|
|
3518
|
+
<Image
|
|
3519
|
+
source={{
|
|
3520
|
+
uri: `data:image/jpeg;base64,${currentFaceImage}`,
|
|
3521
|
+
}}
|
|
3522
|
+
style={{
|
|
3523
|
+
width: 40,
|
|
3524
|
+
height: 48,
|
|
3525
|
+
borderRadius: 2,
|
|
3526
|
+
borderWidth: 1,
|
|
3527
|
+
borderColor: '#4CAF50',
|
|
3528
|
+
}}
|
|
3529
|
+
/>
|
|
3530
|
+
) : (
|
|
3531
|
+
<View
|
|
3532
|
+
style={{
|
|
3533
|
+
width: 40,
|
|
3534
|
+
height: 48,
|
|
3535
|
+
borderRadius: 2,
|
|
3536
|
+
borderWidth: 1,
|
|
3537
|
+
borderColor: '#666',
|
|
3538
|
+
backgroundColor: '#222',
|
|
3539
|
+
justifyContent: 'center',
|
|
3540
|
+
alignItems: 'center',
|
|
3541
|
+
}}
|
|
3542
|
+
>
|
|
3543
|
+
<TextView
|
|
3544
|
+
style={{
|
|
3545
|
+
color: '#666',
|
|
3546
|
+
fontSize: 7,
|
|
3547
|
+
}}
|
|
3548
|
+
>
|
|
3549
|
+
—
|
|
3550
|
+
</TextView>
|
|
3551
|
+
</View>
|
|
3552
|
+
)}
|
|
3553
|
+
<TextView
|
|
3554
|
+
style={{
|
|
3555
|
+
color: currentFaceImage ? '#4CAF50' : '#999',
|
|
3556
|
+
fontSize: 7,
|
|
3557
|
+
marginTop: 1,
|
|
3558
|
+
fontWeight: 'bold',
|
|
3559
|
+
}}
|
|
3560
|
+
>
|
|
3561
|
+
{`${currentFaceImage ? '✓' : '○'} Face`}
|
|
3562
|
+
</TextView>
|
|
3563
|
+
</View>
|
|
3564
|
+
|
|
3565
|
+
{/* Secondary Face Image */}
|
|
3566
|
+
<View style={{ alignItems: 'center' }}>
|
|
3567
|
+
{currentSecondaryFaceImage ? (
|
|
3568
|
+
<Image
|
|
3569
|
+
source={{
|
|
3570
|
+
uri: `data:image/jpeg;base64,${currentSecondaryFaceImage}`,
|
|
3571
|
+
}}
|
|
3572
|
+
style={{
|
|
3573
|
+
width: 40,
|
|
3574
|
+
height: 48,
|
|
3575
|
+
borderRadius: 2,
|
|
3576
|
+
borderWidth: 1,
|
|
3577
|
+
borderColor: '#2196F3',
|
|
3578
|
+
}}
|
|
3579
|
+
/>
|
|
3580
|
+
) : (
|
|
3581
|
+
<View
|
|
3582
|
+
style={{
|
|
3583
|
+
width: 40,
|
|
3584
|
+
height: 48,
|
|
3585
|
+
borderRadius: 2,
|
|
3586
|
+
borderWidth: 1,
|
|
3587
|
+
borderColor: '#666',
|
|
3588
|
+
backgroundColor: '#222',
|
|
3589
|
+
justifyContent: 'center',
|
|
3590
|
+
alignItems: 'center',
|
|
3591
|
+
}}
|
|
3592
|
+
>
|
|
3593
|
+
<TextView
|
|
3594
|
+
style={{
|
|
3595
|
+
color: '#666',
|
|
3596
|
+
fontSize: 7,
|
|
3597
|
+
}}
|
|
3598
|
+
>
|
|
3599
|
+
—
|
|
3600
|
+
</TextView>
|
|
3601
|
+
</View>
|
|
3602
|
+
)}
|
|
3603
|
+
<TextView
|
|
3604
|
+
style={{
|
|
3605
|
+
color: currentSecondaryFaceImage ? '#2196F3' : '#999',
|
|
3606
|
+
fontSize: 7,
|
|
3607
|
+
marginTop: 1,
|
|
3608
|
+
fontWeight: 'bold',
|
|
3609
|
+
}}
|
|
3610
|
+
>
|
|
3611
|
+
{`${currentSecondaryFaceImage ? '✓' : '○'} 2nd`}
|
|
3612
|
+
</TextView>
|
|
3613
|
+
</View>
|
|
3614
|
+
|
|
3615
|
+
{/* Hologram Image */}
|
|
3616
|
+
<View style={{ alignItems: 'center' }}>
|
|
3617
|
+
{currentHologramImage ? (
|
|
3618
|
+
<Image
|
|
3619
|
+
source={{
|
|
3620
|
+
uri: `data:image/jpeg;base64,${currentHologramImage}`,
|
|
3621
|
+
}}
|
|
3622
|
+
style={{
|
|
3623
|
+
width: 40,
|
|
3624
|
+
height: 48,
|
|
3625
|
+
borderRadius: 2,
|
|
3626
|
+
borderWidth: 1,
|
|
3627
|
+
borderColor: '#9C27B0',
|
|
3628
|
+
}}
|
|
3629
|
+
/>
|
|
3630
|
+
) : latestHologramFaceImage && hologramImageCount > 0 ? (
|
|
3631
|
+
<View style={{ position: 'relative' }}>
|
|
3632
|
+
<Image
|
|
3633
|
+
source={{
|
|
3634
|
+
uri: `data:image/jpeg;base64,${latestHologramFaceImage}`,
|
|
3635
|
+
}}
|
|
3636
|
+
style={{
|
|
3637
|
+
width: 40,
|
|
3638
|
+
height: 48,
|
|
3639
|
+
borderRadius: 2,
|
|
3640
|
+
borderWidth: 1,
|
|
3641
|
+
borderColor: '#FFA500',
|
|
3642
|
+
opacity: 0.7,
|
|
3643
|
+
}}
|
|
3644
|
+
/>
|
|
3645
|
+
<View
|
|
3646
|
+
style={{
|
|
3647
|
+
position: 'absolute',
|
|
3648
|
+
bottom: 1,
|
|
3649
|
+
left: 1,
|
|
3650
|
+
right: 1,
|
|
3651
|
+
backgroundColor: 'rgba(0,0,0,0.8)',
|
|
3652
|
+
paddingVertical: 0,
|
|
3653
|
+
borderRadius: 1,
|
|
3654
|
+
}}
|
|
3655
|
+
>
|
|
3656
|
+
<TextView
|
|
3657
|
+
style={{
|
|
3658
|
+
color: '#FFA500',
|
|
3659
|
+
fontSize: 6,
|
|
3660
|
+
textAlign: 'center',
|
|
3661
|
+
fontWeight: 'bold',
|
|
3662
|
+
}}
|
|
3663
|
+
>
|
|
3664
|
+
{hologramImageCount}/{HOLOGRAM_IMAGE_COUNT}
|
|
3665
|
+
</TextView>
|
|
3666
|
+
</View>
|
|
3667
|
+
</View>
|
|
3668
|
+
) : (
|
|
3669
|
+
<View
|
|
3670
|
+
style={{
|
|
3671
|
+
width: 40,
|
|
3672
|
+
height: 48,
|
|
3673
|
+
borderRadius: 2,
|
|
3674
|
+
borderWidth: 1,
|
|
3675
|
+
borderColor: '#666',
|
|
3676
|
+
backgroundColor: '#222',
|
|
3677
|
+
justifyContent: 'center',
|
|
3678
|
+
alignItems: 'center',
|
|
3679
|
+
}}
|
|
3680
|
+
>
|
|
3681
|
+
<TextView
|
|
3682
|
+
style={{
|
|
3683
|
+
color: '#666',
|
|
3684
|
+
fontSize: 7,
|
|
3685
|
+
}}
|
|
3686
|
+
>
|
|
3687
|
+
—
|
|
3688
|
+
</TextView>
|
|
3689
|
+
</View>
|
|
3690
|
+
)}
|
|
3691
|
+
<TextView
|
|
3692
|
+
style={{
|
|
3693
|
+
color: currentHologramImage
|
|
3694
|
+
? '#9C27B0'
|
|
3695
|
+
: latestHologramFaceImage
|
|
3696
|
+
? '#FFA500'
|
|
3697
|
+
: '#999',
|
|
3698
|
+
fontSize: 7,
|
|
3699
|
+
marginTop: 1,
|
|
3700
|
+
fontWeight: 'bold',
|
|
3701
|
+
}}
|
|
3702
|
+
>
|
|
3703
|
+
{`${currentHologramImage ? '✓' : latestHologramFaceImage ? '⏳' : '○'} Holo`}
|
|
3704
|
+
</TextView>
|
|
3705
|
+
</View>
|
|
3706
|
+
|
|
3707
|
+
{/* Hologram Mask Image */}
|
|
3708
|
+
<View style={{ alignItems: 'center' }}>
|
|
3709
|
+
{_currentHologramMaskImage ? (
|
|
3710
|
+
<Image
|
|
3711
|
+
source={{
|
|
3712
|
+
uri: `data:image/jpeg;base64,${_currentHologramMaskImage}`,
|
|
3713
|
+
}}
|
|
3714
|
+
style={{
|
|
3715
|
+
width: 40,
|
|
3716
|
+
height: 48,
|
|
3717
|
+
borderRadius: 2,
|
|
3718
|
+
borderWidth: 1,
|
|
3719
|
+
borderColor: '#FF6B6B',
|
|
3720
|
+
}}
|
|
3721
|
+
/>
|
|
3722
|
+
) : (
|
|
3723
|
+
<View
|
|
3724
|
+
style={{
|
|
3725
|
+
width: 40,
|
|
3726
|
+
height: 48,
|
|
3727
|
+
borderRadius: 2,
|
|
3728
|
+
borderWidth: 1,
|
|
3729
|
+
borderColor: '#666',
|
|
3730
|
+
backgroundColor: '#222',
|
|
3731
|
+
justifyContent: 'center',
|
|
3732
|
+
alignItems: 'center',
|
|
3733
|
+
}}
|
|
3734
|
+
>
|
|
3735
|
+
<TextView
|
|
3736
|
+
style={{
|
|
3737
|
+
color: '#666',
|
|
3738
|
+
fontSize: 7,
|
|
3739
|
+
}}
|
|
3740
|
+
>
|
|
3741
|
+
—
|
|
3742
|
+
</TextView>
|
|
3743
|
+
</View>
|
|
3744
|
+
)}
|
|
3745
|
+
<TextView
|
|
3746
|
+
style={{
|
|
3747
|
+
color: _currentHologramMaskImage ? '#FF6B6B' : '#999',
|
|
3748
|
+
fontSize: 7,
|
|
3749
|
+
marginTop: 1,
|
|
3750
|
+
fontWeight: 'bold',
|
|
3751
|
+
}}
|
|
3752
|
+
>
|
|
3753
|
+
{`${_currentHologramMaskImage ? '✓' : '○'} Mask`}
|
|
3754
|
+
</TextView>
|
|
3755
|
+
</View>
|
|
3756
|
+
</View>
|
|
3579
3757
|
</View>
|
|
3580
3758
|
</SafeAreaView>
|
|
3581
3759
|
)}
|