react-native-rectangle-doc-scanner 3.59.0 → 3.61.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/dist/DocScanner.js +2 -1
- package/dist/FullDocScanner.js +69 -34
- package/package.json +1 -1
- package/src/DocScanner.tsx +2 -1
- package/src/FullDocScanner.tsx +83 -38
package/dist/DocScanner.js
CHANGED
|
@@ -167,7 +167,8 @@ exports.DocScanner = (0, react_1.forwardRef)(({ onCapture, overlayColor = DEFAUL
|
|
|
167
167
|
captureOriginRef.current = 'manual';
|
|
168
168
|
capture().catch((error) => {
|
|
169
169
|
captureOriginRef.current = 'auto';
|
|
170
|
-
console.
|
|
170
|
+
console.error('[DocScanner] manual capture failed', error);
|
|
171
|
+
throw error;
|
|
171
172
|
});
|
|
172
173
|
}, [capture]);
|
|
173
174
|
const handleRectangleDetect = (0, react_1.useCallback)((event) => {
|
package/dist/FullDocScanner.js
CHANGED
|
@@ -83,8 +83,15 @@ const FullDocScanner = ({ onResult, onClose, detectionConfig, overlayColor = '#3
|
|
|
83
83
|
try {
|
|
84
84
|
console.log('[FullDocScanner] openCropper called with path:', imagePath);
|
|
85
85
|
setProcessing(true);
|
|
86
|
+
// Clean path - remove file:// prefix for react-native-image-crop-picker
|
|
87
|
+
// The library handles the prefix internally and double prefixing causes issues
|
|
88
|
+
let cleanPath = imagePath;
|
|
89
|
+
if (cleanPath.startsWith('file://')) {
|
|
90
|
+
cleanPath = cleanPath.replace('file://', '');
|
|
91
|
+
}
|
|
92
|
+
console.log('[FullDocScanner] Clean path for cropper:', cleanPath);
|
|
86
93
|
const croppedImage = await react_native_image_crop_picker_1.default.openCropper({
|
|
87
|
-
path:
|
|
94
|
+
path: cleanPath,
|
|
88
95
|
mediaType: 'photo',
|
|
89
96
|
width: cropWidth,
|
|
90
97
|
height: cropHeight,
|
|
@@ -99,7 +106,7 @@ const FullDocScanner = ({ onResult, onClose, detectionConfig, overlayColor = '#3
|
|
|
99
106
|
hasBase64: !!croppedImage.data,
|
|
100
107
|
});
|
|
101
108
|
setProcessing(false);
|
|
102
|
-
// Show
|
|
109
|
+
// Show confirmation screen
|
|
103
110
|
setCroppedImageData({
|
|
104
111
|
path: croppedImage.path,
|
|
105
112
|
base64: croppedImage.data ?? undefined,
|
|
@@ -108,11 +115,14 @@ const FullDocScanner = ({ onResult, onClose, detectionConfig, overlayColor = '#3
|
|
|
108
115
|
catch (error) {
|
|
109
116
|
console.error('[FullDocScanner] openCropper error:', error);
|
|
110
117
|
setProcessing(false);
|
|
111
|
-
|
|
112
|
-
|
|
118
|
+
const errorMessage = error?.message || String(error);
|
|
119
|
+
if (errorMessage === 'User cancelled image selection' ||
|
|
120
|
+
errorMessage.includes('cancelled') ||
|
|
121
|
+
errorMessage.includes('cancel')) {
|
|
122
|
+
console.log('[FullDocScanner] User cancelled cropper');
|
|
113
123
|
}
|
|
114
124
|
else {
|
|
115
|
-
|
|
125
|
+
emitError(error instanceof Error ? error : new Error(errorMessage), 'Failed to crop image. Please try again.');
|
|
116
126
|
}
|
|
117
127
|
}
|
|
118
128
|
}, [cropWidth, cropHeight, emitError]);
|
|
@@ -123,19 +133,16 @@ const FullDocScanner = ({ onResult, onClose, detectionConfig, overlayColor = '#3
|
|
|
123
133
|
croppedPath: document.croppedPath,
|
|
124
134
|
initialPath: document.initialPath,
|
|
125
135
|
captureMode: captureModeRef.current,
|
|
136
|
+
captureInProgress: captureInProgressRef.current,
|
|
126
137
|
});
|
|
127
|
-
captureInProgressRef.current = false;
|
|
128
|
-
if (document.origin === 'auto') {
|
|
129
|
-
console.log('[FullDocScanner] Ignoring auto capture result');
|
|
130
|
-
return;
|
|
131
|
-
}
|
|
132
138
|
const captureMode = captureModeRef.current;
|
|
139
|
+
// Reset capture state
|
|
140
|
+
captureInProgressRef.current = false;
|
|
141
|
+
captureModeRef.current = null;
|
|
133
142
|
if (!captureMode) {
|
|
134
|
-
console.warn('[FullDocScanner] Missing capture mode for
|
|
135
|
-
captureModeRef.current = null;
|
|
143
|
+
console.warn('[FullDocScanner] Missing capture mode for capture result, ignoring');
|
|
136
144
|
return;
|
|
137
145
|
}
|
|
138
|
-
captureModeRef.current = null;
|
|
139
146
|
const normalizedDoc = normalizeCapturedDocument(document);
|
|
140
147
|
if (captureMode === 'no-grid') {
|
|
141
148
|
console.log('[FullDocScanner] No grid at capture button press: opening cropper for manual selection');
|
|
@@ -178,35 +185,58 @@ const FullDocScanner = ({ onResult, onClose, detectionConfig, overlayColor = '#3
|
|
|
178
185
|
const captureMode = rectangleDetected ? 'grid' : 'no-grid';
|
|
179
186
|
captureModeRef.current = captureMode;
|
|
180
187
|
captureInProgressRef.current = true;
|
|
188
|
+
// Add timeout to reset state if capture hangs
|
|
189
|
+
const captureTimeout = setTimeout(() => {
|
|
190
|
+
if (captureInProgressRef.current) {
|
|
191
|
+
console.error('[FullDocScanner] Capture timeout - resetting state');
|
|
192
|
+
captureModeRef.current = null;
|
|
193
|
+
captureInProgressRef.current = false;
|
|
194
|
+
emitError(new Error('Capture timeout'), 'Capture timed out. Please try again.');
|
|
195
|
+
}
|
|
196
|
+
}, 10000);
|
|
181
197
|
scannerInstance.capture()
|
|
182
198
|
.then((result) => {
|
|
183
|
-
|
|
184
|
-
|
|
199
|
+
clearTimeout(captureTimeout);
|
|
200
|
+
console.log('[FullDocScanner] Manual capture promise resolved:', {
|
|
201
|
+
hasResult: !!result,
|
|
202
|
+
croppedImage: result?.croppedImage,
|
|
203
|
+
initialImage: result?.initialImage,
|
|
204
|
+
});
|
|
205
|
+
// Note: captureInProgressRef is reset in handleCapture
|
|
185
206
|
})
|
|
186
207
|
.catch((error) => {
|
|
208
|
+
clearTimeout(captureTimeout);
|
|
209
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
210
|
+
console.error('[FullDocScanner] Manual capture failed:', errorMessage, error);
|
|
187
211
|
captureModeRef.current = null;
|
|
188
212
|
captureInProgressRef.current = false;
|
|
189
|
-
console.error('[FullDocScanner] Manual capture failed:', error);
|
|
190
213
|
if (error instanceof Error && error.message !== 'capture_in_progress') {
|
|
191
|
-
emitError(error, 'Failed to capture image.');
|
|
214
|
+
emitError(error, 'Failed to capture image. Please try again.');
|
|
192
215
|
}
|
|
193
216
|
});
|
|
194
217
|
}, [processing, rectangleDetected, emitError]);
|
|
195
218
|
const handleGalleryPick = (0, react_1.useCallback)(async () => {
|
|
196
219
|
console.log('[FullDocScanner] handleGalleryPick called');
|
|
197
220
|
if (processing || isGalleryOpen) {
|
|
221
|
+
console.log('[FullDocScanner] Skipping gallery pick - already processing:', { processing, isGalleryOpen });
|
|
198
222
|
return;
|
|
199
223
|
}
|
|
200
224
|
try {
|
|
201
225
|
setIsGalleryOpen(true);
|
|
226
|
+
console.log('[FullDocScanner] Launching image library...');
|
|
202
227
|
const result = await (0, react_native_image_picker_1.launchImageLibrary)({
|
|
203
228
|
mediaType: 'photo',
|
|
204
229
|
quality: 1,
|
|
205
230
|
selectionLimit: 1,
|
|
206
231
|
});
|
|
232
|
+
console.log('[FullDocScanner] Image library result:', {
|
|
233
|
+
didCancel: result.didCancel,
|
|
234
|
+
hasAssets: !!result.assets,
|
|
235
|
+
assetsLength: result.assets?.length,
|
|
236
|
+
});
|
|
207
237
|
setIsGalleryOpen(false);
|
|
208
238
|
if (result.didCancel || !result.assets?.[0]?.uri) {
|
|
209
|
-
console.log('[FullDocScanner] User cancelled gallery picker');
|
|
239
|
+
console.log('[FullDocScanner] User cancelled gallery picker or no image selected');
|
|
210
240
|
return;
|
|
211
241
|
}
|
|
212
242
|
const imageUri = result.assets[0].uri;
|
|
@@ -215,6 +245,7 @@ const FullDocScanner = ({ onResult, onClose, detectionConfig, overlayColor = '#3
|
|
|
215
245
|
await openCropper(imageUri);
|
|
216
246
|
}
|
|
217
247
|
catch (error) {
|
|
248
|
+
console.error('[FullDocScanner] Gallery pick error:', error);
|
|
218
249
|
setIsGalleryOpen(false);
|
|
219
250
|
emitError(error instanceof Error ? error : new Error(String(error)), 'Failed to pick image from gallery.');
|
|
220
251
|
}
|
|
@@ -250,29 +281,33 @@ const FullDocScanner = ({ onResult, onClose, detectionConfig, overlayColor = '#3
|
|
|
250
281
|
const stableCounter = event.stableCounter ?? 0;
|
|
251
282
|
const hasRectangle = Boolean(event.rectangleOnScreen ?? event.rectangleCoordinates);
|
|
252
283
|
const isGoodRectangle = hasRectangle && event.lastDetectionType === 0;
|
|
253
|
-
|
|
284
|
+
// Clear timeout immediately when rectangle is lost
|
|
285
|
+
if (!hasRectangle || !isGoodRectangle) {
|
|
286
|
+
if (rectangleTimeoutRef.current) {
|
|
287
|
+
clearTimeout(rectangleTimeoutRef.current);
|
|
288
|
+
rectangleTimeoutRef.current = null;
|
|
289
|
+
}
|
|
290
|
+
setRectangleDetected(false);
|
|
291
|
+
}
|
|
292
|
+
else {
|
|
293
|
+
// Rectangle detected - clear any existing timeout
|
|
254
294
|
if (rectangleTimeoutRef.current) {
|
|
255
295
|
clearTimeout(rectangleTimeoutRef.current);
|
|
256
296
|
}
|
|
297
|
+
setRectangleDetected(true);
|
|
298
|
+
// Set timeout to clear rectangle after brief period of no updates
|
|
257
299
|
rectangleTimeoutRef.current = setTimeout(() => {
|
|
258
300
|
rectangleTimeoutRef.current = null;
|
|
259
301
|
setRectangleDetected(false);
|
|
302
|
+
console.log('[FullDocScanner] Rectangle timeout - clearing detection');
|
|
260
303
|
}, 300);
|
|
261
304
|
}
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
console.log('[FullDocScanner] Rectangle detection update', {
|
|
269
|
-
lastDetectionType: event.lastDetectionType,
|
|
270
|
-
stableCounter,
|
|
271
|
-
hasRectangle,
|
|
272
|
-
isGoodRectangle,
|
|
273
|
-
});
|
|
274
|
-
}
|
|
275
|
-
return isGoodRectangle;
|
|
305
|
+
console.log('[FullDocScanner] Rectangle detection update', {
|
|
306
|
+
lastDetectionType: event.lastDetectionType,
|
|
307
|
+
stableCounter,
|
|
308
|
+
hasRectangle,
|
|
309
|
+
isGoodRectangle,
|
|
310
|
+
rectangleDetected: isGoodRectangle,
|
|
276
311
|
});
|
|
277
312
|
}, []);
|
|
278
313
|
(0, react_1.useEffect)(() => () => {
|
|
@@ -290,7 +325,7 @@ const FullDocScanner = ({ onResult, onClose, detectionConfig, overlayColor = '#3
|
|
|
290
325
|
react_1.default.createElement(react_native_1.Text, { style: styles.confirmButtonText }, mergedStrings.retake)),
|
|
291
326
|
react_1.default.createElement(react_native_1.TouchableOpacity, { style: [styles.confirmButton, styles.confirmButtonPrimary], onPress: handleConfirm, accessibilityLabel: mergedStrings.confirm, accessibilityRole: "button" },
|
|
292
327
|
react_1.default.createElement(react_native_1.Text, { style: styles.confirmButtonText }, mergedStrings.confirm))))) : (react_1.default.createElement(react_native_1.View, { style: styles.flex },
|
|
293
|
-
react_1.default.createElement(DocScanner_1.DocScanner, { ref: docScannerRef, autoCapture:
|
|
328
|
+
react_1.default.createElement(DocScanner_1.DocScanner, { ref: docScannerRef, autoCapture: false, overlayColor: overlayColor, showGrid: showGrid, gridColor: resolvedGridColor, gridLineWidth: gridLineWidth, minStableFrames: minStableFrames ?? 6, detectionConfig: detectionConfig, onCapture: handleCapture, onRectangleDetect: handleRectangleDetect, showManualCaptureButton: false },
|
|
294
329
|
react_1.default.createElement(react_native_1.View, { style: styles.overlayTop, pointerEvents: "box-none" },
|
|
295
330
|
react_1.default.createElement(react_native_1.TouchableOpacity, { style: styles.closeButton, onPress: handleClose, accessibilityLabel: mergedStrings.cancel, accessibilityRole: "button" },
|
|
296
331
|
react_1.default.createElement(react_native_1.Text, { style: styles.closeButtonLabel }, "\u00D7"))),
|
package/package.json
CHANGED
package/src/DocScanner.tsx
CHANGED
|
@@ -241,7 +241,8 @@ export const DocScanner = forwardRef<DocScannerHandle, Props>(
|
|
|
241
241
|
captureOriginRef.current = 'manual';
|
|
242
242
|
capture().catch((error) => {
|
|
243
243
|
captureOriginRef.current = 'auto';
|
|
244
|
-
console.
|
|
244
|
+
console.error('[DocScanner] manual capture failed', error);
|
|
245
|
+
throw error;
|
|
245
246
|
});
|
|
246
247
|
}, [capture]);
|
|
247
248
|
|
package/src/FullDocScanner.tsx
CHANGED
|
@@ -121,8 +121,17 @@ export const FullDocScanner: React.FC<FullDocScannerProps> = ({
|
|
|
121
121
|
try {
|
|
122
122
|
console.log('[FullDocScanner] openCropper called with path:', imagePath);
|
|
123
123
|
setProcessing(true);
|
|
124
|
+
|
|
125
|
+
// Clean path - remove file:// prefix for react-native-image-crop-picker
|
|
126
|
+
// The library handles the prefix internally and double prefixing causes issues
|
|
127
|
+
let cleanPath = imagePath;
|
|
128
|
+
if (cleanPath.startsWith('file://')) {
|
|
129
|
+
cleanPath = cleanPath.replace('file://', '');
|
|
130
|
+
}
|
|
131
|
+
console.log('[FullDocScanner] Clean path for cropper:', cleanPath);
|
|
132
|
+
|
|
124
133
|
const croppedImage = await ImageCropPicker.openCropper({
|
|
125
|
-
path:
|
|
134
|
+
path: cleanPath,
|
|
126
135
|
mediaType: 'photo',
|
|
127
136
|
width: cropWidth,
|
|
128
137
|
height: cropHeight,
|
|
@@ -140,7 +149,7 @@ export const FullDocScanner: React.FC<FullDocScannerProps> = ({
|
|
|
140
149
|
|
|
141
150
|
setProcessing(false);
|
|
142
151
|
|
|
143
|
-
// Show
|
|
152
|
+
// Show confirmation screen
|
|
144
153
|
setCroppedImageData({
|
|
145
154
|
path: croppedImage.path,
|
|
146
155
|
base64: croppedImage.data ?? undefined,
|
|
@@ -148,13 +157,18 @@ export const FullDocScanner: React.FC<FullDocScannerProps> = ({
|
|
|
148
157
|
} catch (error) {
|
|
149
158
|
console.error('[FullDocScanner] openCropper error:', error);
|
|
150
159
|
setProcessing(false);
|
|
151
|
-
|
|
160
|
+
|
|
161
|
+
const errorMessage = (error as any)?.message || String(error);
|
|
162
|
+
|
|
163
|
+
if (errorMessage === 'User cancelled image selection' ||
|
|
164
|
+
errorMessage.includes('cancelled') ||
|
|
165
|
+
errorMessage.includes('cancel')) {
|
|
166
|
+
console.log('[FullDocScanner] User cancelled cropper');
|
|
167
|
+
} else {
|
|
152
168
|
emitError(
|
|
153
|
-
error instanceof Error ? error : new Error(
|
|
154
|
-
'Failed to crop image.',
|
|
169
|
+
error instanceof Error ? error : new Error(errorMessage),
|
|
170
|
+
'Failed to crop image. Please try again.',
|
|
155
171
|
);
|
|
156
|
-
} else {
|
|
157
|
-
console.log('[FullDocScanner] User cancelled cropper');
|
|
158
172
|
}
|
|
159
173
|
}
|
|
160
174
|
},
|
|
@@ -169,25 +183,20 @@ export const FullDocScanner: React.FC<FullDocScannerProps> = ({
|
|
|
169
183
|
croppedPath: document.croppedPath,
|
|
170
184
|
initialPath: document.initialPath,
|
|
171
185
|
captureMode: captureModeRef.current,
|
|
186
|
+
captureInProgress: captureInProgressRef.current,
|
|
172
187
|
});
|
|
173
188
|
|
|
174
|
-
captureInProgressRef.current = false;
|
|
175
|
-
|
|
176
|
-
if (document.origin === 'auto') {
|
|
177
|
-
console.log('[FullDocScanner] Ignoring auto capture result');
|
|
178
|
-
return;
|
|
179
|
-
}
|
|
180
|
-
|
|
181
189
|
const captureMode = captureModeRef.current;
|
|
182
190
|
|
|
191
|
+
// Reset capture state
|
|
192
|
+
captureInProgressRef.current = false;
|
|
193
|
+
captureModeRef.current = null;
|
|
194
|
+
|
|
183
195
|
if (!captureMode) {
|
|
184
|
-
console.warn('[FullDocScanner] Missing capture mode for
|
|
185
|
-
captureModeRef.current = null;
|
|
196
|
+
console.warn('[FullDocScanner] Missing capture mode for capture result, ignoring');
|
|
186
197
|
return;
|
|
187
198
|
}
|
|
188
199
|
|
|
189
|
-
captureModeRef.current = null;
|
|
190
|
-
|
|
191
200
|
const normalizedDoc = normalizeCapturedDocument(document);
|
|
192
201
|
|
|
193
202
|
if (captureMode === 'no-grid') {
|
|
@@ -242,19 +251,40 @@ export const FullDocScanner: React.FC<FullDocScannerProps> = ({
|
|
|
242
251
|
captureModeRef.current = captureMode;
|
|
243
252
|
captureInProgressRef.current = true;
|
|
244
253
|
|
|
254
|
+
// Add timeout to reset state if capture hangs
|
|
255
|
+
const captureTimeout = setTimeout(() => {
|
|
256
|
+
if (captureInProgressRef.current) {
|
|
257
|
+
console.error('[FullDocScanner] Capture timeout - resetting state');
|
|
258
|
+
captureModeRef.current = null;
|
|
259
|
+
captureInProgressRef.current = false;
|
|
260
|
+
emitError(
|
|
261
|
+
new Error('Capture timeout'),
|
|
262
|
+
'Capture timed out. Please try again.',
|
|
263
|
+
);
|
|
264
|
+
}
|
|
265
|
+
}, 10000);
|
|
266
|
+
|
|
245
267
|
scannerInstance.capture()
|
|
246
268
|
.then((result) => {
|
|
247
|
-
|
|
248
|
-
|
|
269
|
+
clearTimeout(captureTimeout);
|
|
270
|
+
console.log('[FullDocScanner] Manual capture promise resolved:', {
|
|
271
|
+
hasResult: !!result,
|
|
272
|
+
croppedImage: result?.croppedImage,
|
|
273
|
+
initialImage: result?.initialImage,
|
|
274
|
+
});
|
|
275
|
+
// Note: captureInProgressRef is reset in handleCapture
|
|
249
276
|
})
|
|
250
277
|
.catch((error: unknown) => {
|
|
278
|
+
clearTimeout(captureTimeout);
|
|
279
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
280
|
+
console.error('[FullDocScanner] Manual capture failed:', errorMessage, error);
|
|
251
281
|
captureModeRef.current = null;
|
|
252
282
|
captureInProgressRef.current = false;
|
|
253
|
-
|
|
283
|
+
|
|
254
284
|
if (error instanceof Error && error.message !== 'capture_in_progress') {
|
|
255
285
|
emitError(
|
|
256
286
|
error,
|
|
257
|
-
'Failed to capture image.',
|
|
287
|
+
'Failed to capture image. Please try again.',
|
|
258
288
|
);
|
|
259
289
|
}
|
|
260
290
|
});
|
|
@@ -263,21 +293,30 @@ export const FullDocScanner: React.FC<FullDocScannerProps> = ({
|
|
|
263
293
|
const handleGalleryPick = useCallback(async () => {
|
|
264
294
|
console.log('[FullDocScanner] handleGalleryPick called');
|
|
265
295
|
if (processing || isGalleryOpen) {
|
|
296
|
+
console.log('[FullDocScanner] Skipping gallery pick - already processing:', { processing, isGalleryOpen });
|
|
266
297
|
return;
|
|
267
298
|
}
|
|
268
299
|
|
|
269
300
|
try {
|
|
270
301
|
setIsGalleryOpen(true);
|
|
302
|
+
console.log('[FullDocScanner] Launching image library...');
|
|
303
|
+
|
|
271
304
|
const result = await launchImageLibrary({
|
|
272
305
|
mediaType: 'photo',
|
|
273
306
|
quality: 1,
|
|
274
307
|
selectionLimit: 1,
|
|
275
308
|
});
|
|
276
309
|
|
|
310
|
+
console.log('[FullDocScanner] Image library result:', {
|
|
311
|
+
didCancel: result.didCancel,
|
|
312
|
+
hasAssets: !!result.assets,
|
|
313
|
+
assetsLength: result.assets?.length,
|
|
314
|
+
});
|
|
315
|
+
|
|
277
316
|
setIsGalleryOpen(false);
|
|
278
317
|
|
|
279
318
|
if (result.didCancel || !result.assets?.[0]?.uri) {
|
|
280
|
-
console.log('[FullDocScanner] User cancelled gallery picker');
|
|
319
|
+
console.log('[FullDocScanner] User cancelled gallery picker or no image selected');
|
|
281
320
|
return;
|
|
282
321
|
}
|
|
283
322
|
|
|
@@ -287,6 +326,7 @@ export const FullDocScanner: React.FC<FullDocScannerProps> = ({
|
|
|
287
326
|
// Open cropper with the selected image
|
|
288
327
|
await openCropper(imageUri);
|
|
289
328
|
} catch (error) {
|
|
329
|
+
console.error('[FullDocScanner] Gallery pick error:', error);
|
|
290
330
|
setIsGalleryOpen(false);
|
|
291
331
|
emitError(
|
|
292
332
|
error instanceof Error ? error : new Error(String(error)),
|
|
@@ -330,29 +370,34 @@ export const FullDocScanner: React.FC<FullDocScannerProps> = ({
|
|
|
330
370
|
const hasRectangle = Boolean(event.rectangleOnScreen ?? event.rectangleCoordinates);
|
|
331
371
|
const isGoodRectangle = hasRectangle && event.lastDetectionType === 0;
|
|
332
372
|
|
|
333
|
-
|
|
373
|
+
// Clear timeout immediately when rectangle is lost
|
|
374
|
+
if (!hasRectangle || !isGoodRectangle) {
|
|
334
375
|
if (rectangleTimeoutRef.current) {
|
|
335
376
|
clearTimeout(rectangleTimeoutRef.current);
|
|
377
|
+
rectangleTimeoutRef.current = null;
|
|
336
378
|
}
|
|
379
|
+
setRectangleDetected(false);
|
|
380
|
+
} else {
|
|
381
|
+
// Rectangle detected - clear any existing timeout
|
|
382
|
+
if (rectangleTimeoutRef.current) {
|
|
383
|
+
clearTimeout(rectangleTimeoutRef.current);
|
|
384
|
+
}
|
|
385
|
+
setRectangleDetected(true);
|
|
386
|
+
|
|
387
|
+
// Set timeout to clear rectangle after brief period of no updates
|
|
337
388
|
rectangleTimeoutRef.current = setTimeout(() => {
|
|
338
389
|
rectangleTimeoutRef.current = null;
|
|
339
390
|
setRectangleDetected(false);
|
|
391
|
+
console.log('[FullDocScanner] Rectangle timeout - clearing detection');
|
|
340
392
|
}, 300);
|
|
341
|
-
} else if (rectangleTimeoutRef.current) {
|
|
342
|
-
clearTimeout(rectangleTimeoutRef.current);
|
|
343
|
-
rectangleTimeoutRef.current = null;
|
|
344
393
|
}
|
|
345
394
|
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
isGoodRectangle,
|
|
353
|
-
});
|
|
354
|
-
}
|
|
355
|
-
return isGoodRectangle;
|
|
395
|
+
console.log('[FullDocScanner] Rectangle detection update', {
|
|
396
|
+
lastDetectionType: event.lastDetectionType,
|
|
397
|
+
stableCounter,
|
|
398
|
+
hasRectangle,
|
|
399
|
+
isGoodRectangle,
|
|
400
|
+
rectangleDetected: isGoodRectangle,
|
|
356
401
|
});
|
|
357
402
|
}, []);
|
|
358
403
|
|
|
@@ -395,7 +440,7 @@ export const FullDocScanner: React.FC<FullDocScannerProps> = ({
|
|
|
395
440
|
<View style={styles.flex}>
|
|
396
441
|
<DocScanner
|
|
397
442
|
ref={docScannerRef}
|
|
398
|
-
autoCapture={
|
|
443
|
+
autoCapture={false}
|
|
399
444
|
overlayColor={overlayColor}
|
|
400
445
|
showGrid={showGrid}
|
|
401
446
|
gridColor={resolvedGridColor}
|