@trustchex/react-native-sdk 1.409.0 → 1.464.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.
Files changed (156) hide show
  1. package/android/src/main/java/com/trustchex/reactnativesdk/TrustchexSDKModule.kt +2 -8
  2. package/android/src/main/java/com/trustchex/reactnativesdk/camera/TrustchexCameraView.kt +59 -1
  3. package/ios/Camera/TrustchexCameraView.swift +9 -1
  4. package/lib/module/Screens/Debug/NFCScanTestScreen.js +635 -0
  5. package/lib/module/Screens/Dynamic/ContractAcceptanceScreen.js +1 -4
  6. package/lib/module/Screens/Dynamic/IdentityDocumentEIDScanningScreen.js +17 -4
  7. package/lib/module/Screens/Dynamic/LivenessDetectionScreen.js +102 -23
  8. package/lib/module/Screens/Dynamic/VerbalConsentScreen.js +1079 -0
  9. package/lib/module/Screens/Dynamic/VideoCallScreen.js +3 -1
  10. package/lib/module/Screens/Static/ResultScreen.js +128 -22
  11. package/lib/module/Screens/Static/VerificationSessionCheckScreen.js +8 -0
  12. package/lib/module/Shared/Animations/recording.json +1 -0
  13. package/lib/module/Shared/Components/DebugNavigationPanel.js +69 -71
  14. package/lib/module/Shared/Components/EIDScanner.js +212 -108
  15. package/lib/module/Shared/Components/IdentityDocumentCamera.flows.js +5 -3
  16. package/lib/module/Shared/Components/IdentityDocumentCamera.js +53 -36
  17. package/lib/module/Shared/Components/IdentityDocumentCamera.utils.js +13 -4
  18. package/lib/module/Shared/Components/NavigationManager.js +24 -16
  19. package/lib/module/Shared/EIDReader/aesSecureMessagingWrapper.js +51 -0
  20. package/lib/module/Shared/EIDReader/apduLevelPACECapable.js +3 -0
  21. package/lib/module/Shared/EIDReader/bacKey.js +16 -2
  22. package/lib/module/Shared/EIDReader/eidReader.js +354 -13
  23. package/lib/module/Shared/EIDReader/eidService.js +25 -1
  24. package/lib/module/Shared/EIDReader/nfcManagerCardService.js +4 -7
  25. package/lib/module/Shared/EIDReader/paceInfo.js +85 -0
  26. package/lib/module/Shared/EIDReader/paceKeySpec.js +51 -0
  27. package/lib/module/Shared/EIDReader/protocol/paceAPDUSender.js +100 -0
  28. package/lib/module/Shared/EIDReader/protocol/paceProtocol.js +655 -0
  29. package/lib/module/Shared/EIDReader/protocol/paceResult.js +37 -0
  30. package/lib/module/Shared/EIDReader/secureMessagingWrapper.js +27 -4
  31. package/lib/module/Shared/EIDReader/smartcards/commandAPDU.js +2 -1
  32. package/lib/module/Shared/EIDReader/tlv/tlv.helpers.js +1 -1
  33. package/lib/module/Shared/EIDReader/tlv/tlv.utils.js +6 -3
  34. package/lib/module/Shared/EIDReader/utils/aesCrypto.utils.js +189 -0
  35. package/lib/module/Shared/Libs/analytics.utils.js +4 -0
  36. package/lib/module/Shared/Libs/contains.js +1 -40
  37. package/lib/module/Shared/Libs/country-display.utils.js +34 -0
  38. package/lib/module/Shared/Libs/demo.utils.js +8 -0
  39. package/lib/module/Shared/Libs/mrz.utils.js +3 -2
  40. package/lib/module/Shared/Libs/status-bar.utils.js +4 -2
  41. package/lib/module/Shared/Types/analytics.types.js +2 -0
  42. package/lib/module/Translation/Resources/en.js +41 -2
  43. package/lib/module/Translation/Resources/tr.js +41 -2
  44. package/lib/module/Trustchex.js +54 -20
  45. package/lib/module/version.js +1 -1
  46. package/lib/typescript/src/Screens/Debug/NFCScanTestScreen.d.ts +3 -0
  47. package/lib/typescript/src/Screens/Debug/NFCScanTestScreen.d.ts.map +1 -0
  48. package/lib/typescript/src/Screens/Dynamic/ContractAcceptanceScreen.d.ts.map +1 -1
  49. package/lib/typescript/src/Screens/Dynamic/IdentityDocumentEIDScanningScreen.d.ts.map +1 -1
  50. package/lib/typescript/src/Screens/Dynamic/LivenessDetectionScreen.d.ts.map +1 -1
  51. package/lib/typescript/src/Screens/Dynamic/VerbalConsentScreen.d.ts +3 -0
  52. package/lib/typescript/src/Screens/Dynamic/VerbalConsentScreen.d.ts.map +1 -0
  53. package/lib/typescript/src/Screens/Dynamic/VideoCallScreen.d.ts.map +1 -1
  54. package/lib/typescript/src/Screens/Static/ResultScreen.d.ts.map +1 -1
  55. package/lib/typescript/src/Screens/Static/VerificationSessionCheckScreen.d.ts.map +1 -1
  56. package/lib/typescript/src/Shared/Components/DebugNavigationPanel.d.ts.map +1 -1
  57. package/lib/typescript/src/Shared/Components/EIDScanner.d.ts.map +1 -1
  58. package/lib/typescript/src/Shared/Components/IdentityDocumentCamera.d.ts.map +1 -1
  59. package/lib/typescript/src/Shared/Components/IdentityDocumentCamera.flows.d.ts +1 -1
  60. package/lib/typescript/src/Shared/Components/IdentityDocumentCamera.flows.d.ts.map +1 -1
  61. package/lib/typescript/src/Shared/Components/IdentityDocumentCamera.utils.d.ts +5 -0
  62. package/lib/typescript/src/Shared/Components/IdentityDocumentCamera.utils.d.ts.map +1 -1
  63. package/lib/typescript/src/Shared/Components/NavigationManager.d.ts.map +1 -1
  64. package/lib/typescript/src/Shared/EIDReader/aesSecureMessagingWrapper.d.ts +18 -0
  65. package/lib/typescript/src/Shared/EIDReader/aesSecureMessagingWrapper.d.ts.map +1 -0
  66. package/lib/typescript/src/Shared/EIDReader/apduLevelPACECapable.d.ts +23 -0
  67. package/lib/typescript/src/Shared/EIDReader/apduLevelPACECapable.d.ts.map +1 -0
  68. package/lib/typescript/src/Shared/EIDReader/bacKey.d.ts +6 -0
  69. package/lib/typescript/src/Shared/EIDReader/bacKey.d.ts.map +1 -1
  70. package/lib/typescript/src/Shared/EIDReader/eidReader.d.ts.map +1 -1
  71. package/lib/typescript/src/Shared/EIDReader/eidService.d.ts +9 -0
  72. package/lib/typescript/src/Shared/EIDReader/eidService.d.ts.map +1 -1
  73. package/lib/typescript/src/Shared/EIDReader/nfcManagerCardService.d.ts.map +1 -1
  74. package/lib/typescript/src/Shared/EIDReader/paceInfo.d.ts +50 -0
  75. package/lib/typescript/src/Shared/EIDReader/paceInfo.d.ts.map +1 -0
  76. package/lib/typescript/src/Shared/EIDReader/paceKeySpec.d.ts +30 -0
  77. package/lib/typescript/src/Shared/EIDReader/paceKeySpec.d.ts.map +1 -0
  78. package/lib/typescript/src/Shared/EIDReader/protocol/paceAPDUSender.d.ts +17 -0
  79. package/lib/typescript/src/Shared/EIDReader/protocol/paceAPDUSender.d.ts.map +1 -0
  80. package/lib/typescript/src/Shared/EIDReader/protocol/paceProtocol.d.ts +105 -0
  81. package/lib/typescript/src/Shared/EIDReader/protocol/paceProtocol.d.ts.map +1 -0
  82. package/lib/typescript/src/Shared/EIDReader/protocol/paceResult.d.ts +24 -0
  83. package/lib/typescript/src/Shared/EIDReader/protocol/paceResult.d.ts.map +1 -0
  84. package/lib/typescript/src/Shared/EIDReader/secureMessagingWrapper.d.ts +15 -0
  85. package/lib/typescript/src/Shared/EIDReader/secureMessagingWrapper.d.ts.map +1 -1
  86. package/lib/typescript/src/Shared/EIDReader/smartcards/commandAPDU.d.ts.map +1 -1
  87. package/lib/typescript/src/Shared/EIDReader/tlv/tlv.utils.d.ts.map +1 -1
  88. package/lib/typescript/src/Shared/EIDReader/utils/aesCrypto.utils.d.ts +39 -0
  89. package/lib/typescript/src/Shared/EIDReader/utils/aesCrypto.utils.d.ts.map +1 -0
  90. package/lib/typescript/src/Shared/Libs/analytics.utils.d.ts.map +1 -1
  91. package/lib/typescript/src/Shared/Libs/contains.d.ts +0 -7
  92. package/lib/typescript/src/Shared/Libs/contains.d.ts.map +1 -1
  93. package/lib/typescript/src/Shared/Libs/country-display.utils.d.ts +2 -0
  94. package/lib/typescript/src/Shared/Libs/country-display.utils.d.ts.map +1 -0
  95. package/lib/typescript/src/Shared/Libs/demo.utils.d.ts.map +1 -1
  96. package/lib/typescript/src/Shared/Libs/http-client.d.ts +1 -1
  97. package/lib/typescript/src/Shared/Libs/http-client.d.ts.map +1 -1
  98. package/lib/typescript/src/Shared/Libs/mrz.utils.d.ts.map +1 -1
  99. package/lib/typescript/src/Shared/Libs/status-bar.utils.d.ts.map +1 -1
  100. package/lib/typescript/src/Shared/Types/analytics.types.d.ts +2 -0
  101. package/lib/typescript/src/Shared/Types/analytics.types.d.ts.map +1 -1
  102. package/lib/typescript/src/Shared/Types/identificationInfo.d.ts +10 -1
  103. package/lib/typescript/src/Shared/Types/identificationInfo.d.ts.map +1 -1
  104. package/lib/typescript/src/Translation/Resources/en.d.ts +40 -1
  105. package/lib/typescript/src/Translation/Resources/en.d.ts.map +1 -1
  106. package/lib/typescript/src/Translation/Resources/tr.d.ts +40 -1
  107. package/lib/typescript/src/Translation/Resources/tr.d.ts.map +1 -1
  108. package/lib/typescript/src/Trustchex.d.ts.map +1 -1
  109. package/lib/typescript/src/version.d.ts +1 -1
  110. package/package.json +7 -4
  111. package/src/Screens/Debug/NFCScanTestScreen.tsx +692 -0
  112. package/src/Screens/Dynamic/ContractAcceptanceScreen.tsx +1 -4
  113. package/src/Screens/Dynamic/IdentityDocumentEIDScanningScreen.tsx +21 -4
  114. package/src/Screens/Dynamic/LivenessDetectionScreen.tsx +124 -23
  115. package/src/Screens/Dynamic/VerbalConsentScreen.tsx +1401 -0
  116. package/src/Screens/Dynamic/VideoCallScreen.tsx +3 -1
  117. package/src/Screens/Static/ResultScreen.tsx +183 -31
  118. package/src/Screens/Static/VerificationSessionCheckScreen.tsx +9 -0
  119. package/src/Shared/Animations/recording.json +1 -0
  120. package/src/Shared/Components/DebugNavigationPanel.tsx +73 -48
  121. package/src/Shared/Components/EIDScanner.tsx +222 -111
  122. package/src/Shared/Components/IdentityDocumentCamera.flows.ts +7 -4
  123. package/src/Shared/Components/IdentityDocumentCamera.tsx +199 -184
  124. package/src/Shared/Components/IdentityDocumentCamera.utils.ts +13 -4
  125. package/src/Shared/Components/NavigationManager.tsx +27 -18
  126. package/src/Shared/EIDReader/aesSecureMessagingWrapper.ts +69 -0
  127. package/src/Shared/EIDReader/apduLevelPACECapable.ts +34 -0
  128. package/src/Shared/EIDReader/bacKey.ts +24 -8
  129. package/src/Shared/EIDReader/eidReader.ts +398 -12
  130. package/src/Shared/EIDReader/eidService.ts +49 -1
  131. package/src/Shared/EIDReader/nfcManagerCardService.ts +4 -6
  132. package/src/Shared/EIDReader/paceInfo.ts +159 -0
  133. package/src/Shared/EIDReader/paceKeySpec.ts +56 -0
  134. package/src/Shared/EIDReader/protocol/paceAPDUSender.ts +163 -0
  135. package/src/Shared/EIDReader/protocol/paceProtocol.ts +946 -0
  136. package/src/Shared/EIDReader/protocol/paceResult.ts +62 -0
  137. package/src/Shared/EIDReader/secureMessagingWrapper.ts +28 -10
  138. package/src/Shared/EIDReader/smartcards/commandAPDU.ts +2 -1
  139. package/src/Shared/EIDReader/tlv/tlv.helpers.ts +1 -1
  140. package/src/Shared/EIDReader/tlv/tlv.utils.ts +8 -5
  141. package/src/Shared/EIDReader/utils/aesCrypto.utils.ts +217 -0
  142. package/src/Shared/Libs/analytics.utils.ts +4 -0
  143. package/src/Shared/Libs/contains.ts +0 -53
  144. package/src/Shared/Libs/country-display.utils.ts +55 -0
  145. package/src/Shared/Libs/crypto.utils.ts +2 -2
  146. package/src/Shared/Libs/demo.utils.ts +10 -0
  147. package/src/Shared/Libs/http-client.ts +12 -4
  148. package/src/Shared/Libs/mrz.utils.ts +3 -2
  149. package/src/Shared/Libs/status-bar.utils.ts +4 -2
  150. package/src/Shared/Services/VideoSessionService.ts +1 -1
  151. package/src/Shared/Types/analytics.types.ts +2 -0
  152. package/src/Shared/Types/identificationInfo.ts +11 -0
  153. package/src/Translation/Resources/en.ts +63 -3
  154. package/src/Translation/Resources/tr.ts +62 -3
  155. package/src/Trustchex.tsx +53 -17
  156. package/src/version.ts +1 -1
