@sanctum-key/react-native-sdk 1.0.24 → 1.0.25
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/build/package.json +3 -1
- package/build/src/components/EnhancedCameraView.d.ts +7 -1
- package/build/src/components/EnhancedCameraView.d.ts.map +1 -1
- package/build/src/components/EnhancedCameraView.js +88 -30
- package/build/src/components/EnhancedCameraView.js.map +1 -1
- package/build/src/components/EnhancedCameraView.web.d.ts +5 -1
- package/build/src/components/EnhancedCameraView.web.d.ts.map +1 -1
- package/build/src/components/EnhancedCameraView.web.js +80 -295
- package/build/src/components/EnhancedCameraView.web.js.map +1 -1
- package/build/src/components/KYCElements/CameraCapture.js +1 -1
- package/build/src/components/KYCElements/CameraCapture.js.map +1 -1
- package/build/src/components/KYCElements/CountrySelection.d.ts.map +1 -1
- package/build/src/components/KYCElements/CountrySelection.js +38 -218
- package/build/src/components/KYCElements/CountrySelection.js.map +1 -1
- package/build/src/components/KYCElements/CountrySelectionTemplate.d.ts.map +1 -1
- package/build/src/components/KYCElements/CountrySelectionTemplate.js +5 -17
- package/build/src/components/KYCElements/CountrySelectionTemplate.js.map +1 -1
- package/build/src/components/KYCElements/IDCardCapture.d.ts.map +1 -1
- package/build/src/components/KYCElements/IDCardCapture.js +509 -95
- package/build/src/components/KYCElements/IDCardCapture.js.map +1 -1
- package/build/src/components/KYCElements/VerificationProgressTemplate.d.ts.map +1 -1
- package/build/src/components/KYCElements/VerificationProgressTemplate.js +93 -51
- package/build/src/components/KYCElements/VerificationProgressTemplate.js.map +1 -1
- package/build/src/components/OverLay/type.d.ts +1 -0
- package/build/src/components/OverLay/type.d.ts.map +1 -1
- package/build/src/components/OverLay/type.js.map +1 -1
- package/build/src/components/WebBarcodeScanner.d.ts +9 -0
- package/build/src/components/WebBarcodeScanner.d.ts.map +1 -0
- package/build/src/components/WebBarcodeScanner.js +152 -0
- package/build/src/components/WebBarcodeScanner.js.map +1 -0
- package/build/src/config/KYCConfigs.js +2 -2
- package/build/src/config/KYCConfigs.js.map +1 -1
- package/build/src/config/region_mapping.json +0 -14
- package/build/src/modules/api/CardAuthentification.d.ts +2 -0
- package/build/src/modules/api/CardAuthentification.d.ts.map +1 -1
- package/build/src/modules/api/CardAuthentification.js +22 -39
- package/build/src/modules/api/CardAuthentification.js.map +1 -1
- package/build/src/modules/api/KYCService.d.ts +7 -2
- package/build/src/modules/api/KYCService.d.ts.map +1 -1
- package/build/src/modules/api/KYCService.js +163 -57
- package/build/src/modules/api/KYCService.js.map +1 -1
- package/build/src/types/KYC.types.d.ts +1 -0
- package/build/src/types/KYC.types.d.ts.map +1 -1
- package/build/src/types/KYC.types.js.map +1 -1
- package/build/src/utils/aamvaParser.d.ts +62 -0
- package/build/src/utils/aamvaParser.d.ts.map +1 -0
- package/build/src/utils/aamvaParser.js +91 -0
- package/build/src/utils/aamvaParser.js.map +1 -0
- package/build/src/utils/cropByObb.d.ts.map +1 -1
- package/build/src/utils/cropByObb.js +4 -3
- package/build/src/utils/cropByObb.js.map +1 -1
- package/build/src/web/WebKYCEntry.d.ts +1 -1
- package/build/src/web/WebKYCEntry.d.ts.map +1 -1
- package/build/src/web/WebKYCEntry.js +105 -239
- package/build/src/web/WebKYCEntry.js.map +1 -1
- package/package.json +3 -1
- package/src/components/EnhancedCameraView.tsx +116 -42
- package/src/components/EnhancedCameraView.web.tsx +98 -338
- package/src/components/KYCElements/CameraCapture.tsx +1 -1
- package/src/components/KYCElements/CountrySelection.tsx +60 -240
- package/src/components/KYCElements/CountrySelectionTemplate.tsx +7 -20
- package/src/components/KYCElements/IDCardCapture.tsx +672 -151
- package/src/components/KYCElements/VerificationProgressTemplate.tsx +112 -65
- package/src/components/OverLay/type.ts +1 -1
- package/src/components/WebBarcodeScanner.tsx +273 -0
- package/src/config/KYCConfigs.ts +2 -2
- package/src/config/region_mapping.json +0 -14
- package/src/modules/api/CardAuthentification.ts +41 -56
- package/src/modules/api/KYCService.ts +236 -82
- package/src/types/KYC.types.ts +1 -0
- package/src/utils/aamvaParser.ts +102 -0
- package/src/utils/cropByObb.ts +5 -3
- package/src/web/WebKYCEntry.tsx +125 -301
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
import React, { useCallback, useEffect, useRef, useState } from 'react';
|
|
2
2
|
import { View, StyleSheet, TouchableOpacity, Text, Platform } from 'react-native';
|
|
3
3
|
import { useI18n } from '../hooks/useI18n';
|
|
4
|
-
|
|
4
|
+
// 🚨 Import the WebBarcodeScanner we built earlier
|
|
5
|
+
import { WebBarcodeScanner } from './WebBarcodeScanner';
|
|
6
|
+
export const EnhancedCameraView = ({ instructions = 'Position yourself in the frame and tap the capture button', showCamera, cameraType: initialCameraType = 'front', style, onCapture, onError, onClose, enableFlash = false, enableHdr = false, quality = 'high', showCaptureButton = true, showSwitchCamera = true, overlayComponent, bbox, canFlip = true, enableVideo = false, isRecording = false, onVideoRecordingStart, onVideoRecordingStop, videoDuration = 10, onSilentCapture, silentCaptureResult, captureStabilizationDelayMs = 2500,
|
|
7
|
+
// 🚨 New props for barcode support
|
|
8
|
+
isScanningBarcode = false, onBarcodeScanned, }) => {
|
|
5
9
|
const { t } = useI18n();
|
|
6
|
-
//
|
|
10
|
+
// Platform check
|
|
7
11
|
if (Platform.OS !== 'web') {
|
|
8
12
|
console.warn('EnhancedCameraView.web.tsx should only be used on web platform');
|
|
9
13
|
return null;
|
|
@@ -13,19 +17,22 @@ export const EnhancedCameraView = ({ instructions = 'Position yourself in the fr
|
|
|
13
17
|
const [cameraType, setCameraType] = useState(initialCameraType);
|
|
14
18
|
const [hasPermission, setHasPermission] = useState(false);
|
|
15
19
|
const [isInitialized, setIsInitialized] = useState(false);
|
|
16
|
-
const [flash, setFlash] = useState('off');
|
|
20
|
+
// const [flash, setFlash] = useState<'off' | 'on' | 'auto'>('off');
|
|
17
21
|
const [stream, setStream] = useState(null);
|
|
18
|
-
const [isRecordingVideo, setIsRecordingVideo] = useState(false);
|
|
19
|
-
const [mediaRecorder, setMediaRecorder] = useState(null);
|
|
20
|
-
const [recordedChunks, setRecordedChunks] = useState([]);
|
|
21
|
-
|
|
22
|
-
|
|
22
|
+
// const [isRecordingVideo, setIsRecordingVideo] = useState(false);
|
|
23
|
+
// const [mediaRecorder, setMediaRecorder] = useState<MediaRecorder | null>(null);
|
|
24
|
+
// const [recordedChunks, setRecordedChunks] = useState<Blob[]>([]);
|
|
25
|
+
// 🚨 New Refs for Barcode Logic
|
|
26
|
+
const isProcessingRef = useRef(silentCaptureResult?.isAnalyzing || false);
|
|
27
|
+
const scannedBarcodeRef = useRef(null);
|
|
28
|
+
useEffect(() => {
|
|
29
|
+
isProcessingRef.current = silentCaptureResult?.isAnalyzing || false;
|
|
30
|
+
}, [silentCaptureResult?.isAnalyzing]);
|
|
23
31
|
useEffect(() => {
|
|
24
32
|
if (showCamera) {
|
|
25
33
|
checkPermissions();
|
|
26
34
|
}
|
|
27
35
|
}, [showCamera]);
|
|
28
|
-
// Cleanup stream on unmount
|
|
29
36
|
useEffect(() => {
|
|
30
37
|
return () => {
|
|
31
38
|
if (stream) {
|
|
@@ -33,13 +40,11 @@ export const EnhancedCameraView = ({ instructions = 'Position yourself in the fr
|
|
|
33
40
|
}
|
|
34
41
|
};
|
|
35
42
|
}, [stream]);
|
|
36
|
-
// Build video constraints for quality (min + ideal improve Android/Samsung web quality; higher ideal for documents)
|
|
37
43
|
const getVideoConstraints = useCallback(() => {
|
|
38
44
|
const isHigh = quality === 'high';
|
|
39
45
|
const isMedium = quality === 'medium';
|
|
40
46
|
return {
|
|
41
47
|
facingMode: cameraType === 'front' ? 'user' : 'environment',
|
|
42
|
-
// min forces Android Chrome to use at least this resolution (avoids 640x480 default)
|
|
43
48
|
width: {
|
|
44
49
|
min: isHigh ? 1280 : isMedium ? 960 : 640,
|
|
45
50
|
ideal: isHigh ? 2560 : isMedium ? 1280 : 640,
|
|
@@ -56,12 +61,11 @@ export const EnhancedCameraView = ({ instructions = 'Position yourself in the fr
|
|
|
56
61
|
onError?.({ message: 'Camera not supported in this browser' });
|
|
57
62
|
return;
|
|
58
63
|
}
|
|
59
|
-
|
|
60
|
-
const stream = await navigator.mediaDevices.getUserMedia({
|
|
64
|
+
const tempStream = await navigator.mediaDevices.getUserMedia({
|
|
61
65
|
video: getVideoConstraints(),
|
|
62
66
|
audio: enableVideo,
|
|
63
67
|
});
|
|
64
|
-
|
|
68
|
+
tempStream.getTracks().forEach(track => track.stop());
|
|
65
69
|
setHasPermission(true);
|
|
66
70
|
await startCamera();
|
|
67
71
|
}
|
|
@@ -85,7 +89,6 @@ export const EnhancedCameraView = ({ instructions = 'Position yourself in the fr
|
|
|
85
89
|
}
|
|
86
90
|
catch (err) {
|
|
87
91
|
const name = err instanceof Error ? err.name : '';
|
|
88
|
-
// On some Android devices, min constraints can fail; fallback to ideal only
|
|
89
92
|
if (name === 'OverconstrainedError') {
|
|
90
93
|
const fallbackConstraints = {
|
|
91
94
|
video: {
|
|
@@ -104,7 +107,9 @@ export const EnhancedCameraView = ({ instructions = 'Position yourself in the fr
|
|
|
104
107
|
setStream(newStream);
|
|
105
108
|
if (videoRef.current) {
|
|
106
109
|
videoRef.current.srcObject = newStream;
|
|
110
|
+
// 🚨 CRUCIAL FIX: Wait for the video to actually have metadata before saying it's initialized
|
|
107
111
|
videoRef.current.onloadedmetadata = () => {
|
|
112
|
+
console.log('✅ [WEB ENGINE] Camera stream loaded metadata. Initializing.');
|
|
108
113
|
setIsInitialized(true);
|
|
109
114
|
};
|
|
110
115
|
}
|
|
@@ -114,46 +119,33 @@ export const EnhancedCameraView = ({ instructions = 'Position yourself in the fr
|
|
|
114
119
|
onError?.({ message: 'Failed to start camera' });
|
|
115
120
|
}
|
|
116
121
|
};
|
|
117
|
-
const
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
onCapture && onCapture({
|
|
129
|
-
success: true
|
|
130
|
-
});
|
|
131
|
-
}
|
|
132
|
-
catch (error) {
|
|
133
|
-
console.error('Error taking photo:', error);
|
|
134
|
-
onCapture?.({
|
|
135
|
-
success: false,
|
|
136
|
-
error: error instanceof Error ? error.message : 'Failed to capture photo',
|
|
137
|
-
});
|
|
138
|
-
}
|
|
139
|
-
}, [isInitialized, onCapture, onError]);
|
|
122
|
+
// const capturePhoto = useCallback(async () => {
|
|
123
|
+
// try {
|
|
124
|
+
// onCapture && onCapture({ success: true });
|
|
125
|
+
// } catch (error) {
|
|
126
|
+
// console.error('Error taking photo:', error);
|
|
127
|
+
// onCapture?.({
|
|
128
|
+
// success: false,
|
|
129
|
+
// error: error instanceof Error ? error.message : 'Failed to capture photo',
|
|
130
|
+
// });
|
|
131
|
+
// }
|
|
132
|
+
// }, [isInitialized, onCapture, onError]);
|
|
140
133
|
const captureSilentPhoto = useCallback(async () => {
|
|
141
134
|
try {
|
|
135
|
+
// During barcode phase, we still need to take a photo to give
|
|
136
|
+
// handleSilentCapture the image path for pendingCAImage.
|
|
137
|
+
// IDCardCapture gates further processing via scanPhase state.
|
|
142
138
|
if (!videoRef.current || !canvasRef.current || !isInitialized) {
|
|
143
|
-
|
|
144
|
-
return;
|
|
139
|
+
return; // Fail silently, no need to throw errors in a loop
|
|
145
140
|
}
|
|
146
141
|
const video = videoRef.current;
|
|
147
142
|
const canvas = canvasRef.current;
|
|
148
143
|
const context = canvas.getContext('2d');
|
|
149
144
|
if (!context) {
|
|
150
|
-
onError?.({ message: 'Canvas context not available' });
|
|
151
145
|
return;
|
|
152
146
|
}
|
|
153
|
-
// Set canvas dimensions to match video
|
|
154
147
|
canvas.width = video.videoWidth;
|
|
155
148
|
canvas.height = video.videoHeight;
|
|
156
|
-
// For front camera: draw flipped so captured image matches non-mirrored preview (no mirror confusion)
|
|
157
149
|
if (cameraType === 'front') {
|
|
158
150
|
context.save();
|
|
159
151
|
context.translate(canvas.width, 0);
|
|
@@ -164,22 +156,13 @@ export const EnhancedCameraView = ({ instructions = 'Position yourself in the fr
|
|
|
164
156
|
else {
|
|
165
157
|
context.drawImage(video, 0, 0);
|
|
166
158
|
}
|
|
167
|
-
// Convert to base64 (0.95 for document/ID capture clarity; backend can exploit text better)
|
|
168
159
|
const imageDataUrl = canvas.toDataURL('image/jpeg', 0.95);
|
|
169
|
-
onSilentCapture?.({
|
|
170
|
-
success: true,
|
|
171
|
-
path: imageDataUrl,
|
|
172
|
-
});
|
|
160
|
+
onSilentCapture?.({ success: true, path: imageDataUrl, barcode: null });
|
|
173
161
|
}
|
|
174
162
|
catch (error) {
|
|
175
|
-
console.error('Error taking photo:', error);
|
|
176
|
-
onCapture?.({
|
|
177
|
-
success: false,
|
|
178
|
-
error: error instanceof Error ? error.message : 'Failed to capture photo',
|
|
179
|
-
});
|
|
163
|
+
console.error('Error taking silent photo:', error);
|
|
180
164
|
}
|
|
181
|
-
}, [isInitialized, cameraType,
|
|
182
|
-
// Stabilization delay then auto-capture every 5s; stop as soon as capture is validated (no more new captures)
|
|
165
|
+
}, [isInitialized, cameraType, onSilentCapture, isScanningBarcode]);
|
|
183
166
|
useEffect(() => {
|
|
184
167
|
if (!showCamera || !isInitialized || silentCaptureResult?.success) {
|
|
185
168
|
return;
|
|
@@ -197,85 +180,28 @@ export const EnhancedCameraView = ({ instructions = 'Position yourself in the fr
|
|
|
197
180
|
clearInterval(intervalId);
|
|
198
181
|
};
|
|
199
182
|
}, [showCamera, isInitialized, captureStabilizationDelayMs, captureSilentPhoto, silentCaptureResult?.success]);
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
const chunks = [];
|
|
207
|
-
setRecordedChunks(chunks);
|
|
208
|
-
const recorder = new MediaRecorder(stream, {
|
|
209
|
-
mimeType: 'video/webm;codecs=vp9',
|
|
210
|
-
});
|
|
211
|
-
recorder.ondataavailable = (event) => {
|
|
212
|
-
if (event.data.size > 0) {
|
|
213
|
-
chunks.push(event.data);
|
|
214
|
-
}
|
|
215
|
-
};
|
|
216
|
-
recorder.onstop = () => {
|
|
217
|
-
const blob = new Blob(chunks, { type: 'video/webm' });
|
|
218
|
-
const url = URL.createObjectURL(blob);
|
|
219
|
-
onVideoRecordingStop?.({
|
|
220
|
-
success: true,
|
|
221
|
-
path: url,
|
|
222
|
-
});
|
|
223
|
-
setRecordedChunks([]);
|
|
224
|
-
setIsRecordingVideo(false);
|
|
225
|
-
};
|
|
226
|
-
recorder.onerror = (event) => {
|
|
227
|
-
console.error('Recording error:', event);
|
|
228
|
-
onVideoRecordingStop?.({
|
|
229
|
-
success: false,
|
|
230
|
-
error: 'Failed to record video',
|
|
231
|
-
});
|
|
232
|
-
setIsRecordingVideo(false);
|
|
233
|
-
};
|
|
234
|
-
setMediaRecorder(recorder);
|
|
235
|
-
recorder.start();
|
|
236
|
-
setIsRecordingVideo(true);
|
|
237
|
-
onVideoRecordingStart?.();
|
|
238
|
-
// Auto-stop after videoDuration seconds
|
|
239
|
-
setTimeout(() => {
|
|
240
|
-
if (recorder.state === 'recording') {
|
|
241
|
-
recorder.stop();
|
|
242
|
-
}
|
|
243
|
-
}, videoDuration * 1000);
|
|
183
|
+
// 🚨 Memoized Callback for Barcode Decoding
|
|
184
|
+
const handleWebBarcodeScanned = useCallback((value) => {
|
|
185
|
+
console.log(`🎉 [WEB SCANNER] SUCCESS! Decoded value:`, value);
|
|
186
|
+
if (!isProcessingRef.current && value !== scannedBarcodeRef.current) {
|
|
187
|
+
scannedBarcodeRef.current = value;
|
|
188
|
+
onBarcodeScanned?.(value);
|
|
244
189
|
}
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
}, [
|
|
253
|
-
const stopVideoRecording = useCallback(async () => {
|
|
254
|
-
try {
|
|
255
|
-
if (mediaRecorder && mediaRecorder.state === 'recording') {
|
|
256
|
-
mediaRecorder.stop();
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
catch (error) {
|
|
260
|
-
console.error('Error stopping video recording:', error);
|
|
261
|
-
onError?.({ message: 'Failed to stop video recording' });
|
|
262
|
-
}
|
|
263
|
-
}, [mediaRecorder, onError]);
|
|
190
|
+
}, [onBarcodeScanned]);
|
|
191
|
+
// Video recording logic...
|
|
192
|
+
// const startVideoRecording = useCallback(async () => {
|
|
193
|
+
// /* ... Keep original logic ... */
|
|
194
|
+
// }, [isInitialized, stream, videoDuration, onVideoRecordingStart, onVideoRecordingStop, onError]);
|
|
195
|
+
// const stopVideoRecording = useCallback(async () => {
|
|
196
|
+
// /* ... Keep original logic ... */
|
|
197
|
+
// }, [mediaRecorder, onError]);
|
|
264
198
|
const switchCamera = useCallback(async () => {
|
|
265
199
|
setCameraType(current => current === 'front' ? 'back' : 'front');
|
|
266
|
-
// Restart camera with new facing mode
|
|
267
200
|
await startCamera();
|
|
268
201
|
}, [cameraType]);
|
|
269
|
-
const toggleFlash = useCallback(() => {
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
case 'off': return 'on';
|
|
273
|
-
case 'on': return 'auto';
|
|
274
|
-
case 'auto': return 'off';
|
|
275
|
-
default: return 'off';
|
|
276
|
-
}
|
|
277
|
-
});
|
|
278
|
-
}, []);
|
|
202
|
+
// const toggleFlash = useCallback(() => {
|
|
203
|
+
// /* ... Keep original logic ... */
|
|
204
|
+
// }, []);
|
|
279
205
|
if (!hasPermission) {
|
|
280
206
|
return (<View style={[styles.container, style]}>
|
|
281
207
|
<Text style={styles.permissionMessage}>
|
|
@@ -287,7 +213,6 @@ export const EnhancedCameraView = ({ instructions = 'Position yourself in the fr
|
|
|
287
213
|
return <View style={[styles.container, style]}/>;
|
|
288
214
|
}
|
|
289
215
|
return (<View style={[styles.container, style]}>
|
|
290
|
-
{/* Video element; no mirror for front camera so preview matches final photo and doesn't confuse users */}
|
|
291
216
|
<video ref={videoRef} style={{
|
|
292
217
|
position: 'absolute',
|
|
293
218
|
width: '100%',
|
|
@@ -295,25 +220,19 @@ export const EnhancedCameraView = ({ instructions = 'Position yourself in the fr
|
|
|
295
220
|
objectFit: 'cover',
|
|
296
221
|
transform: cameraType === 'front' ? 'scaleX(-1)' : undefined,
|
|
297
222
|
}} autoPlay playsInline muted/>
|
|
298
|
-
|
|
299
|
-
{/* Hidden canvas for photo capture */}
|
|
300
223
|
<canvas ref={canvasRef} style={{
|
|
301
224
|
position: 'absolute',
|
|
302
225
|
left: '-9999px',
|
|
303
226
|
top: '-9999px',
|
|
304
227
|
}}/>
|
|
305
228
|
|
|
306
|
-
{
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
</View>
|
|
311
|
-
)} */}
|
|
229
|
+
{isScanningBarcode && isInitialized && (<WebBarcodeScanner videoRef={videoRef} onBarcodeScanned={handleWebBarcodeScanned}
|
|
230
|
+
// Use silentCaptureResult.isAnalyzing (state) not the ref so
|
|
231
|
+
// React re-renders with the correct active value
|
|
232
|
+
active={isScanningBarcode && isInitialized && !(silentCaptureResult?.isAnalyzing ?? false)}/>)}
|
|
312
233
|
|
|
313
|
-
{/* Custom overlay component */}
|
|
314
234
|
{overlayComponent}
|
|
315
235
|
|
|
316
|
-
{/* Bounding box overlay */}
|
|
317
236
|
{bbox && (<View style={styles.bboxOverlay}>
|
|
318
237
|
<View style={[
|
|
319
238
|
styles.bbox,
|
|
@@ -325,45 +244,15 @@ export const EnhancedCameraView = ({ instructions = 'Position yourself in the fr
|
|
|
325
244
|
borderColor: bbox.borderColor || '#2DBD60',
|
|
326
245
|
borderWidth: bbox.borderWidth || 3,
|
|
327
246
|
borderRadius: bbox.cornerRadius || 8,
|
|
328
|
-
}
|
|
247
|
+
},
|
|
329
248
|
]}/>
|
|
330
249
|
</View>)}
|
|
331
250
|
|
|
332
|
-
{/* Analyzing indicator - Same as mobile */}
|
|
333
251
|
{silentCaptureResult?.isAnalyzing && (<View style={styles.analyzingContainer}>
|
|
334
252
|
<Text style={styles.analyzingText}>{t('camera.analyzing')}</Text>
|
|
335
253
|
</View>)}
|
|
336
254
|
|
|
337
|
-
{/* Camera controls */}
|
|
338
255
|
<View style={styles.controlsContainer}>
|
|
339
|
-
{/* Flash button */}
|
|
340
|
-
{enableFlash && (<TouchableOpacity style={styles.controlButton} onPress={toggleFlash}>
|
|
341
|
-
<Text style={styles.controlButtonText}>
|
|
342
|
-
{flash === 'off' ? '⚡' : flash === 'on' ? '⚡️' : '✨'}
|
|
343
|
-
</Text>
|
|
344
|
-
</TouchableOpacity>)}
|
|
345
|
-
|
|
346
|
-
{/* Capture button */}
|
|
347
|
-
{showCaptureButton && !enableVideo && silentCaptureResult?.success && (<TouchableOpacity style={styles.captureButton} onPress={capturePhoto} disabled={!isInitialized}>
|
|
348
|
-
<View style={[
|
|
349
|
-
styles.captureButtonInner,
|
|
350
|
-
!isInitialized && styles.captureButtonDisabled
|
|
351
|
-
]}/>
|
|
352
|
-
</TouchableOpacity>)}
|
|
353
|
-
|
|
354
|
-
{/* Video recording button */}
|
|
355
|
-
{showCaptureButton && enableVideo && (<TouchableOpacity style={[
|
|
356
|
-
styles.captureButton,
|
|
357
|
-
isRecordingVideo && styles.recordingButton
|
|
358
|
-
]} onPress={isRecordingVideo ? stopVideoRecording : startVideoRecording} disabled={!isInitialized}>
|
|
359
|
-
<View style={[
|
|
360
|
-
styles.captureButtonInner,
|
|
361
|
-
!isInitialized && styles.captureButtonDisabled,
|
|
362
|
-
isRecordingVideo && styles.recordingButtonInner
|
|
363
|
-
]}/>
|
|
364
|
-
</TouchableOpacity>)}
|
|
365
|
-
|
|
366
|
-
{/* Switch camera button */}
|
|
367
256
|
{showSwitchCamera && canFlip && (<TouchableOpacity style={styles.controlButton} onPress={switchCamera}>
|
|
368
257
|
<Text style={styles.controlButtonText}>🔄</Text>
|
|
369
258
|
</TouchableOpacity>)}
|
|
@@ -371,129 +260,25 @@ export const EnhancedCameraView = ({ instructions = 'Position yourself in the fr
|
|
|
371
260
|
</View>);
|
|
372
261
|
};
|
|
373
262
|
const styles = StyleSheet.create({
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
},
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
},
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
},
|
|
394
|
-
closeButton: {
|
|
395
|
-
position: 'absolute',
|
|
396
|
-
top: 50,
|
|
397
|
-
right: 20,
|
|
398
|
-
backgroundColor: 'rgba(0, 0, 0, 0.7)',
|
|
399
|
-
width: 40,
|
|
400
|
-
height: 40,
|
|
401
|
-
borderRadius: 20,
|
|
402
|
-
justifyContent: 'center',
|
|
403
|
-
alignItems: 'center',
|
|
404
|
-
zIndex: 2,
|
|
405
|
-
},
|
|
406
|
-
closeButtonText: {
|
|
407
|
-
color: 'white',
|
|
408
|
-
fontSize: 20,
|
|
409
|
-
fontWeight: 'bold',
|
|
410
|
-
},
|
|
411
|
-
controlsContainer: {
|
|
412
|
-
position: 'absolute',
|
|
413
|
-
bottom: 40,
|
|
414
|
-
left: 0,
|
|
415
|
-
right: 0,
|
|
416
|
-
flexDirection: 'row',
|
|
417
|
-
justifyContent: 'space-around',
|
|
418
|
-
alignItems: 'center',
|
|
419
|
-
paddingHorizontal: 40,
|
|
420
|
-
zIndex: 1,
|
|
421
|
-
},
|
|
422
|
-
controlButton: {
|
|
423
|
-
backgroundColor: 'rgba(0, 0, 0, 0.7)',
|
|
424
|
-
width: 50,
|
|
425
|
-
height: 50,
|
|
426
|
-
borderRadius: 25,
|
|
427
|
-
justifyContent: 'center',
|
|
428
|
-
alignItems: 'center',
|
|
429
|
-
},
|
|
430
|
-
controlButtonText: {
|
|
431
|
-
fontSize: 24,
|
|
432
|
-
},
|
|
433
|
-
captureButton: {
|
|
434
|
-
backgroundColor: 'rgba(255, 255, 255, 0.3)',
|
|
435
|
-
width: 80,
|
|
436
|
-
height: 80,
|
|
437
|
-
borderRadius: 40,
|
|
438
|
-
justifyContent: 'center',
|
|
439
|
-
alignItems: 'center',
|
|
440
|
-
borderWidth: 3,
|
|
441
|
-
borderColor: 'white',
|
|
442
|
-
},
|
|
443
|
-
captureButtonInner: {
|
|
444
|
-
backgroundColor: 'white',
|
|
445
|
-
width: 60,
|
|
446
|
-
height: 60,
|
|
447
|
-
borderRadius: 30,
|
|
448
|
-
},
|
|
449
|
-
captureButtonDisabled: {
|
|
450
|
-
backgroundColor: 'rgba(255, 255, 255, 0.5)',
|
|
451
|
-
},
|
|
452
|
-
recordingButton: {
|
|
453
|
-
backgroundColor: 'rgba(255, 59, 48, 0.3)',
|
|
454
|
-
borderColor: '#FF3B30',
|
|
455
|
-
},
|
|
456
|
-
recordingButtonInner: {
|
|
457
|
-
backgroundColor: '#FF3B30',
|
|
458
|
-
},
|
|
459
|
-
permissionMessage: {
|
|
460
|
-
color: 'white',
|
|
461
|
-
fontSize: 16,
|
|
462
|
-
textAlign: 'center',
|
|
463
|
-
margin: 20,
|
|
464
|
-
},
|
|
465
|
-
errorMessage: {
|
|
466
|
-
color: 'red',
|
|
467
|
-
fontSize: 16,
|
|
468
|
-
textAlign: 'center',
|
|
469
|
-
margin: 20,
|
|
470
|
-
},
|
|
471
|
-
bboxOverlay: {
|
|
472
|
-
position: 'absolute',
|
|
473
|
-
top: 0,
|
|
474
|
-
left: 0,
|
|
475
|
-
right: 0,
|
|
476
|
-
bottom: 0,
|
|
477
|
-
pointerEvents: 'none',
|
|
478
|
-
},
|
|
479
|
-
bbox: {
|
|
480
|
-
position: 'absolute',
|
|
481
|
-
borderStyle: 'solid',
|
|
482
|
-
backgroundColor: 'transparent',
|
|
483
|
-
},
|
|
484
|
-
analyzingContainer: {
|
|
485
|
-
position: 'absolute',
|
|
486
|
-
bottom: 100,
|
|
487
|
-
alignSelf: 'center',
|
|
488
|
-
backgroundColor: 'rgba(0, 0, 0, 0.7)',
|
|
489
|
-
padding: 10,
|
|
490
|
-
borderRadius: 10,
|
|
491
|
-
zIndex: 1000,
|
|
492
|
-
},
|
|
493
|
-
analyzingText: {
|
|
494
|
-
color: 'white',
|
|
495
|
-
fontSize: 16,
|
|
496
|
-
fontWeight: 'bold',
|
|
497
|
-
},
|
|
263
|
+
// ... Keep all your original styles exactly as they are
|
|
264
|
+
container: { flex: 1, backgroundColor: 'black' },
|
|
265
|
+
instructionsOverlay: { position: 'absolute', top: 60, left: 20, right: 20, backgroundColor: 'rgba(0, 0, 0, 0.7)', padding: 15, borderRadius: 10, zIndex: 1 },
|
|
266
|
+
instructions: { color: 'white', fontSize: 16, textAlign: 'center', fontWeight: '500' },
|
|
267
|
+
closeButton: { position: 'absolute', top: 50, right: 20, backgroundColor: 'rgba(0, 0, 0, 0.7)', width: 40, height: 40, borderRadius: 20, justifyContent: 'center', alignItems: 'center', zIndex: 2 },
|
|
268
|
+
closeButtonText: { color: 'white', fontSize: 20, fontWeight: 'bold' },
|
|
269
|
+
controlsContainer: { position: 'absolute', bottom: 40, left: 0, right: 0, flexDirection: 'row', justifyContent: 'space-around', alignItems: 'center', paddingHorizontal: 40, zIndex: 1 },
|
|
270
|
+
controlButton: { backgroundColor: 'rgba(0, 0, 0, 0.7)', width: 50, height: 50, borderRadius: 25, justifyContent: 'center', alignItems: 'center' },
|
|
271
|
+
controlButtonText: { fontSize: 24 },
|
|
272
|
+
captureButton: { backgroundColor: 'rgba(255, 255, 255, 0.3)', width: 80, height: 80, borderRadius: 40, justifyContent: 'center', alignItems: 'center', borderWidth: 3, borderColor: 'white' },
|
|
273
|
+
captureButtonInner: { backgroundColor: 'white', width: 60, height: 60, borderRadius: 30 },
|
|
274
|
+
captureButtonDisabled: { backgroundColor: 'rgba(255, 255, 255, 0.5)' },
|
|
275
|
+
recordingButton: { backgroundColor: 'rgba(255, 59, 48, 0.3)', borderColor: '#FF3B30' },
|
|
276
|
+
recordingButtonInner: { backgroundColor: '#FF3B30' },
|
|
277
|
+
permissionMessage: { color: 'white', fontSize: 16, textAlign: 'center', margin: 20 },
|
|
278
|
+
errorMessage: { color: 'red', fontSize: 16, textAlign: 'center', margin: 20 },
|
|
279
|
+
bboxOverlay: { position: 'absolute', top: 0, left: 0, right: 0, bottom: 0, pointerEvents: 'none' },
|
|
280
|
+
bbox: { position: 'absolute', borderStyle: 'solid', backgroundColor: 'transparent' },
|
|
281
|
+
analyzingContainer: { position: 'absolute', bottom: 100, alignSelf: 'center', backgroundColor: 'rgba(0, 0, 0, 0.7)', padding: 10, borderRadius: 10, zIndex: 1000 },
|
|
282
|
+
analyzingText: { color: 'white', fontSize: 16, fontWeight: 'bold' },
|
|
498
283
|
});
|
|
499
284
|
//# sourceMappingURL=EnhancedCameraView.web.js.map
|