Skip to content

Commit 0b9f18a

Browse files
authored
fix: multiple image upload issue using native image picker and generic improvements for upload (#2638)
* fix: multiple image upload issue using native image picker and generic improvements for upload * fix: respect file size config for clicked image * fix: remove console.log * fix: add useCallback to a couple of functions * fix: broken tests
1 parent 08fc71b commit 0b9f18a

File tree

10 files changed

+211
-142
lines changed

10 files changed

+211
-142
lines changed

package/expo-package/src/optionalDependencies/takePhoto.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ export const takePhoto = ImagePicker
7474

7575
return {
7676
cancelled: false,
77+
size: photo.fileSize,
7778
source: 'camera',
7879
uri: photo.uri,
7980
...size,

package/native-package/src/optionalDependencies/pickImage.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@ try {
1010
export const pickImage = ImagePicker
1111
? async () => {
1212
try {
13-
const result = await ImagePicker.launchImageLibrary({ mediaType: 'mixed' });
13+
const result = await ImagePicker.launchImageLibrary({
14+
mediaType: 'mixed',
15+
});
1416
const canceled = result.didCancel;
1517
const errorCode = result.errorCode;
1618

@@ -20,7 +22,7 @@ export const pickImage = ImagePicker
2022
if (!canceled) {
2123
const assets = result.assets.map((asset) => ({
2224
...asset,
23-
duration: asset.duration * 1000, // in milliseconds
25+
duration: asset.duration ? asset.duration * 1000 : undefined, // in milliseconds
2426
name: asset.fileName,
2527
size: asset.fileSize,
2628
source: 'picker',

package/native-package/src/optionalDependencies/takePhoto.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ export const takePhoto = ImagePicker
6060
}
6161
return {
6262
cancelled: false,
63+
size: photo.size,
6364
source: 'camera',
6465
uri: photo.path,
6566
...size,

package/src/components/AttachmentPicker/components/AttachmentPickerItem.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { Alert, ImageBackground, Platform, StyleSheet, Text, View } from 'react-
55
import { TouchableOpacity } from '@gorhom/bottom-sheet';
66
import { lookup } from 'mime-types';
77

8-
import type { AttachmentPickerContextValue } from '../../../contexts/attachmentPickerContext/AttachmentPickerContext';
8+
import { AttachmentPickerContextValue } from '../../../contexts/attachmentPickerContext/AttachmentPickerContext';
99
import { useTheme } from '../../../contexts/themeContext/ThemeContext';
1010
import { useViewport } from '../../../hooks/useViewport';
1111
import { Recorder } from '../../../icons';
@@ -23,7 +23,6 @@ type AttachmentPickerItemType = Pick<
2323
selected: boolean;
2424
numberOfAttachmentPickerImageColumns?: number;
2525
};
26-
2726
type AttachmentImageProps = Omit<AttachmentPickerItemType, 'setSelectedFiles' | 'selectedFiles'>;
2827

2928
type AttachmentVideoProps = Omit<AttachmentPickerItemType, 'setSelectedImages' | 'selectedImages'>;

package/src/components/MessageInput/FileUploadPreview.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ const styles = StyleSheet.create({
3434
dismiss: {
3535
borderRadius: 24,
3636
height: 24,
37+
marginRight: 4,
3738
position: 'absolute',
3839
right: 8,
3940
top: 8,

package/src/components/MessageInput/MessageInput.tsx

Lines changed: 65 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ import {
4949
useTranslationContext,
5050
} from '../../contexts/translationContext/TranslationContext';
5151

52-
import { triggerHaptic } from '../../native';
52+
import { isImageMediaLibraryAvailable, triggerHaptic } from '../../native';
5353
import type { Asset, DefaultStreamChatGenerics } from '../../types/types';
5454
import { AutoCompleteInput } from '../AutoCompleteInput/AutoCompleteInput';
5555

@@ -118,7 +118,6 @@ type MessageInputPropsWithContext<
118118
| 'FileUploadPreview'
119119
| 'fileUploads'
120120
| 'giphyActive'
121-
| 'hasImagePicker'
122121
| 'ImageUploadPreview'
123122
| 'imageUploads'
124123
| 'Input'
@@ -185,7 +184,6 @@ const MessageInputWithContext = <
185184
FileUploadPreview,
186185
fileUploads,
187186
giphyActive,
188-
hasImagePicker,
189187
ImageUploadPreview,
190188
imageUploads,
191189
Input,
@@ -349,46 +347,71 @@ const MessageInputWithContext = <
349347
imagesToRemove.forEach((image) => removeImage(image.id));
350348
};
351349

350+
const uploadFilesHandler = async () => {
351+
const fileToUpload = selectedFiles.find((selectedFile) => {
352+
const uploadedFile = fileUploads.find(
353+
(fileUpload) =>
354+
fileUpload.file.uri === selectedFile.uri || fileUpload.url === selectedFile.uri,
355+
);
356+
return !uploadedFile;
357+
});
358+
if (fileToUpload) await uploadNewFile(fileToUpload);
359+
};
360+
361+
const removeFilesHandler = () => {
362+
const filesToRemove = fileUploads.filter(
363+
(fileUpload) =>
364+
!selectedFiles.find(
365+
(selectedFile) =>
366+
selectedFile.uri === fileUpload.file.uri || selectedFile.uri === fileUpload.url,
367+
),
368+
);
369+
filesToRemove.forEach((file) => removeFile(file.id));
370+
};
371+
372+
/**
373+
* When a user selects or deselects an image in the image picker using media library.
374+
*/
352375
useEffect(() => {
353-
if (imagesForInput) {
354-
if (selectedImagesLength > imageUploadsLength) {
355-
/** User selected an image in bottom sheet attachment picker */
356-
uploadImagesHandler();
357-
} else {
358-
/** User de-selected an image in bottom sheet attachment picker */
359-
removeImagesHandler();
376+
const uploadOrRemoveImage = async () => {
377+
if (imagesForInput) {
378+
if (selectedImagesLength > imageUploadsLength) {
379+
/** User selected an image in bottom sheet attachment picker */
380+
await uploadImagesHandler();
381+
} else {
382+
/** User de-selected an image in bottom sheet attachment picker */
383+
removeImagesHandler();
384+
}
360385
}
361-
}
386+
};
387+
// If image picker is not available, don't do anything
388+
if (!isImageMediaLibraryAvailable()) return;
389+
uploadOrRemoveImage();
362390
// eslint-disable-next-line react-hooks/exhaustive-deps
363391
}, [selectedImagesLength]);
364392

393+
/**
394+
* When a user selects or deselects a video in the image picker using media library.
395+
*/
365396
useEffect(() => {
366-
if (selectedFilesLength > fileUploadsLength) {
367-
/** User selected a video in bottom sheet attachment picker */
368-
const fileToUpload = selectedFiles.find((selectedFile) => {
369-
const uploadedFile = fileUploads.find(
370-
(fileUpload) =>
371-
fileUpload.file.uri === selectedFile.uri || fileUpload.url === selectedFile.uri,
372-
);
373-
return !uploadedFile;
374-
});
375-
if (fileToUpload) uploadNewFile(fileToUpload);
376-
} else {
377-
/** User de-selected a video in bottom sheet attachment picker */
378-
const filesToRemove = fileUploads.filter(
379-
(fileUpload) =>
380-
!selectedFiles.find(
381-
(selectedFile) =>
382-
selectedFile.uri === fileUpload.file.uri || selectedFile.uri === fileUpload.url,
383-
),
384-
);
385-
filesToRemove.forEach((file) => removeFile(file.id));
386-
}
397+
const uploadOrRemoveFile = async () => {
398+
if (selectedFilesLength > fileUploadsLength) {
399+
/** User selected a video in bottom sheet attachment picker */
400+
await uploadFilesHandler();
401+
} else {
402+
/** User de-selected a video in bottom sheet attachment picker */
403+
removeFilesHandler();
404+
}
405+
};
406+
uploadOrRemoveFile();
387407
// eslint-disable-next-line react-hooks/exhaustive-deps
388408
}, [selectedFilesLength]);
389409

410+
/**
411+
* This is for image attachments selected from attachment picker.
412+
*/
390413
useEffect(() => {
391-
if (imagesForInput && hasImagePicker) {
414+
if (imagesForInput && isImageMediaLibraryAvailable()) {
392415
if (imageUploadsLength < selectedImagesLength) {
393416
// /** User removed some image from seleted images within ImageUploadPreview. */
394417
const updatedSelectedImages = selectedImages.filter((selectedImage) => {
@@ -401,9 +424,7 @@ const MessageInputWithContext = <
401424
setSelectedImages(updatedSelectedImages);
402425
} else if (imageUploadsLength > selectedImagesLength) {
403426
/**
404-
* User is editing some message which contains image attachments OR
405-
* image attachment is added from custom image picker (other than the default bottomsheet image picker)
406-
* using `uploadNewImage` function from `MessageInputContext`.
427+
* User is editing some message which contains image attachments.
407428
**/
408429
setSelectedImages(
409430
imageUploads
@@ -418,10 +439,13 @@ const MessageInputWithContext = <
418439
}
419440
}
420441
// eslint-disable-next-line react-hooks/exhaustive-deps
421-
}, [imageUploadsLength, hasImagePicker]);
442+
}, [imageUploadsLength]);
422443

444+
/**
445+
* This is for video attachments selected from attachment picker.
446+
*/
423447
useEffect(() => {
424-
if (hasImagePicker) {
448+
if (isImageMediaLibraryAvailable()) {
425449
if (fileUploadsLength < selectedFilesLength) {
426450
/** User removed some video from seleted files within ImageUploadPreview. */
427451
const updatedSelectedFiles = selectedFiles.filter((selectedFile) => {
@@ -434,9 +458,7 @@ const MessageInputWithContext = <
434458
setSelectedFiles(updatedSelectedFiles);
435459
} else if (fileUploadsLength > selectedFilesLength) {
436460
/**
437-
* User is editing some message which contains video attachments OR
438-
* video attachment is added from custom image picker (other than the default bottom-sheet image picker)
439-
* using `uploadNewFile` function from `MessageInputContext`.
461+
* User is editing some message which contains video attachments.
440462
**/
441463
setSelectedFiles(
442464
fileUploads.map((fileUpload) => ({
@@ -450,9 +472,10 @@ const MessageInputWithContext = <
450472
}
451473
}
452474
// eslint-disable-next-line react-hooks/exhaustive-deps
453-
}, [fileUploadsLength, hasImagePicker]);
475+
}, [fileUploadsLength]);
454476

455477
const editingExists = !!editing;
478+
456479
useEffect(() => {
457480
if (editing && inputBoxRef.current) {
458481
inputBoxRef.current.focus();
@@ -1036,7 +1059,6 @@ export const MessageInput = <
10361059
FileUploadPreview,
10371060
fileUploads,
10381061
giphyActive,
1039-
hasImagePicker,
10401062
ImageUploadPreview,
10411063
imageUploads,
10421064
Input,
@@ -1117,7 +1139,6 @@ export const MessageInput = <
11171139
FileUploadPreview,
11181140
fileUploads,
11191141
giphyActive,
1120-
hasImagePicker,
11211142
ImageUploadPreview,
11221143
imageUploads,
11231144
Input,

0 commit comments

Comments
 (0)