@teamnhz/rn-ui-toolkit 1.2.8 → 1.2.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.
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import { Modal, View, StyleSheet, TouchableOpacity } from "react-native";
|
|
3
3
|
import { Colors } from "../../styles";
|
|
4
|
-
const BottomSheet = ({ ref, visible, onClose, children, height = 300, }) => {
|
|
4
|
+
const BottomSheet = ({ ref, visible, onClose, children, height = 300, sheetBackground = Colors.appThemeColor, }) => {
|
|
5
5
|
return (React.createElement(Modal, { ref: ref, transparent: true, visible: visible, animationType: "slide" },
|
|
6
6
|
React.createElement(TouchableOpacity, { style: styles.overlay, activeOpacity: 1, onPress: onClose }),
|
|
7
|
-
React.createElement(View, { style: [
|
|
7
|
+
React.createElement(View, { style: [
|
|
8
|
+
styles.sheet,
|
|
9
|
+
{ height, backgroundColor: sheetBackground }, // 🔥 dynamic bg color
|
|
10
|
+
] },
|
|
8
11
|
React.createElement(View, { style: styles.dragIndicator }),
|
|
9
12
|
children)));
|
|
10
13
|
};
|
|
@@ -15,7 +18,6 @@ const styles = StyleSheet.create({
|
|
|
15
18
|
backgroundColor: "rgba(0,0,0,0.4)",
|
|
16
19
|
},
|
|
17
20
|
sheet: {
|
|
18
|
-
backgroundColor: Colors.appThemeColor,
|
|
19
21
|
borderTopLeftRadius: 16,
|
|
20
22
|
borderTopRightRadius: 16,
|
|
21
23
|
padding: 16,
|
|
@@ -1,10 +1,40 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
+
import { ViewStyle, TextStyle, ImageStyle } from "react-native";
|
|
3
|
+
import { cameraPermissions, galleryPermissions, checkMicroPhonePermission } from "../../utils/permissions";
|
|
4
|
+
type CustomStyles = {
|
|
5
|
+
container?: ViewStyle;
|
|
6
|
+
row?: ViewStyle;
|
|
7
|
+
text?: TextStyle;
|
|
8
|
+
icon?: ImageStyle;
|
|
9
|
+
backgroundColor?: any;
|
|
10
|
+
};
|
|
2
11
|
type Props = {
|
|
12
|
+
visible: boolean;
|
|
13
|
+
onClose: () => void;
|
|
3
14
|
mediaType: "photo" | "video";
|
|
4
15
|
isMultiSelect?: boolean;
|
|
5
16
|
onSuccess: (data: any) => void;
|
|
6
|
-
|
|
7
|
-
|
|
17
|
+
labels?: {
|
|
18
|
+
camera?: string;
|
|
19
|
+
gallery?: string;
|
|
20
|
+
cancel?: string;
|
|
21
|
+
};
|
|
22
|
+
icons?: {
|
|
23
|
+
camera?: any;
|
|
24
|
+
gallery?: any;
|
|
25
|
+
cancel?: any;
|
|
26
|
+
};
|
|
27
|
+
styles?: CustomStyles;
|
|
28
|
+
permissionHandlers?: {
|
|
29
|
+
camera?: typeof cameraPermissions;
|
|
30
|
+
gallery?: typeof galleryPermissions;
|
|
31
|
+
microphone?: typeof checkMicroPhonePermission;
|
|
32
|
+
};
|
|
33
|
+
pickerOptions?: {
|
|
34
|
+
camera?: object;
|
|
35
|
+
gallery?: object;
|
|
36
|
+
cropper?: object;
|
|
37
|
+
};
|
|
8
38
|
enableCompression?: boolean;
|
|
9
39
|
imageCompressionOptions?: {
|
|
10
40
|
maxWidth?: number;
|
|
@@ -320,205 +320,425 @@
|
|
|
320
320
|
// tintColor: Colors.white,
|
|
321
321
|
// },
|
|
322
322
|
// });
|
|
323
|
+
// import React, { useCallback } from "react";
|
|
324
|
+
// import {
|
|
325
|
+
// View,
|
|
326
|
+
// Text,
|
|
327
|
+
// TouchableOpacity,
|
|
328
|
+
// StyleSheet,
|
|
329
|
+
// Image,
|
|
330
|
+
// Alert,
|
|
331
|
+
// } from "react-native";
|
|
332
|
+
// import { BottomSheet, Dividers } from "../index";
|
|
333
|
+
// import { launchCamera, launchImageLibrary } from "react-native-image-picker";
|
|
334
|
+
// import ImageCropPicker from "react-native-image-crop-picker";
|
|
335
|
+
// import {
|
|
336
|
+
// Image as ImageCompressor,
|
|
337
|
+
// Video as VideoCompressor,
|
|
338
|
+
// } from "react-native-compressor";
|
|
339
|
+
// import RNFS from "react-native-fs";
|
|
340
|
+
// import { Colors, Images, Scale, Typography } from "../../styles";
|
|
341
|
+
// // Import your permission utilities
|
|
342
|
+
// import {
|
|
343
|
+
// cameraPermissions,
|
|
344
|
+
// galleryPermissions,
|
|
345
|
+
// checkMicroPhonePermission,
|
|
346
|
+
// } from "../../utils/permissions";
|
|
347
|
+
// type Props = {
|
|
348
|
+
// mediaType: "photo" | "video";
|
|
349
|
+
// isMultiSelect?: boolean;
|
|
350
|
+
// onSuccess: (data: any) => void;
|
|
351
|
+
// visible: boolean;
|
|
352
|
+
// onClose: () => void;
|
|
353
|
+
// // Compression options
|
|
354
|
+
// enableCompression?: boolean;
|
|
355
|
+
// imageCompressionOptions?: {
|
|
356
|
+
// maxWidth?: number;
|
|
357
|
+
// quality?: number;
|
|
358
|
+
// };
|
|
359
|
+
// videoCompressionOptions?: {
|
|
360
|
+
// compressionMethod?: "auto" | "manual";
|
|
361
|
+
// };
|
|
362
|
+
// };
|
|
363
|
+
// const ImagePicker: React.FC<Props> = ({
|
|
364
|
+
// mediaType,
|
|
365
|
+
// isMultiSelect = false,
|
|
366
|
+
// onSuccess,
|
|
367
|
+
// visible,
|
|
368
|
+
// onClose,
|
|
369
|
+
// enableCompression = true,
|
|
370
|
+
// imageCompressionOptions = { maxWidth: 1080, quality: 0.7 },
|
|
371
|
+
// videoCompressionOptions = { compressionMethod: "auto" },
|
|
372
|
+
// }) => {
|
|
373
|
+
// // Success handler
|
|
374
|
+
// const onComplete = useCallback(
|
|
375
|
+
// (data: any) => {
|
|
376
|
+
// onSuccess(data);
|
|
377
|
+
// onClose();
|
|
378
|
+
// },
|
|
379
|
+
// [onSuccess, onClose]
|
|
380
|
+
// );
|
|
381
|
+
// // Helper: Compress Image
|
|
382
|
+
// const compressImage = async (imagePath: string) => {
|
|
383
|
+
// if (!enableCompression) return imagePath;
|
|
384
|
+
// try {
|
|
385
|
+
// const compressedImage = await ImageCompressor.compress(imagePath, {
|
|
386
|
+
// maxWidth: imageCompressionOptions.maxWidth,
|
|
387
|
+
// quality: imageCompressionOptions.quality,
|
|
388
|
+
// });
|
|
389
|
+
// // Log compressed size (optional)
|
|
390
|
+
// const stats = await RNFS.stat(compressedImage.replace("file://", ""));
|
|
391
|
+
// const sizeInMB = stats.size / (1024 * 1024);
|
|
392
|
+
// console.log("Compressed Image Size (MB):", sizeInMB);
|
|
393
|
+
// return compressedImage;
|
|
394
|
+
// } catch (error) {
|
|
395
|
+
// console.error("Image compression error:", error);
|
|
396
|
+
// return imagePath; // Return original if compression fails
|
|
397
|
+
// }
|
|
398
|
+
// };
|
|
399
|
+
// // Helper: Compress Video
|
|
400
|
+
// const compressVideo = async (videoUri: string) => {
|
|
401
|
+
// if (!enableCompression) return videoUri;
|
|
402
|
+
// try {
|
|
403
|
+
// const compressedVideo = await VideoCompressor.compress(videoUri, {
|
|
404
|
+
// compressionMethod: videoCompressionOptions.compressionMethod,
|
|
405
|
+
// });
|
|
406
|
+
// // Log compressed size (optional)
|
|
407
|
+
// const stats = await RNFS.stat(compressedVideo.replace("file://", ""));
|
|
408
|
+
// const sizeInMB = stats.size / (1024 * 1024);
|
|
409
|
+
// console.log("Compressed Video Size (MB):", sizeInMB);
|
|
410
|
+
// return compressedVideo;
|
|
411
|
+
// } catch (error) {
|
|
412
|
+
// console.error("Video compression error:", error);
|
|
413
|
+
// return videoUri; // Return original if compression fails
|
|
414
|
+
// }
|
|
415
|
+
// };
|
|
416
|
+
// // CAMERA HANDLER with permission check and compression
|
|
417
|
+
// const handleCamera = async () => {
|
|
418
|
+
// await cameraPermissions(async (granted: boolean) => {
|
|
419
|
+
// if (!granted) return;
|
|
420
|
+
// if (mediaType === "photo") {
|
|
421
|
+
// try {
|
|
422
|
+
// const response = await ImageCropPicker.openCamera({
|
|
423
|
+
// mediaType: "photo",
|
|
424
|
+
// });
|
|
425
|
+
// if (isMultiSelect) {
|
|
426
|
+
// // Single capture for multi-select mode
|
|
427
|
+
// const compressedPath = await compressImage(response.path);
|
|
428
|
+
// onComplete([{ ...response, path: compressedPath }]);
|
|
429
|
+
// } else {
|
|
430
|
+
// // Crop and compress single image
|
|
431
|
+
// const cropped = await ImageCropPicker.openCropper({
|
|
432
|
+
// path: response?.path,
|
|
433
|
+
// width: response?.width,
|
|
434
|
+
// height: response?.height,
|
|
435
|
+
// mediaType: "photo",
|
|
436
|
+
// freeStyleCropEnabled: true,
|
|
437
|
+
// });
|
|
438
|
+
// const compressedPath = await compressImage(cropped.path);
|
|
439
|
+
// onComplete({ ...cropped, path: compressedPath });
|
|
440
|
+
// }
|
|
441
|
+
// } catch (error) {
|
|
442
|
+
// console.log("Camera cancelled or error:", error);
|
|
443
|
+
// }
|
|
444
|
+
// } else {
|
|
445
|
+
// // VIDEO CAPTURE - check microphone permission first
|
|
446
|
+
// const micPermission = await checkMicroPhonePermission();
|
|
447
|
+
// if (!micPermission) {
|
|
448
|
+
// Alert.alert(
|
|
449
|
+
// "Microphone Permission Required",
|
|
450
|
+
// "Please enable microphone access to record videos."
|
|
451
|
+
// );
|
|
452
|
+
// return;
|
|
453
|
+
// }
|
|
454
|
+
// launchCamera(
|
|
455
|
+
// {
|
|
456
|
+
// mediaType: "video",
|
|
457
|
+
// durationLimit: 60,
|
|
458
|
+
// videoQuality: "high",
|
|
459
|
+
// },
|
|
460
|
+
// async (response) => {
|
|
461
|
+
// if (response?.assets?.length) {
|
|
462
|
+
// const videoUri = response.assets[0]?.uri;
|
|
463
|
+
// const compressedPath = await compressVideo(videoUri);
|
|
464
|
+
// onComplete({
|
|
465
|
+
// path: compressedPath,
|
|
466
|
+
// duration: response.assets[0]?.duration,
|
|
467
|
+
// });
|
|
468
|
+
// }
|
|
469
|
+
// }
|
|
470
|
+
// );
|
|
471
|
+
// }
|
|
472
|
+
// });
|
|
473
|
+
// };
|
|
474
|
+
// // GALLERY HANDLER with permission check and compression
|
|
475
|
+
// const handleGallery = async () => {
|
|
476
|
+
// await galleryPermissions(async (granted: boolean) => {
|
|
477
|
+
// if (!granted) return;
|
|
478
|
+
// if (mediaType === "photo") {
|
|
479
|
+
// try {
|
|
480
|
+
// if (isMultiSelect) {
|
|
481
|
+
// const images = await ImageCropPicker.openPicker({
|
|
482
|
+
// mediaType: "photo",
|
|
483
|
+
// multiple: true,
|
|
484
|
+
// maxFiles: 5,
|
|
485
|
+
// });
|
|
486
|
+
// if (images.length > 5) {
|
|
487
|
+
// Alert.alert(
|
|
488
|
+
// "Limit Exceeded",
|
|
489
|
+
// "You can only select up to 5 images."
|
|
490
|
+
// );
|
|
491
|
+
// return;
|
|
492
|
+
// }
|
|
493
|
+
// // Compress multiple images
|
|
494
|
+
// const compressedImages = await Promise.all(
|
|
495
|
+
// images.map(async (img) => ({
|
|
496
|
+
// ...img,
|
|
497
|
+
// path: await compressImage(img.path),
|
|
498
|
+
// }))
|
|
499
|
+
// );
|
|
500
|
+
// onComplete(compressedImages);
|
|
501
|
+
// } else {
|
|
502
|
+
// // Single image with crop
|
|
503
|
+
// const response = await ImageCropPicker.openPicker({
|
|
504
|
+
// mediaType: "photo",
|
|
505
|
+
// });
|
|
506
|
+
// const cropped = await ImageCropPicker.openCropper({
|
|
507
|
+
// path: response?.path,
|
|
508
|
+
// width: response?.width,
|
|
509
|
+
// height: response?.height,
|
|
510
|
+
// mediaType: "photo",
|
|
511
|
+
// freeStyleCropEnabled: true,
|
|
512
|
+
// });
|
|
513
|
+
// const compressedPath = await compressImage(cropped.path);
|
|
514
|
+
// onComplete({ ...cropped, path: compressedPath });
|
|
515
|
+
// }
|
|
516
|
+
// } catch (error) {
|
|
517
|
+
// console.log("Gallery cancelled or error:", error);
|
|
518
|
+
// }
|
|
519
|
+
// } else {
|
|
520
|
+
// // VIDEO FROM GALLERY
|
|
521
|
+
// launchImageLibrary(
|
|
522
|
+
// {
|
|
523
|
+
// mediaType: "video",
|
|
524
|
+
// assetRepresentationMode: "current",
|
|
525
|
+
// },
|
|
526
|
+
// async (result) => {
|
|
527
|
+
// if (result?.assets?.length) {
|
|
528
|
+
// const videoUri = result.assets[0]?.uri;
|
|
529
|
+
// const compressedPath = await compressVideo(videoUri);
|
|
530
|
+
// onComplete({
|
|
531
|
+
// path: compressedPath,
|
|
532
|
+
// duration: result.assets[0]?.duration,
|
|
533
|
+
// });
|
|
534
|
+
// }
|
|
535
|
+
// }
|
|
536
|
+
// );
|
|
537
|
+
// }
|
|
538
|
+
// });
|
|
539
|
+
// };
|
|
540
|
+
// return (
|
|
541
|
+
// <BottomSheet visible={visible} onClose={onClose} height={230}>
|
|
542
|
+
// <View style={styles.container}>
|
|
543
|
+
// {/* Camera */}
|
|
544
|
+
// <TouchableOpacity style={styles.row} onPress={handleCamera}>
|
|
545
|
+
// <Image source={Images.video_icon} style={styles.icon} />
|
|
546
|
+
// <Text style={styles.text}>Camera</Text>
|
|
547
|
+
// </TouchableOpacity>
|
|
548
|
+
// <Dividers small />
|
|
549
|
+
// {/* Gallery */}
|
|
550
|
+
// <TouchableOpacity style={styles.row} onPress={handleGallery}>
|
|
551
|
+
// <Image source={Images.image_icon} style={styles.icon} />
|
|
552
|
+
// <Text style={styles.text}>Gallery</Text>
|
|
553
|
+
// </TouchableOpacity>
|
|
554
|
+
// <Dividers small />
|
|
555
|
+
// {/* Cancel */}
|
|
556
|
+
// <TouchableOpacity style={styles.row} onPress={onClose}>
|
|
557
|
+
// <Image source={Images.cancel} style={styles.icon} />
|
|
558
|
+
// <Text style={styles.text}>Cancel</Text>
|
|
559
|
+
// </TouchableOpacity>
|
|
560
|
+
// </View>
|
|
561
|
+
// </BottomSheet>
|
|
562
|
+
// );
|
|
563
|
+
// };
|
|
564
|
+
// export default ImagePicker;
|
|
565
|
+
// const styles = StyleSheet.create({
|
|
566
|
+
// container: { flex: 1, padding: 16 },
|
|
567
|
+
// row: {
|
|
568
|
+
// flexDirection: "row",
|
|
569
|
+
// alignItems: "center",
|
|
570
|
+
// },
|
|
571
|
+
// text: { ...Typography.style.standardU(), color: Colors.white },
|
|
572
|
+
// icon: {
|
|
573
|
+
// width: Scale.moderateScale(20),
|
|
574
|
+
// height: Scale.moderateScale(20),
|
|
575
|
+
// marginRight: 10,
|
|
576
|
+
// tintColor: Colors.white,
|
|
577
|
+
// },
|
|
578
|
+
// });
|
|
323
579
|
import React, { useCallback } from "react";
|
|
324
|
-
import { View, Text, TouchableOpacity, StyleSheet, Image,
|
|
325
|
-
import { BottomSheet, Dividers } from "../index";
|
|
580
|
+
import { View, Text, TouchableOpacity, StyleSheet, Image, } from "react-native";
|
|
581
|
+
import { BottomSheet, Dividers } from "../index"; // ✅ YOUR ORIGINAL BOTTOMSHEET
|
|
326
582
|
import { launchCamera, launchImageLibrary } from "react-native-image-picker";
|
|
327
583
|
import ImageCropPicker from "react-native-image-crop-picker";
|
|
328
584
|
import { Image as ImageCompressor, Video as VideoCompressor, } from "react-native-compressor";
|
|
329
|
-
|
|
330
|
-
import { Colors, Images, Scale, Typography } from "../../styles";
|
|
331
|
-
// Import your permission utilities
|
|
585
|
+
// Permission functions (user can override)
|
|
332
586
|
import { cameraPermissions, galleryPermissions, checkMicroPhonePermission, } from "../../utils/permissions";
|
|
333
|
-
const ImagePicker = ({
|
|
334
|
-
|
|
587
|
+
const ImagePicker = ({ visible, onClose, mediaType, isMultiSelect = false, onSuccess, labels = {
|
|
588
|
+
camera: "Camera",
|
|
589
|
+
gallery: "Gallery",
|
|
590
|
+
cancel: "Cancel",
|
|
591
|
+
}, icons = {
|
|
592
|
+
camera: null,
|
|
593
|
+
gallery: null,
|
|
594
|
+
cancel: null,
|
|
595
|
+
}, styles: customStyle = {}, permissionHandlers = {
|
|
596
|
+
camera: cameraPermissions,
|
|
597
|
+
gallery: galleryPermissions,
|
|
598
|
+
microphone: checkMicroPhonePermission,
|
|
599
|
+
}, pickerOptions = {
|
|
600
|
+
camera: {},
|
|
601
|
+
gallery: {},
|
|
602
|
+
cropper: {},
|
|
603
|
+
}, enableCompression = true, imageCompressionOptions = { maxWidth: 1080, quality: 0.7 }, videoCompressionOptions = { compressionMethod: "auto" }, }) => {
|
|
604
|
+
const s = { ...defaultStyles, ...customStyle };
|
|
335
605
|
const onComplete = useCallback((data) => {
|
|
336
606
|
onSuccess(data);
|
|
337
607
|
onClose();
|
|
338
608
|
}, [onSuccess, onClose]);
|
|
339
|
-
|
|
340
|
-
const compressImage = async (imagePath) => {
|
|
609
|
+
const compressImage = async (path) => {
|
|
341
610
|
if (!enableCompression)
|
|
342
|
-
return
|
|
611
|
+
return path;
|
|
343
612
|
try {
|
|
344
|
-
|
|
345
|
-
maxWidth: imageCompressionOptions.maxWidth,
|
|
346
|
-
quality: imageCompressionOptions.quality,
|
|
347
|
-
});
|
|
348
|
-
// Log compressed size (optional)
|
|
349
|
-
const stats = await RNFS.stat(compressedImage.replace("file://", ""));
|
|
350
|
-
const sizeInMB = stats.size / (1024 * 1024);
|
|
351
|
-
console.log("Compressed Image Size (MB):", sizeInMB);
|
|
352
|
-
return compressedImage;
|
|
613
|
+
return await ImageCompressor.compress(path, imageCompressionOptions);
|
|
353
614
|
}
|
|
354
|
-
catch
|
|
355
|
-
|
|
356
|
-
return imagePath; // Return original if compression fails
|
|
615
|
+
catch {
|
|
616
|
+
return path;
|
|
357
617
|
}
|
|
358
618
|
};
|
|
359
|
-
|
|
360
|
-
const compressVideo = async (videoUri) => {
|
|
619
|
+
const compressVideo = async (uri) => {
|
|
361
620
|
if (!enableCompression)
|
|
362
|
-
return
|
|
621
|
+
return uri;
|
|
363
622
|
try {
|
|
364
|
-
|
|
365
|
-
compressionMethod: videoCompressionOptions.compressionMethod,
|
|
366
|
-
});
|
|
367
|
-
// Log compressed size (optional)
|
|
368
|
-
const stats = await RNFS.stat(compressedVideo.replace("file://", ""));
|
|
369
|
-
const sizeInMB = stats.size / (1024 * 1024);
|
|
370
|
-
console.log("Compressed Video Size (MB):", sizeInMB);
|
|
371
|
-
return compressedVideo;
|
|
623
|
+
return await VideoCompressor.compress(uri, videoCompressionOptions);
|
|
372
624
|
}
|
|
373
|
-
catch
|
|
374
|
-
|
|
375
|
-
return videoUri; // Return original if compression fails
|
|
625
|
+
catch {
|
|
626
|
+
return uri;
|
|
376
627
|
}
|
|
377
628
|
};
|
|
378
|
-
// CAMERA HANDLER with permission check and compression
|
|
379
629
|
const handleCamera = async () => {
|
|
380
|
-
await
|
|
630
|
+
await permissionHandlers.camera?.(async (granted) => {
|
|
381
631
|
if (!granted)
|
|
382
632
|
return;
|
|
383
633
|
if (mediaType === "photo") {
|
|
384
634
|
try {
|
|
385
|
-
const
|
|
635
|
+
const img = await ImageCropPicker.openCamera({
|
|
386
636
|
mediaType: "photo",
|
|
637
|
+
...pickerOptions.camera,
|
|
387
638
|
});
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
}
|
|
393
|
-
else {
|
|
394
|
-
// Crop and compress single image
|
|
395
|
-
const cropped = await ImageCropPicker.openCropper({
|
|
396
|
-
path: response?.path,
|
|
397
|
-
width: response?.width,
|
|
398
|
-
height: response?.height,
|
|
639
|
+
let cropped = img;
|
|
640
|
+
if (!isMultiSelect) {
|
|
641
|
+
cropped = await ImageCropPicker.openCropper({
|
|
642
|
+
path: img.path,
|
|
399
643
|
mediaType: "photo",
|
|
400
644
|
freeStyleCropEnabled: true,
|
|
645
|
+
...pickerOptions.cropper,
|
|
401
646
|
});
|
|
402
|
-
const compressedPath = await compressImage(cropped.path);
|
|
403
|
-
onComplete({ ...cropped, path: compressedPath });
|
|
404
647
|
}
|
|
648
|
+
const compressed = await compressImage(cropped.path);
|
|
649
|
+
onComplete({ ...cropped, path: compressed });
|
|
405
650
|
}
|
|
406
|
-
catch
|
|
407
|
-
console.log("Camera cancelled or error:", error);
|
|
408
|
-
}
|
|
651
|
+
catch { }
|
|
409
652
|
}
|
|
410
653
|
else {
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
if (!micPermission) {
|
|
414
|
-
Alert.alert("Microphone Permission Required", "Please enable microphone access to record videos.");
|
|
654
|
+
const micGranted = await permissionHandlers.microphone?.();
|
|
655
|
+
if (!micGranted)
|
|
415
656
|
return;
|
|
416
|
-
}
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
videoQuality: "high",
|
|
421
|
-
}, async (response) => {
|
|
422
|
-
if (response?.assets?.length) {
|
|
423
|
-
const videoUri = response.assets[0]?.uri;
|
|
424
|
-
const compressedPath = await compressVideo(videoUri);
|
|
425
|
-
onComplete({
|
|
426
|
-
path: compressedPath,
|
|
427
|
-
duration: response.assets[0]?.duration,
|
|
428
|
-
});
|
|
657
|
+
launchCamera({ mediaType: "video", ...pickerOptions.camera }, async (res) => {
|
|
658
|
+
if (res?.assets?.length) {
|
|
659
|
+
const compressed = await compressVideo(res.assets[0].uri);
|
|
660
|
+
onComplete({ path: compressed });
|
|
429
661
|
}
|
|
430
662
|
});
|
|
431
663
|
}
|
|
432
664
|
});
|
|
433
665
|
};
|
|
434
|
-
// GALLERY HANDLER with permission check and compression
|
|
435
666
|
const handleGallery = async () => {
|
|
436
|
-
await
|
|
667
|
+
await permissionHandlers.gallery?.(async (granted) => {
|
|
437
668
|
if (!granted)
|
|
438
669
|
return;
|
|
439
670
|
if (mediaType === "photo") {
|
|
440
671
|
try {
|
|
441
|
-
|
|
442
|
-
|
|
672
|
+
let result = await ImageCropPicker.openPicker({
|
|
673
|
+
mediaType: "photo",
|
|
674
|
+
multiple: isMultiSelect,
|
|
675
|
+
...pickerOptions.gallery,
|
|
676
|
+
});
|
|
677
|
+
if (!isMultiSelect) {
|
|
678
|
+
result = await ImageCropPicker.openCropper({
|
|
679
|
+
path: result.path,
|
|
443
680
|
mediaType: "photo",
|
|
444
|
-
|
|
445
|
-
|
|
681
|
+
freeStyleCropEnabled: true,
|
|
682
|
+
...pickerOptions.cropper,
|
|
446
683
|
});
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
}
|
|
451
|
-
// Compress multiple images
|
|
452
|
-
const compressedImages = await Promise.all(images.map(async (img) => ({
|
|
684
|
+
}
|
|
685
|
+
if (isMultiSelect) {
|
|
686
|
+
const compressed = await Promise.all(result.map(async (img) => ({
|
|
453
687
|
...img,
|
|
454
688
|
path: await compressImage(img.path),
|
|
455
689
|
})));
|
|
456
|
-
onComplete(
|
|
690
|
+
onComplete(compressed);
|
|
457
691
|
}
|
|
458
692
|
else {
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
mediaType: "photo",
|
|
462
|
-
});
|
|
463
|
-
const cropped = await ImageCropPicker.openCropper({
|
|
464
|
-
path: response?.path,
|
|
465
|
-
width: response?.width,
|
|
466
|
-
height: response?.height,
|
|
467
|
-
mediaType: "photo",
|
|
468
|
-
freeStyleCropEnabled: true,
|
|
469
|
-
});
|
|
470
|
-
const compressedPath = await compressImage(cropped.path);
|
|
471
|
-
onComplete({ ...cropped, path: compressedPath });
|
|
693
|
+
const compressed = await compressImage(result.path);
|
|
694
|
+
onComplete({ ...result, path: compressed });
|
|
472
695
|
}
|
|
473
696
|
}
|
|
474
|
-
catch
|
|
475
|
-
console.log("Gallery cancelled or error:", error);
|
|
476
|
-
}
|
|
697
|
+
catch { }
|
|
477
698
|
}
|
|
478
699
|
else {
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
}, async (result) => {
|
|
484
|
-
if (result?.assets?.length) {
|
|
485
|
-
const videoUri = result.assets[0]?.uri;
|
|
486
|
-
const compressedPath = await compressVideo(videoUri);
|
|
487
|
-
onComplete({
|
|
488
|
-
path: compressedPath,
|
|
489
|
-
duration: result.assets[0]?.duration,
|
|
490
|
-
});
|
|
700
|
+
launchImageLibrary({ mediaType: "video", ...pickerOptions.gallery }, async (res) => {
|
|
701
|
+
if (res?.assets?.length) {
|
|
702
|
+
const compressed = await compressVideo(res.assets[0].uri);
|
|
703
|
+
onComplete({ path: compressed });
|
|
491
704
|
}
|
|
492
705
|
});
|
|
493
706
|
}
|
|
494
707
|
});
|
|
495
708
|
};
|
|
496
|
-
return (React.createElement(BottomSheet, { visible: visible, onClose: onClose, height: 230 },
|
|
497
|
-
React.createElement(View, { style:
|
|
498
|
-
React.createElement(TouchableOpacity, { style:
|
|
499
|
-
React.createElement(Image, { source:
|
|
500
|
-
React.createElement(Text, { style:
|
|
709
|
+
return (React.createElement(BottomSheet, { visible: visible, onClose: onClose, height: 230, sheetBackground: customStyle?.backgroundColor },
|
|
710
|
+
React.createElement(View, { style: s.container },
|
|
711
|
+
React.createElement(TouchableOpacity, { style: s.row, onPress: handleCamera },
|
|
712
|
+
icons.camera && React.createElement(Image, { source: icons.camera, style: s.icon }),
|
|
713
|
+
React.createElement(Text, { style: s.text }, labels.camera)),
|
|
501
714
|
React.createElement(Dividers, { small: true }),
|
|
502
|
-
React.createElement(TouchableOpacity, { style:
|
|
503
|
-
React.createElement(Image, { source:
|
|
504
|
-
React.createElement(Text, { style:
|
|
715
|
+
React.createElement(TouchableOpacity, { style: s.row, onPress: handleGallery },
|
|
716
|
+
icons.gallery && React.createElement(Image, { source: icons.gallery, style: s.icon }),
|
|
717
|
+
React.createElement(Text, { style: s.text }, labels.gallery)),
|
|
505
718
|
React.createElement(Dividers, { small: true }),
|
|
506
|
-
React.createElement(TouchableOpacity, { style:
|
|
507
|
-
React.createElement(Image, { source:
|
|
508
|
-
React.createElement(Text, { style:
|
|
719
|
+
React.createElement(TouchableOpacity, { style: s.row, onPress: onClose },
|
|
720
|
+
icons.cancel && React.createElement(Image, { source: icons.cancel, style: s.icon }),
|
|
721
|
+
React.createElement(Text, { style: s.text }, labels.cancel)))));
|
|
509
722
|
};
|
|
510
723
|
export default ImagePicker;
|
|
511
|
-
const
|
|
512
|
-
container: {
|
|
724
|
+
const defaultStyles = StyleSheet.create({
|
|
725
|
+
container: {
|
|
726
|
+
flex: 1,
|
|
727
|
+
padding: 16,
|
|
728
|
+
},
|
|
513
729
|
row: {
|
|
514
730
|
flexDirection: "row",
|
|
515
731
|
alignItems: "center",
|
|
732
|
+
paddingVertical: 10,
|
|
733
|
+
},
|
|
734
|
+
text: {
|
|
735
|
+
fontSize: 16,
|
|
736
|
+
color: "white",
|
|
516
737
|
},
|
|
517
|
-
text: { ...Typography.style.standardU(), color: Colors.white },
|
|
518
738
|
icon: {
|
|
519
|
-
width:
|
|
520
|
-
height:
|
|
739
|
+
width: 20,
|
|
740
|
+
height: 20,
|
|
521
741
|
marginRight: 10,
|
|
522
|
-
tintColor:
|
|
742
|
+
tintColor: "white",
|
|
523
743
|
},
|
|
524
744
|
});
|