react-native-rectangle-doc-scanner 3.35.0 → 3.37.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/CropEditor.js +24 -6
- package/dist/FullDocScanner.js +49 -48
- package/package.json +2 -2
- package/src/CropEditor.tsx +43 -16
- package/src/FullDocScanner.tsx +59 -49
package/dist/CropEditor.js
CHANGED
|
@@ -117,12 +117,26 @@ const CropEditor = ({ document, overlayColor = 'rgba(0,0,0,0.5)', overlayStrokeC
|
|
|
117
117
|
};
|
|
118
118
|
onCropChange?.(rect);
|
|
119
119
|
}, [imageSize, onCropChange]);
|
|
120
|
-
|
|
120
|
+
// Ensure proper file URI format
|
|
121
|
+
const imageUri = document.path.startsWith('file://')
|
|
122
|
+
? document.path
|
|
123
|
+
: `file://${document.path}`;
|
|
124
|
+
const initialRect = getInitialRectangle();
|
|
125
|
+
console.log('[CropEditor] Rendering with:', {
|
|
126
|
+
imageUri,
|
|
127
|
+
imageSize,
|
|
128
|
+
displaySize,
|
|
129
|
+
initialRect,
|
|
130
|
+
isLoading: isImageLoading,
|
|
131
|
+
hasError: !!loadError,
|
|
132
|
+
});
|
|
121
133
|
return (react_1.default.createElement(react_native_1.View, { style: styles.container, onLayout: handleLayout }, loadError ? (react_1.default.createElement(react_native_1.View, { style: styles.errorContainer },
|
|
122
134
|
react_1.default.createElement(react_native_1.Text, { style: styles.errorText }, "Failed to load image"),
|
|
123
135
|
react_1.default.createElement(react_native_1.Text, { style: styles.errorPath }, imageUri))) : !imageSize || isImageLoading ? (react_1.default.createElement(react_native_1.View, { style: styles.loadingContainer },
|
|
124
136
|
react_1.default.createElement(react_native_1.ActivityIndicator, { size: "large", color: handlerColor }),
|
|
125
|
-
react_1.default.createElement(react_native_1.Text, { style: styles.loadingText }, "Loading image..."))) : (react_1.default.createElement(
|
|
137
|
+
react_1.default.createElement(react_native_1.Text, { style: styles.loadingText }, "Loading image..."))) : (react_1.default.createElement(react_1.default.Fragment, null,
|
|
138
|
+
react_1.default.createElement(react_native_perspective_image_cropper_1.default, { height: displaySize.height, width: displaySize.width, image: imageUri, rectangleCoordinates: initialRect, overlayColor: overlayColor, overlayStrokeColor: overlayStrokeColor, handlerColor: handlerColor, enablePanStrict: enablePanStrict, onDragEnd: handleDragEnd }),
|
|
139
|
+
react_1.default.createElement(react_native_1.Image, { source: { uri: imageUri }, style: styles.debugImage, onLoad: () => console.log('[CropEditor] Debug image loaded'), onError: (e) => console.error('[CropEditor] Debug image error:', e.nativeEvent.error) })))));
|
|
126
140
|
};
|
|
127
141
|
exports.CropEditor = CropEditor;
|
|
128
142
|
const styles = react_native_1.StyleSheet.create({
|
|
@@ -157,10 +171,14 @@ const styles = react_native_1.StyleSheet.create({
|
|
|
157
171
|
fontSize: 12,
|
|
158
172
|
textAlign: 'center',
|
|
159
173
|
},
|
|
160
|
-
|
|
161
|
-
width: 1,
|
|
162
|
-
height: 1,
|
|
163
|
-
opacity: 0,
|
|
174
|
+
debugImage: {
|
|
164
175
|
position: 'absolute',
|
|
176
|
+
width: 100,
|
|
177
|
+
height: 100,
|
|
178
|
+
top: 10,
|
|
179
|
+
right: 10,
|
|
180
|
+
opacity: 0.5,
|
|
181
|
+
borderWidth: 2,
|
|
182
|
+
borderColor: 'red',
|
|
165
183
|
},
|
|
166
184
|
});
|
package/dist/FullDocScanner.js
CHANGED
|
@@ -69,13 +69,13 @@ const FullDocScanner = ({ onResult, onClose, detectionConfig, overlayColor = '#3
|
|
|
69
69
|
const processingCaptureRef = (0, react_1.useRef)(false);
|
|
70
70
|
const cropInitializedRef = (0, react_1.useRef)(false);
|
|
71
71
|
const mergedStrings = (0, react_1.useMemo)(() => ({
|
|
72
|
-
captureHint: strings?.captureHint ?? '
|
|
73
|
-
manualHint: strings?.manualHint ?? '
|
|
74
|
-
cancel: strings?.cancel ?? '
|
|
75
|
-
confirm: strings?.confirm ?? '
|
|
76
|
-
retake: strings?.retake ?? '
|
|
77
|
-
cropTitle: strings?.cropTitle ?? '
|
|
78
|
-
processing: strings?.processing ?? '
|
|
72
|
+
captureHint: strings?.captureHint ?? '',
|
|
73
|
+
manualHint: strings?.manualHint ?? '',
|
|
74
|
+
cancel: strings?.cancel ?? '',
|
|
75
|
+
confirm: strings?.confirm ?? '',
|
|
76
|
+
retake: strings?.retake ?? '',
|
|
77
|
+
cropTitle: strings?.cropTitle ?? '',
|
|
78
|
+
processing: strings?.processing ?? '',
|
|
79
79
|
}), [strings]);
|
|
80
80
|
(0, react_1.useEffect)(() => {
|
|
81
81
|
if (!capturedDoc) {
|
|
@@ -205,27 +205,16 @@ const FullDocScanner = ({ onResult, onClose, detectionConfig, overlayColor = '#3
|
|
|
205
205
|
return;
|
|
206
206
|
}
|
|
207
207
|
const normalizedDoc = normalizeCapturedDocument(document);
|
|
208
|
-
|
|
209
|
-
console.log('[FullDocScanner]
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
cropInitializedRef.current = false;
|
|
219
|
-
setCapturedDoc(normalizedDoc);
|
|
220
|
-
setImageSize(null);
|
|
221
|
-
setCropRectangle(null);
|
|
222
|
-
setScreen('crop');
|
|
223
|
-
return;
|
|
224
|
-
}
|
|
225
|
-
console.log('[FullDocScanner] Starting auto flow - processing capture');
|
|
226
|
-
processingCaptureRef.current = true;
|
|
227
|
-
processAutoCapture(document);
|
|
228
|
-
}, [manualCapture, processAutoCapture]);
|
|
208
|
+
// 자동 촬영이든 수동 촬영이든 모두 crop 화면으로 이동
|
|
209
|
+
console.log('[FullDocScanner] Moving to crop/preview screen');
|
|
210
|
+
manualCapturePending.current = false;
|
|
211
|
+
processingCaptureRef.current = false;
|
|
212
|
+
cropInitializedRef.current = false;
|
|
213
|
+
setCapturedDoc(normalizedDoc);
|
|
214
|
+
setImageSize(null);
|
|
215
|
+
setCropRectangle(null);
|
|
216
|
+
setScreen('crop');
|
|
217
|
+
}, []);
|
|
229
218
|
const handleCropChange = (0, react_1.useCallback)((rectangle) => {
|
|
230
219
|
setCropRectangle(rectangle);
|
|
231
220
|
}, []);
|
|
@@ -325,25 +314,25 @@ const FullDocScanner = ({ onResult, onClose, detectionConfig, overlayColor = '#3
|
|
|
325
314
|
}, [onClose, resetState]);
|
|
326
315
|
return (react_1.default.createElement(react_native_1.View, { style: styles.container },
|
|
327
316
|
screen === 'scanner' && (react_1.default.createElement(react_native_1.View, { style: styles.flex },
|
|
328
|
-
react_1.default.createElement(DocScanner_1.DocScanner, { ref: docScannerRef, autoCapture: !manualCapture, overlayColor: overlayColor, showGrid: showGrid, gridColor: resolvedGridColor, gridLineWidth: gridLineWidth, minStableFrames: minStableFrames ?? 6, detectionConfig: detectionConfig, onCapture: handleCapture, showManualCaptureButton:
|
|
329
|
-
react_1.default.createElement(react_native_1.View, { style: styles.
|
|
317
|
+
react_1.default.createElement(DocScanner_1.DocScanner, { ref: docScannerRef, autoCapture: !manualCapture, overlayColor: overlayColor, showGrid: showGrid, gridColor: resolvedGridColor, gridLineWidth: gridLineWidth, minStableFrames: minStableFrames ?? 6, detectionConfig: detectionConfig, onCapture: handleCapture, showManualCaptureButton: false },
|
|
318
|
+
react_1.default.createElement(react_native_1.View, { style: styles.overlayTop, pointerEvents: "box-none" },
|
|
330
319
|
react_1.default.createElement(react_native_1.TouchableOpacity, { style: styles.closeButton, onPress: handleClose, accessibilityLabel: mergedStrings.cancel, accessibilityRole: "button" },
|
|
331
|
-
react_1.default.createElement(react_native_1.Text, { style: styles.closeButtonLabel }, "\u00D7")),
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
react_1.default.createElement(react_native_1.Text, { style: styles.captureText }, mergedStrings.
|
|
320
|
+
react_1.default.createElement(react_native_1.Text, { style: styles.closeButtonLabel }, "\u00D7"))),
|
|
321
|
+
(mergedStrings.captureHint || mergedStrings.manualHint) && (react_1.default.createElement(react_native_1.View, { style: styles.instructionsContainer, pointerEvents: "none" },
|
|
322
|
+
react_1.default.createElement(react_native_1.View, { style: styles.instructions },
|
|
323
|
+
mergedStrings.captureHint && (react_1.default.createElement(react_native_1.Text, { style: styles.captureText }, mergedStrings.captureHint)),
|
|
324
|
+
mergedStrings.manualHint && (react_1.default.createElement(react_native_1.Text, { style: styles.captureText }, mergedStrings.manualHint))))),
|
|
325
|
+
react_1.default.createElement(react_native_1.View, { style: styles.shutterContainer, pointerEvents: "box-none" },
|
|
335
326
|
react_1.default.createElement(react_native_1.TouchableOpacity, { style: [styles.shutterButton, processing && styles.shutterButtonDisabled], onPress: triggerManualCapture, disabled: processing, accessibilityLabel: mergedStrings.manualHint, accessibilityRole: "button" },
|
|
336
327
|
react_1.default.createElement(react_native_1.View, { style: styles.shutterInner })))))),
|
|
337
328
|
screen === 'crop' && capturedDoc && (react_1.default.createElement(react_native_1.View, { style: styles.flex },
|
|
338
329
|
react_1.default.createElement(CropEditor_1.CropEditor, { document: capturedDoc, overlayColor: "rgba(0,0,0,0.6)", overlayStrokeColor: overlayStrokeColor, handlerColor: handlerColor, onCropChange: handleCropChange }),
|
|
339
330
|
react_1.default.createElement(react_native_1.View, { style: styles.cropFooter },
|
|
340
|
-
react_1.default.createElement(react_native_1.TouchableOpacity, { style: [styles.actionButton, styles.secondaryButton], onPress: handleRetake },
|
|
341
|
-
|
|
342
|
-
react_1.default.createElement(react_native_1.TouchableOpacity, { style: [styles.actionButton, styles.primaryButton], onPress: handleConfirm },
|
|
343
|
-
react_1.default.createElement(react_native_1.Text, { style: styles.buttonText }, mergedStrings.confirm))))),
|
|
331
|
+
react_1.default.createElement(react_native_1.TouchableOpacity, { style: [styles.actionButton, styles.secondaryButton], onPress: handleRetake }, mergedStrings.retake && react_1.default.createElement(react_native_1.Text, { style: styles.buttonText }, mergedStrings.retake)),
|
|
332
|
+
react_1.default.createElement(react_native_1.TouchableOpacity, { style: [styles.actionButton, styles.primaryButton], onPress: handleConfirm }, mergedStrings.confirm && react_1.default.createElement(react_native_1.Text, { style: styles.buttonText }, mergedStrings.confirm))))),
|
|
344
333
|
processing && (react_1.default.createElement(react_native_1.View, { style: styles.processingOverlay },
|
|
345
334
|
react_1.default.createElement(react_native_1.ActivityIndicator, { size: "large", color: overlayStrokeColor }),
|
|
346
|
-
react_1.default.createElement(react_native_1.Text, { style: styles.processingText }, mergedStrings.processing)))));
|
|
335
|
+
mergedStrings.processing && (react_1.default.createElement(react_native_1.Text, { style: styles.processingText }, mergedStrings.processing))))));
|
|
347
336
|
};
|
|
348
337
|
exports.FullDocScanner = FullDocScanner;
|
|
349
338
|
const styles = react_native_1.StyleSheet.create({
|
|
@@ -354,12 +343,27 @@ const styles = react_native_1.StyleSheet.create({
|
|
|
354
343
|
flex: {
|
|
355
344
|
flex: 1,
|
|
356
345
|
},
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
346
|
+
overlayTop: {
|
|
347
|
+
position: 'absolute',
|
|
348
|
+
top: 48,
|
|
349
|
+
right: 24,
|
|
350
|
+
zIndex: 10,
|
|
351
|
+
},
|
|
352
|
+
instructionsContainer: {
|
|
353
|
+
position: 'absolute',
|
|
354
|
+
top: '40%',
|
|
355
|
+
left: 0,
|
|
356
|
+
right: 0,
|
|
357
|
+
alignItems: 'center',
|
|
358
|
+
zIndex: 5,
|
|
359
|
+
},
|
|
360
|
+
shutterContainer: {
|
|
361
|
+
position: 'absolute',
|
|
362
|
+
bottom: 64,
|
|
363
|
+
left: 0,
|
|
364
|
+
right: 0,
|
|
365
|
+
alignItems: 'center',
|
|
366
|
+
zIndex: 10,
|
|
363
367
|
},
|
|
364
368
|
closeButton: {
|
|
365
369
|
width: 40,
|
|
@@ -368,7 +372,6 @@ const styles = react_native_1.StyleSheet.create({
|
|
|
368
372
|
backgroundColor: 'rgba(0,0,0,0.5)',
|
|
369
373
|
justifyContent: 'center',
|
|
370
374
|
alignItems: 'center',
|
|
371
|
-
alignSelf: 'flex-end',
|
|
372
375
|
},
|
|
373
376
|
closeButtonLabel: {
|
|
374
377
|
color: '#fff',
|
|
@@ -377,7 +380,6 @@ const styles = react_native_1.StyleSheet.create({
|
|
|
377
380
|
marginTop: -3,
|
|
378
381
|
},
|
|
379
382
|
instructions: {
|
|
380
|
-
alignSelf: 'center',
|
|
381
383
|
backgroundColor: 'rgba(0,0,0,0.55)',
|
|
382
384
|
borderRadius: 16,
|
|
383
385
|
paddingHorizontal: 20,
|
|
@@ -389,7 +391,6 @@ const styles = react_native_1.StyleSheet.create({
|
|
|
389
391
|
textAlign: 'center',
|
|
390
392
|
},
|
|
391
393
|
shutterButton: {
|
|
392
|
-
alignSelf: 'center',
|
|
393
394
|
width: 80,
|
|
394
395
|
height: 80,
|
|
395
396
|
borderRadius: 40,
|
package/package.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-native-rectangle-doc-scanner",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.37.0",
|
|
4
4
|
"description": "Native-backed document scanner for React Native with customizable overlays.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
7
|
"types": "dist/index.d.ts",
|
|
8
8
|
"repository": {
|
|
9
9
|
"type": "git",
|
|
10
|
-
"url": "https://github.com/danchew90/react-native-rectangle-doc-scanner.git"
|
|
10
|
+
"url": "git+https://github.com/danchew90/react-native-rectangle-doc-scanner.git"
|
|
11
11
|
},
|
|
12
12
|
"homepage": "https://github.com/danchew90/react-native-rectangle-doc-scanner",
|
|
13
13
|
"bugs": {
|
package/src/CropEditor.tsx
CHANGED
|
@@ -120,7 +120,21 @@ export const CropEditor: React.FC<CropEditorProps> = ({
|
|
|
120
120
|
onCropChange?.(rect);
|
|
121
121
|
}, [imageSize, onCropChange]);
|
|
122
122
|
|
|
123
|
-
|
|
123
|
+
// Ensure proper file URI format
|
|
124
|
+
const imageUri = document.path.startsWith('file://')
|
|
125
|
+
? document.path
|
|
126
|
+
: `file://${document.path}`;
|
|
127
|
+
|
|
128
|
+
const initialRect = getInitialRectangle();
|
|
129
|
+
|
|
130
|
+
console.log('[CropEditor] Rendering with:', {
|
|
131
|
+
imageUri,
|
|
132
|
+
imageSize,
|
|
133
|
+
displaySize,
|
|
134
|
+
initialRect,
|
|
135
|
+
isLoading: isImageLoading,
|
|
136
|
+
hasError: !!loadError,
|
|
137
|
+
});
|
|
124
138
|
|
|
125
139
|
return (
|
|
126
140
|
<View style={styles.container} onLayout={handleLayout}>
|
|
@@ -136,17 +150,26 @@ export const CropEditor: React.FC<CropEditorProps> = ({
|
|
|
136
150
|
<Text style={styles.loadingText}>Loading image...</Text>
|
|
137
151
|
</View>
|
|
138
152
|
) : (
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
153
|
+
<>
|
|
154
|
+
<CustomImageCropper
|
|
155
|
+
height={displaySize.height}
|
|
156
|
+
width={displaySize.width}
|
|
157
|
+
image={imageUri}
|
|
158
|
+
rectangleCoordinates={initialRect}
|
|
159
|
+
overlayColor={overlayColor}
|
|
160
|
+
overlayStrokeColor={overlayStrokeColor}
|
|
161
|
+
handlerColor={handlerColor}
|
|
162
|
+
enablePanStrict={enablePanStrict}
|
|
163
|
+
onDragEnd={handleDragEnd}
|
|
164
|
+
/>
|
|
165
|
+
{/* Debug: Show image in background to verify it loads */}
|
|
166
|
+
<Image
|
|
167
|
+
source={{ uri: imageUri }}
|
|
168
|
+
style={styles.debugImage}
|
|
169
|
+
onLoad={() => console.log('[CropEditor] Debug image loaded')}
|
|
170
|
+
onError={(e) => console.error('[CropEditor] Debug image error:', e.nativeEvent.error)}
|
|
171
|
+
/>
|
|
172
|
+
</>
|
|
150
173
|
)}
|
|
151
174
|
</View>
|
|
152
175
|
);
|
|
@@ -184,10 +207,14 @@ const styles = StyleSheet.create({
|
|
|
184
207
|
fontSize: 12,
|
|
185
208
|
textAlign: 'center',
|
|
186
209
|
},
|
|
187
|
-
|
|
188
|
-
width: 1,
|
|
189
|
-
height: 1,
|
|
190
|
-
opacity: 0,
|
|
210
|
+
debugImage: {
|
|
191
211
|
position: 'absolute',
|
|
212
|
+
width: 100,
|
|
213
|
+
height: 100,
|
|
214
|
+
top: 10,
|
|
215
|
+
right: 10,
|
|
216
|
+
opacity: 0.5,
|
|
217
|
+
borderWidth: 2,
|
|
218
|
+
borderColor: 'red',
|
|
192
219
|
},
|
|
193
220
|
});
|
package/src/FullDocScanner.tsx
CHANGED
|
@@ -122,15 +122,15 @@ export const FullDocScanner: React.FC<FullDocScannerProps> = ({
|
|
|
122
122
|
const processingCaptureRef = useRef(false);
|
|
123
123
|
const cropInitializedRef = useRef(false);
|
|
124
124
|
|
|
125
|
-
const mergedStrings = useMemo
|
|
125
|
+
const mergedStrings = useMemo(
|
|
126
126
|
() => ({
|
|
127
|
-
captureHint: strings?.captureHint ?? '
|
|
128
|
-
manualHint: strings?.manualHint ?? '
|
|
129
|
-
cancel: strings?.cancel ?? '
|
|
130
|
-
confirm: strings?.confirm ?? '
|
|
131
|
-
retake: strings?.retake ?? '
|
|
132
|
-
cropTitle: strings?.cropTitle ?? '
|
|
133
|
-
processing: strings?.processing ?? '
|
|
127
|
+
captureHint: strings?.captureHint ?? '',
|
|
128
|
+
manualHint: strings?.manualHint ?? '',
|
|
129
|
+
cancel: strings?.cancel ?? '',
|
|
130
|
+
confirm: strings?.confirm ?? '',
|
|
131
|
+
retake: strings?.retake ?? '',
|
|
132
|
+
cropTitle: strings?.cropTitle ?? '',
|
|
133
|
+
processing: strings?.processing ?? '',
|
|
134
134
|
}),
|
|
135
135
|
[strings],
|
|
136
136
|
);
|
|
@@ -323,32 +323,18 @@ export const FullDocScanner: React.FC<FullDocScannerProps> = ({
|
|
|
323
323
|
}
|
|
324
324
|
|
|
325
325
|
const normalizedDoc = normalizeCapturedDocument(document);
|
|
326
|
-
const wantsManualFlow =
|
|
327
|
-
manualCapture || manualCapturePending.current || document.origin === 'manual';
|
|
328
326
|
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
processingCaptureRef.current = false;
|
|
339
|
-
cropInitializedRef.current = false;
|
|
340
|
-
setCapturedDoc(normalizedDoc);
|
|
341
|
-
setImageSize(null);
|
|
342
|
-
setCropRectangle(null);
|
|
343
|
-
setScreen('crop');
|
|
344
|
-
return;
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
console.log('[FullDocScanner] Starting auto flow - processing capture');
|
|
348
|
-
processingCaptureRef.current = true;
|
|
349
|
-
processAutoCapture(document);
|
|
327
|
+
// 자동 촬영이든 수동 촬영이든 모두 crop 화면으로 이동
|
|
328
|
+
console.log('[FullDocScanner] Moving to crop/preview screen');
|
|
329
|
+
manualCapturePending.current = false;
|
|
330
|
+
processingCaptureRef.current = false;
|
|
331
|
+
cropInitializedRef.current = false;
|
|
332
|
+
setCapturedDoc(normalizedDoc);
|
|
333
|
+
setImageSize(null);
|
|
334
|
+
setCropRectangle(null);
|
|
335
|
+
setScreen('crop');
|
|
350
336
|
},
|
|
351
|
-
[
|
|
337
|
+
[],
|
|
352
338
|
);
|
|
353
339
|
|
|
354
340
|
const handleCropChange = useCallback((rectangle: Rectangle) => {
|
|
@@ -491,9 +477,9 @@ export const FullDocScanner: React.FC<FullDocScannerProps> = ({
|
|
|
491
477
|
minStableFrames={minStableFrames ?? 6}
|
|
492
478
|
detectionConfig={detectionConfig}
|
|
493
479
|
onCapture={handleCapture}
|
|
494
|
-
showManualCaptureButton
|
|
480
|
+
showManualCaptureButton={false}
|
|
495
481
|
>
|
|
496
|
-
<View style={styles.
|
|
482
|
+
<View style={styles.overlayTop} pointerEvents="box-none">
|
|
497
483
|
<TouchableOpacity
|
|
498
484
|
style={styles.closeButton}
|
|
499
485
|
onPress={handleClose}
|
|
@@ -502,10 +488,20 @@ export const FullDocScanner: React.FC<FullDocScannerProps> = ({
|
|
|
502
488
|
>
|
|
503
489
|
<Text style={styles.closeButtonLabel}>×</Text>
|
|
504
490
|
</TouchableOpacity>
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
491
|
+
</View>
|
|
492
|
+
{(mergedStrings.captureHint || mergedStrings.manualHint) && (
|
|
493
|
+
<View style={styles.instructionsContainer} pointerEvents="none">
|
|
494
|
+
<View style={styles.instructions}>
|
|
495
|
+
{mergedStrings.captureHint && (
|
|
496
|
+
<Text style={styles.captureText}>{mergedStrings.captureHint}</Text>
|
|
497
|
+
)}
|
|
498
|
+
{mergedStrings.manualHint && (
|
|
499
|
+
<Text style={styles.captureText}>{mergedStrings.manualHint}</Text>
|
|
500
|
+
)}
|
|
501
|
+
</View>
|
|
508
502
|
</View>
|
|
503
|
+
)}
|
|
504
|
+
<View style={styles.shutterContainer} pointerEvents="box-none">
|
|
509
505
|
<TouchableOpacity
|
|
510
506
|
style={[styles.shutterButton, processing && styles.shutterButtonDisabled]}
|
|
511
507
|
onPress={triggerManualCapture}
|
|
@@ -531,10 +527,10 @@ export const FullDocScanner: React.FC<FullDocScannerProps> = ({
|
|
|
531
527
|
/>
|
|
532
528
|
<View style={styles.cropFooter}>
|
|
533
529
|
<TouchableOpacity style={[styles.actionButton, styles.secondaryButton]} onPress={handleRetake}>
|
|
534
|
-
<Text style={styles.buttonText}>{mergedStrings.retake}</Text>
|
|
530
|
+
{mergedStrings.retake && <Text style={styles.buttonText}>{mergedStrings.retake}</Text>}
|
|
535
531
|
</TouchableOpacity>
|
|
536
532
|
<TouchableOpacity style={[styles.actionButton, styles.primaryButton]} onPress={handleConfirm}>
|
|
537
|
-
<Text style={styles.buttonText}>{mergedStrings.confirm}</Text>
|
|
533
|
+
{mergedStrings.confirm && <Text style={styles.buttonText}>{mergedStrings.confirm}</Text>}
|
|
538
534
|
</TouchableOpacity>
|
|
539
535
|
</View>
|
|
540
536
|
</View>
|
|
@@ -543,7 +539,9 @@ export const FullDocScanner: React.FC<FullDocScannerProps> = ({
|
|
|
543
539
|
{processing && (
|
|
544
540
|
<View style={styles.processingOverlay}>
|
|
545
541
|
<ActivityIndicator size="large" color={overlayStrokeColor} />
|
|
546
|
-
|
|
542
|
+
{mergedStrings.processing && (
|
|
543
|
+
<Text style={styles.processingText}>{mergedStrings.processing}</Text>
|
|
544
|
+
)}
|
|
547
545
|
</View>
|
|
548
546
|
)}
|
|
549
547
|
</View>
|
|
@@ -558,12 +556,27 @@ const styles = StyleSheet.create({
|
|
|
558
556
|
flex: {
|
|
559
557
|
flex: 1,
|
|
560
558
|
},
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
559
|
+
overlayTop: {
|
|
560
|
+
position: 'absolute',
|
|
561
|
+
top: 48,
|
|
562
|
+
right: 24,
|
|
563
|
+
zIndex: 10,
|
|
564
|
+
},
|
|
565
|
+
instructionsContainer: {
|
|
566
|
+
position: 'absolute',
|
|
567
|
+
top: '40%',
|
|
568
|
+
left: 0,
|
|
569
|
+
right: 0,
|
|
570
|
+
alignItems: 'center',
|
|
571
|
+
zIndex: 5,
|
|
572
|
+
},
|
|
573
|
+
shutterContainer: {
|
|
574
|
+
position: 'absolute',
|
|
575
|
+
bottom: 64,
|
|
576
|
+
left: 0,
|
|
577
|
+
right: 0,
|
|
578
|
+
alignItems: 'center',
|
|
579
|
+
zIndex: 10,
|
|
567
580
|
},
|
|
568
581
|
closeButton: {
|
|
569
582
|
width: 40,
|
|
@@ -572,7 +585,6 @@ const styles = StyleSheet.create({
|
|
|
572
585
|
backgroundColor: 'rgba(0,0,0,0.5)',
|
|
573
586
|
justifyContent: 'center',
|
|
574
587
|
alignItems: 'center',
|
|
575
|
-
alignSelf: 'flex-end',
|
|
576
588
|
},
|
|
577
589
|
closeButtonLabel: {
|
|
578
590
|
color: '#fff',
|
|
@@ -581,7 +593,6 @@ const styles = StyleSheet.create({
|
|
|
581
593
|
marginTop: -3,
|
|
582
594
|
},
|
|
583
595
|
instructions: {
|
|
584
|
-
alignSelf: 'center',
|
|
585
596
|
backgroundColor: 'rgba(0,0,0,0.55)',
|
|
586
597
|
borderRadius: 16,
|
|
587
598
|
paddingHorizontal: 20,
|
|
@@ -593,7 +604,6 @@ const styles = StyleSheet.create({
|
|
|
593
604
|
textAlign: 'center',
|
|
594
605
|
},
|
|
595
606
|
shutterButton: {
|
|
596
|
-
alignSelf: 'center',
|
|
597
607
|
width: 80,
|
|
598
608
|
height: 80,
|
|
599
609
|
borderRadius: 40,
|