@@ -30,10 +30,27 @@ const IdentityDocumentEIDScanningScreen = () => {
30
30
  useState<DocumentScannedData | null>(null);
31
31
  const [passportData, setPassportData] =
32
32
  useState<DocumentScannedData | null>();
33
- const [documentNumber, setDocumentNumber] = useState<string>();
34
- const [dateOfBirth, setDateOfBirth] = useState<string>();
35
- const [dateOfExpiry, setDateOfExpiry] = useState<string>();
36
- const [documentType, setDocumentType] = useState<string>();
33
+ const [documentNumber, setDocumentNumber] = useState<string | undefined>(
34
+ () => {
35
+ const mrzFields =
36
+ appContext.identificationInfo.scannedDocument?.mrzFields;
37
+ return mrzFields?.documentNumber ?? undefined;
38
+ }
39
+ );
40
+ const [dateOfBirth, setDateOfBirth] = useState<string | undefined>(() => {
41
+ const mrzFields = appContext.identificationInfo.scannedDocument?.mrzFields;
42
+ return mrzFields?.birthDate ?? undefined;
43
+ });
44
+ const [dateOfExpiry, setDateOfExpiry] = useState<string | undefined>(() => {
45
+ const mrzFields = appContext.identificationInfo.scannedDocument?.mrzFields;
46
+ return mrzFields?.expirationDate ?? undefined;
47
+ });
48
+ const [documentType, setDocumentType] = useState<string | undefined>(() => {
49
+ const dc =
50
+ appContext.identificationInfo.scannedDocument?.mrzFields?.documentCode;
51
+ if (!dc) return undefined;
52
+ return dc === 'I' ? 'ID' : dc === 'P' ? 'PASSPORT' : 'UNKNOWN';
53
+ });
37
54
  const [isNFCSupported, setIsNFCSupported] = useState<boolean>(false);
38
55
  const { t } = useTranslation();
39
56
  const [allowedDocumentTypes, setAllowedDocumentTypes] = useState<
@@ -9,10 +9,13 @@ import React, {
9
9
  useRef,
10
10
  } from 'react';
11
11
  import {
12
+ Animated,
13
+ Easing,
12
14
  StyleSheet,
13
15
  Text,
14
16
  View,
15
17
  Dimensions,
18
+ Platform,
16
19
  Vibration,
17
20
  StatusBar,
18
21
  } from 'react-native';
@@ -27,7 +30,7 @@ import NavigationManager, {
27
30
  type NavigationManagerRef,
28
31
  } from '../../Shared/Components/NavigationManager';
29
32
  import AppContext from '../../Shared/Contexts/AppContext';
30
- import { contains, type Rect } from '../../Shared/Libs/contains';
33
+ import { type Rect } from '../../Shared/Libs/contains';
31
34
  import { useTranslation } from 'react-i18next';
32
35
  import StyledButton from '../../Shared/Components/StyledButton';
33
36
  import LottieView from 'lottie-react-native';
@@ -43,7 +46,7 @@ import { useKeepAwake } from '../../Shared/Libs/native-keep-awake.utils';
43
46
 
44
47
  const { width: windowWidth, height: windowHeight } = Dimensions.get('window');
45
48
 
46
- const PREVIEW_SIZE = windowWidth * 0.8;
49
+ const PREVIEW_SIZE = windowWidth * 0.95;
47
50
  const PREVIEW_RECT: Rect = {
48
51
  minX: (windowWidth - PREVIEW_SIZE) / 2,
49
52
  minY: (windowHeight - PREVIEW_SIZE) / 2,
@@ -96,10 +99,36 @@ const LivenessDetectionScreen = () => {
96
99
  const [isRecording, setIsRecording] = useState(false);
97
100
  const insets = useSafeAreaInsets();
98
101
  const referenceFaceTrackingId = useRef<number | null>(null);
102
+ const recordingDotOpacity = useRef(new Animated.Value(1)).current;
99
103
 
100
104
  // Track screen view and exit
101
105
  useScreenTracking('liveness_detection');
102
106
 
107
+ useEffect(() => {
108
+ if (isRecording) {
109
+ const pulse = Animated.loop(
110
+ Animated.sequence([
111
+ Animated.timing(recordingDotOpacity, {
112
+ toValue: 0.2,
113
+ duration: 600,
114
+ easing: Easing.inOut(Easing.ease),
115
+ useNativeDriver: true,
116
+ }),
117
+ Animated.timing(recordingDotOpacity, {
118
+ toValue: 1,
119
+ duration: 600,
120
+ easing: Easing.inOut(Easing.ease),
121
+ useNativeDriver: true,
122
+ }),
123
+ ])
124
+ );
125
+ pulse.start();
126
+ return () => pulse.stop();
127
+ } else {
128
+ recordingDotOpacity.setValue(1);
129
+ }
130
+ }, [isRecording, recordingDotOpacity]);
131
+
103
132
  // Configure status bar for white background
104
133
  useStatusBarWhiteBackground();
105
134
 
@@ -167,7 +196,9 @@ const LivenessDetectionScreen = () => {
167
196
  } else {
168
197
  // Guide screen with white background - use dark icons
169
198
  StatusBar.setBarStyle('dark-content', true);
170
- StatusBar.setBackgroundColor('#ffffff', true);
199
+ if (Platform.OS === 'android') {
200
+ StatusBar.setBackgroundColor('#ffffff', true);
201
+ }
171
202
  }
172
203
  }, [hasGuideShown]);
173
204
 
@@ -289,6 +320,14 @@ const LivenessDetectionScreen = () => {
289
320
  return leftOpen >= 0.8 && rightOpen >= 0.8;
290
321
  };
291
322
 
323
+ const areEyesVisible = (face: Face) => {
324
+ // Relaxed check: eyes just need to be detected (not fully closed).
325
+ // Smiling naturally causes squinting, so a lower threshold is used.
326
+ const leftOpen = face.leftEyeOpenProbability ?? 0;
327
+ const rightOpen = face.rightEyeOpenProbability ?? 0;
328
+ return leftOpen >= 0.3 && rightOpen >= 0.3;
329
+ };
330
+
292
331
  const instructionReducer = (
293
332
  state: StateType,
294
333
  action: PossibleActions
@@ -526,26 +565,42 @@ const LivenessDetectionScreen = () => {
526
565
  );
527
566
  }
528
567
 
529
- // Calculate preview rect in frame coordinates (not screen coordinates)
530
- // Preview circle is 80% of frame width, centered
531
- const previewSizeInFrame = frameWidth * 0.8;
568
+ // Map the on-screen circle into frame coordinates.
569
+ // Camera uses FILL_CENTER / resizeAspectFill (cover): uniform scale filling
570
+ // the view, cropping overflow symmetrically.
571
+ const coverScale = Math.max(
572
+ windowWidth / frameWidth,
573
+ windowHeight / frameHeight
574
+ );
575
+ const offsetX = (frameWidth - windowWidth / coverScale) / 2;
576
+ const offsetY = (frameHeight - windowHeight / coverScale) / 2;
532
577
  const previewRectInFrame: Rect = {
533
- minX: (frameWidth - previewSizeInFrame) / 2,
534
- minY: (frameHeight - previewSizeInFrame) / 2,
535
- width: previewSizeInFrame,
536
- height: previewSizeInFrame,
578
+ minX: PREVIEW_RECT.minX / coverScale + offsetX,
579
+ minY: PREVIEW_RECT.minY / coverScale + offsetY,
580
+ width: PREVIEW_RECT.width / coverScale,
581
+ height: PREVIEW_RECT.height / coverScale,
537
582
  };
538
-
539
- const faceRectSmaller: Rect = {
540
- width: face.bounds.width - PREVIEW_EDGE_OFFSET,
541
- height: face.bounds.height - PREVIEW_EDGE_OFFSET,
542
- minY: face.bounds.y + PREVIEW_EDGE_OFFSET / 2,
543
- minX: face.bounds.x + PREVIEW_EDGE_OFFSET / 2,
544
- };
545
- const previewContainsFace = contains({
546
- outside: previewRectInFrame,
547
- inside: faceRectSmaller,
548
- });
583
+ const previewSizeInFrame = PREVIEW_RECT.width / coverScale;
584
+
585
+ // Check containment using face center + yaw-stable core radius.
586
+ // When the head turns (yaw), the bounding box grows wider but height stays
587
+ // constant so min(width, height)/2 gives a stable size that doesn't
588
+ // falsely trigger an outside-circle reset during TURN_HEAD_LEFT/RIGHT.
589
+ const faceCenterX = face.bounds.x + face.bounds.width / 2;
590
+ const faceCenterY = face.bounds.y + face.bounds.height / 2;
591
+ const faceCoreRadius = Math.max(
592
+ 0,
593
+ Math.min(face.bounds.width, face.bounds.height) / 2 -
594
+ PREVIEW_EDGE_OFFSET / 2
595
+ );
596
+ const circleCX = previewRectInFrame.minX + previewRectInFrame.width / 2;
597
+ const circleCY = previewRectInFrame.minY + previewRectInFrame.height / 2;
598
+ const circleR = previewSizeInFrame / 2;
599
+ const faceDx = faceCenterX - circleCX;
600
+ const faceDy = faceCenterY - circleCY;
601
+ const previewContainsFace =
602
+ faceDx * faceDx + faceDy * faceDy <=
603
+ (circleR - faceCoreRadius) * (circleR - faceCoreRadius);
549
604
  const multipleFacesDetected = faces.length > 1;
550
605
 
551
606
  if (!isImageBright) {
@@ -694,11 +749,12 @@ const LivenessDetectionScreen = () => {
694
749
  instructions.SMILE.minAngle < face.pitchAngle &&
695
750
  face.pitchAngle < instructions.SMILE.maxAngle;
696
751
 
697
- // Check if smiling with sufficient probability AND looking at camera AND eyes open
752
+ // Check if smiling with sufficient probability AND looking at camera AND eyes visible
753
+ // Use relaxed eye check — smiling naturally causes squinting
698
754
  if (
699
755
  smilingProb >= instructions.SMILE.minProbability &&
700
756
  isFacingCamera &&
701
- areEyesOpen(face)
757
+ areEyesVisible(face)
702
758
  ) {
703
759
  instructions.SMILE.photo = image;
704
760
  dispatch({ type: 'NEXT_INSTRUCTION', payload: 'SMILE' });
@@ -890,6 +946,24 @@ const LivenessDetectionScreen = () => {
890
946
  mask="url(#hole-mask)"
891
947
  />
892
948
  </Svg>
949
+ {isRecording && (
950
+ <View
951
+ style={[
952
+ styles.recordingIndicatorContainer,
953
+ { top: PREVIEW_RECT.minY - 40 },
954
+ ]}
955
+ >
956
+ <View style={styles.recordingIndicator}>
957
+ <Animated.View
958
+ style={[
959
+ styles.recordingDot,
960
+ { opacity: recordingDotOpacity },
961
+ ]}
962
+ />
963
+ <Text style={styles.recordingText}>REC</Text>
964
+ </View>
965
+ </View>
966
+ )}
893
967
  <View
894
968
  style={[
895
969
  styles.instructionsContainerBottom,
@@ -1014,6 +1088,33 @@ const styles = StyleSheet.create({
1014
1088
  width: '100%',
1015
1089
  zIndex: 1,
1016
1090
  },
1091
+ recordingIndicatorContainer: {
1092
+ position: 'absolute',
1093
+ width: '100%',
1094
+ alignItems: 'center',
1095
+ zIndex: 2,
1096
+ },
1097
+ recordingIndicator: {
1098
+ flexDirection: 'row',
1099
+ alignItems: 'center',
1100
+ gap: 8,
1101
+ backgroundColor: 'rgba(0, 0, 0, 0.6)',
1102
+ paddingVertical: 6,
1103
+ paddingHorizontal: 14,
1104
+ borderRadius: 20,
1105
+ },
1106
+ recordingDot: {
1107
+ width: 10,
1108
+ height: 10,
1109
+ borderRadius: 5,
1110
+ backgroundColor: '#ef4444',
1111
+ },
1112
+ recordingText: {
1113
+ color: '#ffffff',
1114
+ fontSize: 14,
1115
+ fontWeight: '700',
1116
+ letterSpacing: 1,
1117
+ },
1017
1118
  guide: {
1018
1119
  flex: 1,
1019
1120
  display: 'flex',