react-native-rectangle-doc-scanner 3.36.0 → 3.38.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 +18 -11
- package/dist/FullDocScanner.js +54 -37
- package/package.json +2 -2
- package/src/CropEditor.tsx +40 -17
- package/src/FullDocScanner.tsx +66 -34
package/dist/CropEditor.js
CHANGED
|
@@ -32,14 +32,10 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
32
32
|
return result;
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
-
};
|
|
38
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
36
|
exports.CropEditor = void 0;
|
|
40
37
|
const react_1 = __importStar(require("react"));
|
|
41
38
|
const react_native_1 = require("react-native");
|
|
42
|
-
const react_native_perspective_image_cropper_1 = __importDefault(require("react-native-perspective-image-cropper"));
|
|
43
39
|
const coordinate_1 = require("./utils/coordinate");
|
|
44
40
|
/**
|
|
45
41
|
* CropEditor Component
|
|
@@ -117,12 +113,25 @@ const CropEditor = ({ document, overlayColor = 'rgba(0,0,0,0.5)', overlayStrokeC
|
|
|
117
113
|
};
|
|
118
114
|
onCropChange?.(rect);
|
|
119
115
|
}, [imageSize, onCropChange]);
|
|
120
|
-
|
|
116
|
+
// Ensure proper file URI format
|
|
117
|
+
const imageUri = document.path.startsWith('file://')
|
|
118
|
+
? document.path
|
|
119
|
+
: `file://${document.path}`;
|
|
120
|
+
const initialRect = getInitialRectangle();
|
|
121
|
+
console.log('[CropEditor] Rendering with:', {
|
|
122
|
+
imageUri,
|
|
123
|
+
imageSize,
|
|
124
|
+
displaySize,
|
|
125
|
+
initialRect,
|
|
126
|
+
isLoading: isImageLoading,
|
|
127
|
+
hasError: !!loadError,
|
|
128
|
+
});
|
|
121
129
|
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
130
|
react_1.default.createElement(react_native_1.Text, { style: styles.errorText }, "Failed to load image"),
|
|
123
131
|
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
132
|
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(
|
|
133
|
+
react_1.default.createElement(react_native_1.Text, { style: styles.loadingText }, "Loading image..."))) : (react_1.default.createElement(react_1.default.Fragment, null,
|
|
134
|
+
react_1.default.createElement(react_native_1.Image, { source: { uri: imageUri }, style: styles.fullImage, resizeMode: "contain", onLoad: () => console.log('[CropEditor] Image loaded successfully'), onError: (e) => console.error('[CropEditor] Image load error:', e.nativeEvent.error) })))));
|
|
126
135
|
};
|
|
127
136
|
exports.CropEditor = CropEditor;
|
|
128
137
|
const styles = react_native_1.StyleSheet.create({
|
|
@@ -157,10 +166,8 @@ const styles = react_native_1.StyleSheet.create({
|
|
|
157
166
|
fontSize: 12,
|
|
158
167
|
textAlign: 'center',
|
|
159
168
|
},
|
|
160
|
-
|
|
161
|
-
width:
|
|
162
|
-
height:
|
|
163
|
-
opacity: 0,
|
|
164
|
-
position: 'absolute',
|
|
169
|
+
fullImage: {
|
|
170
|
+
width: '100%',
|
|
171
|
+
height: '100%',
|
|
165
172
|
},
|
|
166
173
|
});
|
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) {
|
|
@@ -224,20 +224,25 @@ const FullDocScanner = ({ onResult, onClose, detectionConfig, overlayColor = '#3
|
|
|
224
224
|
console.log('[FullDocScanner] Already processing, skipping manual capture');
|
|
225
225
|
return;
|
|
226
226
|
}
|
|
227
|
+
// Reset DocScanner state before capturing
|
|
228
|
+
docScannerRef.current?.reset();
|
|
227
229
|
console.log('[FullDocScanner] Setting manualCapturePending to true');
|
|
228
230
|
manualCapturePending.current = true;
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
231
|
+
// Small delay to ensure reset completes
|
|
232
|
+
setTimeout(() => {
|
|
233
|
+
const capturePromise = docScannerRef.current?.capture();
|
|
234
|
+
console.log('[FullDocScanner] capturePromise:', !!capturePromise);
|
|
235
|
+
if (capturePromise && typeof capturePromise.catch === 'function') {
|
|
236
|
+
capturePromise.catch((error) => {
|
|
237
|
+
manualCapturePending.current = false;
|
|
238
|
+
console.warn('[FullDocScanner] manual capture failed', error);
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
else if (!capturePromise) {
|
|
242
|
+
console.warn('[FullDocScanner] No capture promise returned');
|
|
233
243
|
manualCapturePending.current = false;
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
}
|
|
237
|
-
else if (!capturePromise) {
|
|
238
|
-
console.warn('[FullDocScanner] No capture promise returned');
|
|
239
|
-
manualCapturePending.current = false;
|
|
240
|
-
}
|
|
244
|
+
}
|
|
245
|
+
}, 100);
|
|
241
246
|
}, []);
|
|
242
247
|
const performCrop = (0, react_1.useCallback)(async () => {
|
|
243
248
|
if (!capturedDoc) {
|
|
@@ -315,24 +320,24 @@ const FullDocScanner = ({ onResult, onClose, detectionConfig, overlayColor = '#3
|
|
|
315
320
|
return (react_1.default.createElement(react_native_1.View, { style: styles.container },
|
|
316
321
|
screen === 'scanner' && (react_1.default.createElement(react_native_1.View, { style: styles.flex },
|
|
317
322
|
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.
|
|
323
|
+
react_1.default.createElement(react_native_1.View, { style: styles.overlayTop, pointerEvents: "box-none" },
|
|
319
324
|
react_1.default.createElement(react_native_1.TouchableOpacity, { style: styles.closeButton, onPress: handleClose, accessibilityLabel: mergedStrings.cancel, accessibilityRole: "button" },
|
|
320
|
-
react_1.default.createElement(react_native_1.Text, { style: styles.closeButtonLabel }, "\u00D7")),
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
react_1.default.createElement(react_native_1.Text, { style: styles.captureText }, mergedStrings.
|
|
325
|
+
react_1.default.createElement(react_native_1.Text, { style: styles.closeButtonLabel }, "\u00D7"))),
|
|
326
|
+
(mergedStrings.captureHint || mergedStrings.manualHint) && (react_1.default.createElement(react_native_1.View, { style: styles.instructionsContainer, pointerEvents: "none" },
|
|
327
|
+
react_1.default.createElement(react_native_1.View, { style: styles.instructions },
|
|
328
|
+
mergedStrings.captureHint && (react_1.default.createElement(react_native_1.Text, { style: styles.captureText }, mergedStrings.captureHint)),
|
|
329
|
+
mergedStrings.manualHint && (react_1.default.createElement(react_native_1.Text, { style: styles.captureText }, mergedStrings.manualHint))))),
|
|
330
|
+
react_1.default.createElement(react_native_1.View, { style: styles.shutterContainer, pointerEvents: "box-none" },
|
|
324
331
|
react_1.default.createElement(react_native_1.TouchableOpacity, { style: [styles.shutterButton, processing && styles.shutterButtonDisabled], onPress: triggerManualCapture, disabled: processing, accessibilityLabel: mergedStrings.manualHint, accessibilityRole: "button" },
|
|
325
332
|
react_1.default.createElement(react_native_1.View, { style: styles.shutterInner })))))),
|
|
326
333
|
screen === 'crop' && capturedDoc && (react_1.default.createElement(react_native_1.View, { style: styles.flex },
|
|
327
334
|
react_1.default.createElement(CropEditor_1.CropEditor, { document: capturedDoc, overlayColor: "rgba(0,0,0,0.6)", overlayStrokeColor: overlayStrokeColor, handlerColor: handlerColor, onCropChange: handleCropChange }),
|
|
328
335
|
react_1.default.createElement(react_native_1.View, { style: styles.cropFooter },
|
|
329
|
-
react_1.default.createElement(react_native_1.TouchableOpacity, { style: [styles.actionButton, styles.secondaryButton], onPress: handleRetake },
|
|
330
|
-
|
|
331
|
-
react_1.default.createElement(react_native_1.TouchableOpacity, { style: [styles.actionButton, styles.primaryButton], onPress: handleConfirm },
|
|
332
|
-
react_1.default.createElement(react_native_1.Text, { style: styles.buttonText }, mergedStrings.confirm))))),
|
|
336
|
+
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)),
|
|
337
|
+
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))))),
|
|
333
338
|
processing && (react_1.default.createElement(react_native_1.View, { style: styles.processingOverlay },
|
|
334
339
|
react_1.default.createElement(react_native_1.ActivityIndicator, { size: "large", color: overlayStrokeColor }),
|
|
335
|
-
react_1.default.createElement(react_native_1.Text, { style: styles.processingText }, mergedStrings.processing)))));
|
|
340
|
+
mergedStrings.processing && (react_1.default.createElement(react_native_1.Text, { style: styles.processingText }, mergedStrings.processing))))));
|
|
336
341
|
};
|
|
337
342
|
exports.FullDocScanner = FullDocScanner;
|
|
338
343
|
const styles = react_native_1.StyleSheet.create({
|
|
@@ -343,12 +348,27 @@ const styles = react_native_1.StyleSheet.create({
|
|
|
343
348
|
flex: {
|
|
344
349
|
flex: 1,
|
|
345
350
|
},
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
351
|
+
overlayTop: {
|
|
352
|
+
position: 'absolute',
|
|
353
|
+
top: 48,
|
|
354
|
+
right: 24,
|
|
355
|
+
zIndex: 10,
|
|
356
|
+
},
|
|
357
|
+
instructionsContainer: {
|
|
358
|
+
position: 'absolute',
|
|
359
|
+
top: '40%',
|
|
360
|
+
left: 0,
|
|
361
|
+
right: 0,
|
|
362
|
+
alignItems: 'center',
|
|
363
|
+
zIndex: 5,
|
|
364
|
+
},
|
|
365
|
+
shutterContainer: {
|
|
366
|
+
position: 'absolute',
|
|
367
|
+
bottom: 64,
|
|
368
|
+
left: 0,
|
|
369
|
+
right: 0,
|
|
370
|
+
alignItems: 'center',
|
|
371
|
+
zIndex: 10,
|
|
352
372
|
},
|
|
353
373
|
closeButton: {
|
|
354
374
|
width: 40,
|
|
@@ -357,7 +377,6 @@ const styles = react_native_1.StyleSheet.create({
|
|
|
357
377
|
backgroundColor: 'rgba(0,0,0,0.5)',
|
|
358
378
|
justifyContent: 'center',
|
|
359
379
|
alignItems: 'center',
|
|
360
|
-
alignSelf: 'flex-end',
|
|
361
380
|
},
|
|
362
381
|
closeButtonLabel: {
|
|
363
382
|
color: '#fff',
|
|
@@ -366,7 +385,6 @@ const styles = react_native_1.StyleSheet.create({
|
|
|
366
385
|
marginTop: -3,
|
|
367
386
|
},
|
|
368
387
|
instructions: {
|
|
369
|
-
alignSelf: 'center',
|
|
370
388
|
backgroundColor: 'rgba(0,0,0,0.55)',
|
|
371
389
|
borderRadius: 16,
|
|
372
390
|
paddingHorizontal: 20,
|
|
@@ -378,7 +396,6 @@ const styles = react_native_1.StyleSheet.create({
|
|
|
378
396
|
textAlign: 'center',
|
|
379
397
|
},
|
|
380
398
|
shutterButton: {
|
|
381
|
-
alignSelf: 'center',
|
|
382
399
|
width: 80,
|
|
383
400
|
height: 80,
|
|
384
401
|
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.38.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,28 @@ 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
|
+
{/* Full screen image */}
|
|
155
|
+
<Image
|
|
156
|
+
source={{ uri: imageUri }}
|
|
157
|
+
style={styles.fullImage}
|
|
158
|
+
resizeMode="contain"
|
|
159
|
+
onLoad={() => console.log('[CropEditor] Image loaded successfully')}
|
|
160
|
+
onError={(e) => console.error('[CropEditor] Image load error:', e.nativeEvent.error)}
|
|
161
|
+
/>
|
|
162
|
+
{/* Temporarily disabled CustomImageCropper - showing image only */}
|
|
163
|
+
{/* <CustomImageCropper
|
|
164
|
+
height={displaySize.height}
|
|
165
|
+
width={displaySize.width}
|
|
166
|
+
image={imageUri}
|
|
167
|
+
rectangleCoordinates={initialRect}
|
|
168
|
+
overlayColor={overlayColor}
|
|
169
|
+
overlayStrokeColor={overlayStrokeColor}
|
|
170
|
+
handlerColor={handlerColor}
|
|
171
|
+
enablePanStrict={enablePanStrict}
|
|
172
|
+
onDragEnd={handleDragEnd}
|
|
173
|
+
/> */}
|
|
174
|
+
</>
|
|
150
175
|
)}
|
|
151
176
|
</View>
|
|
152
177
|
);
|
|
@@ -184,10 +209,8 @@ const styles = StyleSheet.create({
|
|
|
184
209
|
fontSize: 12,
|
|
185
210
|
textAlign: 'center',
|
|
186
211
|
},
|
|
187
|
-
|
|
188
|
-
width:
|
|
189
|
-
height:
|
|
190
|
-
opacity: 0,
|
|
191
|
-
position: 'absolute',
|
|
212
|
+
fullImage: {
|
|
213
|
+
width: '100%',
|
|
214
|
+
height: '100%',
|
|
192
215
|
},
|
|
193
216
|
});
|
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
|
);
|
|
@@ -347,19 +347,27 @@ export const FullDocScanner: React.FC<FullDocScannerProps> = ({
|
|
|
347
347
|
console.log('[FullDocScanner] Already processing, skipping manual capture');
|
|
348
348
|
return;
|
|
349
349
|
}
|
|
350
|
+
|
|
351
|
+
// Reset DocScanner state before capturing
|
|
352
|
+
docScannerRef.current?.reset();
|
|
353
|
+
|
|
350
354
|
console.log('[FullDocScanner] Setting manualCapturePending to true');
|
|
351
355
|
manualCapturePending.current = true;
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
capturePromise.
|
|
356
|
+
|
|
357
|
+
// Small delay to ensure reset completes
|
|
358
|
+
setTimeout(() => {
|
|
359
|
+
const capturePromise = docScannerRef.current?.capture();
|
|
360
|
+
console.log('[FullDocScanner] capturePromise:', !!capturePromise);
|
|
361
|
+
if (capturePromise && typeof capturePromise.catch === 'function') {
|
|
362
|
+
capturePromise.catch((error: unknown) => {
|
|
363
|
+
manualCapturePending.current = false;
|
|
364
|
+
console.warn('[FullDocScanner] manual capture failed', error);
|
|
365
|
+
});
|
|
366
|
+
} else if (!capturePromise) {
|
|
367
|
+
console.warn('[FullDocScanner] No capture promise returned');
|
|
356
368
|
manualCapturePending.current = false;
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
} else if (!capturePromise) {
|
|
360
|
-
console.warn('[FullDocScanner] No capture promise returned');
|
|
361
|
-
manualCapturePending.current = false;
|
|
362
|
-
}
|
|
369
|
+
}
|
|
370
|
+
}, 100);
|
|
363
371
|
}, []);
|
|
364
372
|
|
|
365
373
|
const performCrop = useCallback(async (): Promise<{ base64: string; rectangle: Rectangle }> => {
|
|
@@ -479,7 +487,7 @@ export const FullDocScanner: React.FC<FullDocScannerProps> = ({
|
|
|
479
487
|
onCapture={handleCapture}
|
|
480
488
|
showManualCaptureButton={false}
|
|
481
489
|
>
|
|
482
|
-
<View style={styles.
|
|
490
|
+
<View style={styles.overlayTop} pointerEvents="box-none">
|
|
483
491
|
<TouchableOpacity
|
|
484
492
|
style={styles.closeButton}
|
|
485
493
|
onPress={handleClose}
|
|
@@ -488,10 +496,20 @@ export const FullDocScanner: React.FC<FullDocScannerProps> = ({
|
|
|
488
496
|
>
|
|
489
497
|
<Text style={styles.closeButtonLabel}>×</Text>
|
|
490
498
|
</TouchableOpacity>
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
499
|
+
</View>
|
|
500
|
+
{(mergedStrings.captureHint || mergedStrings.manualHint) && (
|
|
501
|
+
<View style={styles.instructionsContainer} pointerEvents="none">
|
|
502
|
+
<View style={styles.instructions}>
|
|
503
|
+
{mergedStrings.captureHint && (
|
|
504
|
+
<Text style={styles.captureText}>{mergedStrings.captureHint}</Text>
|
|
505
|
+
)}
|
|
506
|
+
{mergedStrings.manualHint && (
|
|
507
|
+
<Text style={styles.captureText}>{mergedStrings.manualHint}</Text>
|
|
508
|
+
)}
|
|
509
|
+
</View>
|
|
494
510
|
</View>
|
|
511
|
+
)}
|
|
512
|
+
<View style={styles.shutterContainer} pointerEvents="box-none">
|
|
495
513
|
<TouchableOpacity
|
|
496
514
|
style={[styles.shutterButton, processing && styles.shutterButtonDisabled]}
|
|
497
515
|
onPress={triggerManualCapture}
|
|
@@ -517,10 +535,10 @@ export const FullDocScanner: React.FC<FullDocScannerProps> = ({
|
|
|
517
535
|
/>
|
|
518
536
|
<View style={styles.cropFooter}>
|
|
519
537
|
<TouchableOpacity style={[styles.actionButton, styles.secondaryButton]} onPress={handleRetake}>
|
|
520
|
-
<Text style={styles.buttonText}>{mergedStrings.retake}</Text>
|
|
538
|
+
{mergedStrings.retake && <Text style={styles.buttonText}>{mergedStrings.retake}</Text>}
|
|
521
539
|
</TouchableOpacity>
|
|
522
540
|
<TouchableOpacity style={[styles.actionButton, styles.primaryButton]} onPress={handleConfirm}>
|
|
523
|
-
<Text style={styles.buttonText}>{mergedStrings.confirm}</Text>
|
|
541
|
+
{mergedStrings.confirm && <Text style={styles.buttonText}>{mergedStrings.confirm}</Text>}
|
|
524
542
|
</TouchableOpacity>
|
|
525
543
|
</View>
|
|
526
544
|
</View>
|
|
@@ -529,7 +547,9 @@ export const FullDocScanner: React.FC<FullDocScannerProps> = ({
|
|
|
529
547
|
{processing && (
|
|
530
548
|
<View style={styles.processingOverlay}>
|
|
531
549
|
<ActivityIndicator size="large" color={overlayStrokeColor} />
|
|
532
|
-
|
|
550
|
+
{mergedStrings.processing && (
|
|
551
|
+
<Text style={styles.processingText}>{mergedStrings.processing}</Text>
|
|
552
|
+
)}
|
|
533
553
|
</View>
|
|
534
554
|
)}
|
|
535
555
|
</View>
|
|
@@ -544,12 +564,27 @@ const styles = StyleSheet.create({
|
|
|
544
564
|
flex: {
|
|
545
565
|
flex: 1,
|
|
546
566
|
},
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
567
|
+
overlayTop: {
|
|
568
|
+
position: 'absolute',
|
|
569
|
+
top: 48,
|
|
570
|
+
right: 24,
|
|
571
|
+
zIndex: 10,
|
|
572
|
+
},
|
|
573
|
+
instructionsContainer: {
|
|
574
|
+
position: 'absolute',
|
|
575
|
+
top: '40%',
|
|
576
|
+
left: 0,
|
|
577
|
+
right: 0,
|
|
578
|
+
alignItems: 'center',
|
|
579
|
+
zIndex: 5,
|
|
580
|
+
},
|
|
581
|
+
shutterContainer: {
|
|
582
|
+
position: 'absolute',
|
|
583
|
+
bottom: 64,
|
|
584
|
+
left: 0,
|
|
585
|
+
right: 0,
|
|
586
|
+
alignItems: 'center',
|
|
587
|
+
zIndex: 10,
|
|
553
588
|
},
|
|
554
589
|
closeButton: {
|
|
555
590
|
width: 40,
|
|
@@ -558,7 +593,6 @@ const styles = StyleSheet.create({
|
|
|
558
593
|
backgroundColor: 'rgba(0,0,0,0.5)',
|
|
559
594
|
justifyContent: 'center',
|
|
560
595
|
alignItems: 'center',
|
|
561
|
-
alignSelf: 'flex-end',
|
|
562
596
|
},
|
|
563
597
|
closeButtonLabel: {
|
|
564
598
|
color: '#fff',
|
|
@@ -567,7 +601,6 @@ const styles = StyleSheet.create({
|
|
|
567
601
|
marginTop: -3,
|
|
568
602
|
},
|
|
569
603
|
instructions: {
|
|
570
|
-
alignSelf: 'center',
|
|
571
604
|
backgroundColor: 'rgba(0,0,0,0.55)',
|
|
572
605
|
borderRadius: 16,
|
|
573
606
|
paddingHorizontal: 20,
|
|
@@ -579,7 +612,6 @@ const styles = StyleSheet.create({
|
|
|
579
612
|
textAlign: 'center',
|
|
580
613
|
},
|
|
581
614
|
shutterButton: {
|
|
582
|
-
alignSelf: 'center',
|
|
583
615
|
width: 80,
|
|
584
616
|
height: 80,
|
|
585
617
|
borderRadius: 40,
|