@teamnhz/rn-ui-toolkit 1.1.8 → 1.1.9
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/components/ImagePicker/index.js +56 -303
- package/package.json +1 -1
|
@@ -1,259 +1,3 @@
|
|
|
1
|
-
// import React, { useCallback } from "react";
|
|
2
|
-
// import {
|
|
3
|
-
// View,
|
|
4
|
-
// Text,
|
|
5
|
-
// TouchableOpacity,
|
|
6
|
-
// StyleSheet,
|
|
7
|
-
// Image,
|
|
8
|
-
// Alert,
|
|
9
|
-
// } from "react-native";
|
|
10
|
-
// import { BottomSheet, Dividers } from "../index";
|
|
11
|
-
// import { launchCamera, launchImageLibrary } from "react-native-image-picker";
|
|
12
|
-
// import ImageCropPicker from "react-native-image-crop-picker";
|
|
13
|
-
// import {
|
|
14
|
-
// Image as ImageCompressor,
|
|
15
|
-
// Video as VideoCompressor,
|
|
16
|
-
// } from "react-native-compressor";
|
|
17
|
-
// import RNFS from "react-native-fs";
|
|
18
|
-
// import { Colors, Images, Scale, Typography } from "../../styles";
|
|
19
|
-
// // Import your permission utilities
|
|
20
|
-
// import {
|
|
21
|
-
// cameraPermissions,
|
|
22
|
-
// galleryPermissions,
|
|
23
|
-
// checkMicroPhonePermission,
|
|
24
|
-
// } from "../../utils/permissions";
|
|
25
|
-
// type Props = {
|
|
26
|
-
// mediaType: "photo" | "video";
|
|
27
|
-
// isMultiSelect?: boolean;
|
|
28
|
-
// onSuccess: (data: any) => void;
|
|
29
|
-
// visible: boolean;
|
|
30
|
-
// onClose: () => void;
|
|
31
|
-
// // Compression options
|
|
32
|
-
// enableCompression?: boolean;
|
|
33
|
-
// imageCompressionOptions?: {
|
|
34
|
-
// maxWidth?: number;
|
|
35
|
-
// quality?: number;
|
|
36
|
-
// };
|
|
37
|
-
// videoCompressionOptions?: {
|
|
38
|
-
// compressionMethod?: "auto" | "manual";
|
|
39
|
-
// };
|
|
40
|
-
// };
|
|
41
|
-
// const ImagePicker: React.FC<Props> = ({
|
|
42
|
-
// mediaType,
|
|
43
|
-
// isMultiSelect = false,
|
|
44
|
-
// onSuccess,
|
|
45
|
-
// visible,
|
|
46
|
-
// onClose,
|
|
47
|
-
// enableCompression = true,
|
|
48
|
-
// imageCompressionOptions = { maxWidth: 1080, quality: 0.7 },
|
|
49
|
-
// videoCompressionOptions = { compressionMethod: "auto" },
|
|
50
|
-
// }) => {
|
|
51
|
-
// // Success handler
|
|
52
|
-
// const onComplete = useCallback(
|
|
53
|
-
// (data: any) => {
|
|
54
|
-
// onSuccess(data);
|
|
55
|
-
// onClose();
|
|
56
|
-
// },
|
|
57
|
-
// [onSuccess, onClose]
|
|
58
|
-
// );
|
|
59
|
-
// // Helper: Compress Image
|
|
60
|
-
// const compressImage = async (imagePath: string) => {
|
|
61
|
-
// if (!enableCompression) return imagePath;
|
|
62
|
-
// try {
|
|
63
|
-
// const compressedImage = await ImageCompressor.compress(imagePath, {
|
|
64
|
-
// maxWidth: imageCompressionOptions.maxWidth,
|
|
65
|
-
// quality: imageCompressionOptions.quality,
|
|
66
|
-
// });
|
|
67
|
-
// // Log compressed size (optional)
|
|
68
|
-
// const stats = await RNFS.stat(compressedImage.replace("file://", ""));
|
|
69
|
-
// const sizeInMB = stats.size / (1024 * 1024);
|
|
70
|
-
// console.log("Compressed Image Size (MB):", sizeInMB);
|
|
71
|
-
// return compressedImage;
|
|
72
|
-
// } catch (error) {
|
|
73
|
-
// console.error("Image compression error:", error);
|
|
74
|
-
// return imagePath; // Return original if compression fails
|
|
75
|
-
// }
|
|
76
|
-
// };
|
|
77
|
-
// // Helper: Compress Video
|
|
78
|
-
// const compressVideo = async (videoUri: string) => {
|
|
79
|
-
// if (!enableCompression) return videoUri;
|
|
80
|
-
// try {
|
|
81
|
-
// const compressedVideo = await VideoCompressor.compress(videoUri, {
|
|
82
|
-
// compressionMethod: videoCompressionOptions.compressionMethod,
|
|
83
|
-
// });
|
|
84
|
-
// // Log compressed size (optional)
|
|
85
|
-
// const stats = await RNFS.stat(compressedVideo.replace("file://", ""));
|
|
86
|
-
// const sizeInMB = stats.size / (1024 * 1024);
|
|
87
|
-
// console.log("Compressed Video Size (MB):", sizeInMB);
|
|
88
|
-
// return compressedVideo;
|
|
89
|
-
// } catch (error) {
|
|
90
|
-
// console.error("Video compression error:", error);
|
|
91
|
-
// return videoUri; // Return original if compression fails
|
|
92
|
-
// }
|
|
93
|
-
// };
|
|
94
|
-
// // CAMERA HANDLER with permission check and compression
|
|
95
|
-
// const handleCamera = async () => {
|
|
96
|
-
// await cameraPermissions(async (granted: boolean) => {
|
|
97
|
-
// if (!granted) return;
|
|
98
|
-
// if (mediaType === "photo") {
|
|
99
|
-
// try {
|
|
100
|
-
// const response = await ImageCropPicker.openCamera({
|
|
101
|
-
// mediaType: "photo",
|
|
102
|
-
// });
|
|
103
|
-
// if (isMultiSelect) {
|
|
104
|
-
// // Single capture for multi-select mode
|
|
105
|
-
// const compressedPath = await compressImage(response.path);
|
|
106
|
-
// onComplete([{ ...response, path: compressedPath }]);
|
|
107
|
-
// } else {
|
|
108
|
-
// // Crop and compress single image
|
|
109
|
-
// const cropped = await ImageCropPicker.openCropper({
|
|
110
|
-
// path: response?.path,
|
|
111
|
-
// width: response?.width,
|
|
112
|
-
// height: response?.height,
|
|
113
|
-
// mediaType: "photo",
|
|
114
|
-
// freeStyleCropEnabled: true,
|
|
115
|
-
// });
|
|
116
|
-
// const compressedPath = await compressImage(cropped.path);
|
|
117
|
-
// onComplete({ ...cropped, path: compressedPath });
|
|
118
|
-
// }
|
|
119
|
-
// } catch (error) {
|
|
120
|
-
// console.log("Camera cancelled or error:", error);
|
|
121
|
-
// }
|
|
122
|
-
// } else {
|
|
123
|
-
// // VIDEO CAPTURE - check microphone permission first
|
|
124
|
-
// const micPermission = await checkMicroPhonePermission();
|
|
125
|
-
// if (!micPermission) {
|
|
126
|
-
// Alert.alert(
|
|
127
|
-
// "Microphone Permission Required",
|
|
128
|
-
// "Please enable microphone access to record videos."
|
|
129
|
-
// );
|
|
130
|
-
// return;
|
|
131
|
-
// }
|
|
132
|
-
// launchCamera(
|
|
133
|
-
// {
|
|
134
|
-
// mediaType: "video",
|
|
135
|
-
// durationLimit: 60,
|
|
136
|
-
// videoQuality: "high",
|
|
137
|
-
// },
|
|
138
|
-
// async (response) => {
|
|
139
|
-
// if (response?.assets?.length) {
|
|
140
|
-
// const videoUri = response.assets[0]?.uri;
|
|
141
|
-
// const compressedPath = await compressVideo(videoUri);
|
|
142
|
-
// onComplete({
|
|
143
|
-
// path: compressedPath,
|
|
144
|
-
// duration: response.assets[0]?.duration,
|
|
145
|
-
// });
|
|
146
|
-
// }
|
|
147
|
-
// }
|
|
148
|
-
// );
|
|
149
|
-
// }
|
|
150
|
-
// });
|
|
151
|
-
// };
|
|
152
|
-
// // GALLERY HANDLER with permission check and compression
|
|
153
|
-
// const handleGallery = async () => {
|
|
154
|
-
// await galleryPermissions(async (granted: boolean) => {
|
|
155
|
-
// if (!granted) return;
|
|
156
|
-
// if (mediaType === "photo") {
|
|
157
|
-
// try {
|
|
158
|
-
// if (isMultiSelect) {
|
|
159
|
-
// const images = await ImageCropPicker.openPicker({
|
|
160
|
-
// mediaType: "photo",
|
|
161
|
-
// multiple: true,
|
|
162
|
-
// maxFiles: 5,
|
|
163
|
-
// });
|
|
164
|
-
// if (images.length > 5) {
|
|
165
|
-
// Alert.alert(
|
|
166
|
-
// "Limit Exceeded",
|
|
167
|
-
// "You can only select up to 5 images."
|
|
168
|
-
// );
|
|
169
|
-
// return;
|
|
170
|
-
// }
|
|
171
|
-
// // Compress multiple images
|
|
172
|
-
// const compressedImages = await Promise.all(
|
|
173
|
-
// images.map(async (img) => ({
|
|
174
|
-
// ...img,
|
|
175
|
-
// path: await compressImage(img.path),
|
|
176
|
-
// }))
|
|
177
|
-
// );
|
|
178
|
-
// onComplete(compressedImages);
|
|
179
|
-
// } else {
|
|
180
|
-
// // Single image with crop
|
|
181
|
-
// const response = await ImageCropPicker.openPicker({
|
|
182
|
-
// mediaType: "photo",
|
|
183
|
-
// });
|
|
184
|
-
// const cropped = await ImageCropPicker.openCropper({
|
|
185
|
-
// path: response?.path,
|
|
186
|
-
// width: response?.width,
|
|
187
|
-
// height: response?.height,
|
|
188
|
-
// mediaType: "photo",
|
|
189
|
-
// freeStyleCropEnabled: true,
|
|
190
|
-
// });
|
|
191
|
-
// const compressedPath = await compressImage(cropped.path);
|
|
192
|
-
// onComplete({ ...cropped, path: compressedPath });
|
|
193
|
-
// }
|
|
194
|
-
// } catch (error) {
|
|
195
|
-
// console.log("Gallery cancelled or error:", error);
|
|
196
|
-
// }
|
|
197
|
-
// } else {
|
|
198
|
-
// // VIDEO FROM GALLERY
|
|
199
|
-
// launchImageLibrary(
|
|
200
|
-
// {
|
|
201
|
-
// mediaType: "video",
|
|
202
|
-
// assetRepresentationMode: "current",
|
|
203
|
-
// },
|
|
204
|
-
// async (result) => {
|
|
205
|
-
// if (result?.assets?.length) {
|
|
206
|
-
// const videoUri = result.assets[0]?.uri;
|
|
207
|
-
// const compressedPath = await compressVideo(videoUri);
|
|
208
|
-
// onComplete({
|
|
209
|
-
// path: compressedPath,
|
|
210
|
-
// duration: result.assets[0]?.duration,
|
|
211
|
-
// });
|
|
212
|
-
// }
|
|
213
|
-
// }
|
|
214
|
-
// );
|
|
215
|
-
// }
|
|
216
|
-
// });
|
|
217
|
-
// };
|
|
218
|
-
// return (
|
|
219
|
-
// <BottomSheet visible={visible} onClose={onClose} height={230}>
|
|
220
|
-
// <View style={styles.container}>
|
|
221
|
-
// {/* Camera */}
|
|
222
|
-
// <TouchableOpacity style={styles.row} onPress={handleCamera}>
|
|
223
|
-
// <Image source={Images.video_icon} style={styles.icon} />
|
|
224
|
-
// <Text style={styles.text}>Camera</Text>
|
|
225
|
-
// </TouchableOpacity>
|
|
226
|
-
// <Dividers small />
|
|
227
|
-
// {/* Gallery */}
|
|
228
|
-
// <TouchableOpacity style={styles.row} onPress={handleGallery}>
|
|
229
|
-
// <Image source={Images.image_icon} style={styles.icon} />
|
|
230
|
-
// <Text style={styles.text}>Gallery</Text>
|
|
231
|
-
// </TouchableOpacity>
|
|
232
|
-
// <Dividers small />
|
|
233
|
-
// {/* Cancel */}
|
|
234
|
-
// <TouchableOpacity style={styles.row} onPress={onClose}>
|
|
235
|
-
// <Image source={Images.cancel} style={styles.icon} />
|
|
236
|
-
// <Text style={styles.text}>Cancel</Text>
|
|
237
|
-
// </TouchableOpacity>
|
|
238
|
-
// </View>
|
|
239
|
-
// </BottomSheet>
|
|
240
|
-
// );
|
|
241
|
-
// };
|
|
242
|
-
// export default ImagePicker;
|
|
243
|
-
// const styles = StyleSheet.create({
|
|
244
|
-
// container: { flex: 1, padding: 16 },
|
|
245
|
-
// row: {
|
|
246
|
-
// flexDirection: "row",
|
|
247
|
-
// alignItems: "center",
|
|
248
|
-
// },
|
|
249
|
-
// text: { ...Typography.style.standardU(), color: Colors.white },
|
|
250
|
-
// icon: {
|
|
251
|
-
// width: Scale.moderateScale(20),
|
|
252
|
-
// height: Scale.moderateScale(20),
|
|
253
|
-
// marginRight: 10,
|
|
254
|
-
// tintColor: Colors.white,
|
|
255
|
-
// },
|
|
256
|
-
// });
|
|
257
1
|
import React from "react";
|
|
258
2
|
import { View, Text, TouchableOpacity, StyleSheet, Image, } from "react-native";
|
|
259
3
|
import { BottomSheet, Dividers } from "../index";
|
|
@@ -262,16 +6,35 @@ import ImageCropPicker from "react-native-image-crop-picker";
|
|
|
262
6
|
import { Image as ImageCompressor, Video as VideoCompressor, } from "react-native-compressor";
|
|
263
7
|
import { Colors, Images, Scale, Typography } from "../../styles";
|
|
264
8
|
import { cameraPermissions, galleryPermissions, checkMicroPhonePermission, } from "../../utils/permissions";
|
|
9
|
+
// NORMALIZE FINAL RESPONSE
|
|
10
|
+
const buildResponse = (raw, compressedPath) => {
|
|
11
|
+
return {
|
|
12
|
+
path: compressedPath || raw?.path || raw?.uri?.replace("file://", ""),
|
|
13
|
+
originalPath: raw?.path?.replace("file://", "") ||
|
|
14
|
+
raw?.uri?.replace("file://", "") ||
|
|
15
|
+
"",
|
|
16
|
+
fileName: raw?.fileName || "",
|
|
17
|
+
type: raw?.type || "",
|
|
18
|
+
duration: raw?.duration || undefined,
|
|
19
|
+
};
|
|
20
|
+
};
|
|
265
21
|
const ImagePicker = ({ mediaType, isMultiSelect = false, onSuccess, visible, onClose, enableCompression = true, }) => {
|
|
266
|
-
//
|
|
267
|
-
const
|
|
22
|
+
// SEND RAW (loading true) TO PARENT
|
|
23
|
+
const sendRaw = (raw) => {
|
|
268
24
|
onClose();
|
|
269
|
-
onSuccess({
|
|
25
|
+
onSuccess({
|
|
26
|
+
loading: true,
|
|
27
|
+
data: buildResponse(raw),
|
|
28
|
+
});
|
|
270
29
|
};
|
|
271
|
-
//
|
|
272
|
-
const
|
|
273
|
-
onSuccess({
|
|
30
|
+
// SEND FINAL COMPRESSED
|
|
31
|
+
const sendFinal = (raw, compressedPath) => {
|
|
32
|
+
onSuccess({
|
|
33
|
+
loading: false,
|
|
34
|
+
data: buildResponse(raw, compressedPath),
|
|
35
|
+
});
|
|
274
36
|
};
|
|
37
|
+
// IMAGE COMPRESSOR
|
|
275
38
|
const compressImage = async (path) => {
|
|
276
39
|
try {
|
|
277
40
|
const compressed = await ImageCompressor.compress(path, {
|
|
@@ -280,10 +43,11 @@ const ImagePicker = ({ mediaType, isMultiSelect = false, onSuccess, visible, onC
|
|
|
280
43
|
});
|
|
281
44
|
return compressed;
|
|
282
45
|
}
|
|
283
|
-
catch
|
|
46
|
+
catch {
|
|
284
47
|
return path;
|
|
285
48
|
}
|
|
286
49
|
};
|
|
50
|
+
// VIDEO COMPRESSOR
|
|
287
51
|
const compressVideo = async (uri) => {
|
|
288
52
|
try {
|
|
289
53
|
const compressed = await VideoCompressor.compress(uri, {
|
|
@@ -291,84 +55,73 @@ const ImagePicker = ({ mediaType, isMultiSelect = false, onSuccess, visible, onC
|
|
|
291
55
|
});
|
|
292
56
|
return compressed;
|
|
293
57
|
}
|
|
294
|
-
catch
|
|
58
|
+
catch {
|
|
295
59
|
return uri;
|
|
296
60
|
}
|
|
297
61
|
};
|
|
298
|
-
//
|
|
62
|
+
// ------------------ CAMERA ------------------
|
|
299
63
|
const handleCamera = async () => {
|
|
300
64
|
await cameraPermissions(async (granted) => {
|
|
301
65
|
if (!granted)
|
|
302
66
|
return;
|
|
303
67
|
if (mediaType === "photo") {
|
|
304
68
|
try {
|
|
305
|
-
const picked = await ImageCropPicker.openCamera({
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
sendFinalCompressed({ ...picked, path: compressedPath });
|
|
312
|
-
}, 10);
|
|
69
|
+
const picked = await ImageCropPicker.openCamera({ mediaType: "photo" });
|
|
70
|
+
sendRaw(picked);
|
|
71
|
+
const compressed = enableCompression
|
|
72
|
+
? await compressImage(picked.path)
|
|
73
|
+
: picked.path;
|
|
74
|
+
sendFinal(picked, compressed);
|
|
313
75
|
}
|
|
314
|
-
catch (
|
|
315
|
-
console.log(
|
|
76
|
+
catch (e) {
|
|
77
|
+
console.log(e);
|
|
316
78
|
}
|
|
317
79
|
}
|
|
318
80
|
else {
|
|
319
|
-
// VIDEO
|
|
320
81
|
const mic = await checkMicroPhonePermission();
|
|
321
82
|
if (!mic)
|
|
322
83
|
return;
|
|
323
|
-
launchCamera({ mediaType: "video", durationLimit: 60, videoQuality: "high" }, (res) => {
|
|
84
|
+
launchCamera({ mediaType: "video", durationLimit: 60, videoQuality: "high" }, async (res) => {
|
|
324
85
|
if (!res?.assets?.length)
|
|
325
86
|
return;
|
|
326
87
|
const raw = res.assets[0];
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
duration: raw.duration,
|
|
333
|
-
});
|
|
334
|
-
}, 10);
|
|
88
|
+
sendRaw(raw);
|
|
89
|
+
const compressed = enableCompression
|
|
90
|
+
? await compressVideo(raw.uri)
|
|
91
|
+
: raw.uri;
|
|
92
|
+
sendFinal(raw, compressed);
|
|
335
93
|
});
|
|
336
94
|
}
|
|
337
95
|
});
|
|
338
96
|
};
|
|
339
|
-
//
|
|
97
|
+
// ------------------ GALLERY ------------------
|
|
340
98
|
const handleGallery = async () => {
|
|
341
99
|
await galleryPermissions(async (granted) => {
|
|
342
100
|
if (!granted)
|
|
343
101
|
return;
|
|
344
102
|
if (mediaType === "photo") {
|
|
345
103
|
try {
|
|
346
|
-
const picked = await ImageCropPicker.openPicker({
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
sendFinalCompressed({ ...picked, path: compressed });
|
|
353
|
-
}, 10);
|
|
104
|
+
const picked = await ImageCropPicker.openPicker({ mediaType: "photo" });
|
|
105
|
+
sendRaw(picked);
|
|
106
|
+
const compressed = enableCompression
|
|
107
|
+
? await compressImage(picked.path)
|
|
108
|
+
: picked.path;
|
|
109
|
+
sendFinal(picked, compressed);
|
|
354
110
|
}
|
|
355
111
|
catch (e) {
|
|
356
112
|
console.log(e);
|
|
357
113
|
}
|
|
358
114
|
}
|
|
359
115
|
else {
|
|
360
|
-
launchImageLibrary({ mediaType: "video" }, (res) => {
|
|
116
|
+
launchImageLibrary({ mediaType: "video" }, async (res) => {
|
|
361
117
|
if (!res?.assets?.length)
|
|
362
118
|
return;
|
|
363
119
|
const raw = res.assets[0];
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
duration: raw.duration,
|
|
370
|
-
});
|
|
371
|
-
}, 10);
|
|
120
|
+
sendRaw(raw);
|
|
121
|
+
const compressed = enableCompression
|
|
122
|
+
? await compressVideo(raw.uri)
|
|
123
|
+
: raw.uri;
|
|
124
|
+
sendFinal(raw, compressed);
|
|
372
125
|
});
|
|
373
126
|
}
|
|
374
127
|
});
|