Skip to content

Commit

Permalink
fix: multiple image upload issue using native image picker and generi…
Browse files Browse the repository at this point in the history
…c 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
  • Loading branch information
khushal87 authored Aug 30, 2024
1 parent 08fc71b commit 0b9f18a
Show file tree
Hide file tree
Showing 10 changed files with 211 additions and 142 deletions.
1 change: 1 addition & 0 deletions package/expo-package/src/optionalDependencies/takePhoto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ export const takePhoto = ImagePicker

return {
cancelled: false,
size: photo.fileSize,
source: 'camera',
uri: photo.uri,
...size,
Expand Down
6 changes: 4 additions & 2 deletions package/native-package/src/optionalDependencies/pickImage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ try {
export const pickImage = ImagePicker
? async () => {
try {
const result = await ImagePicker.launchImageLibrary({ mediaType: 'mixed' });
const result = await ImagePicker.launchImageLibrary({
mediaType: 'mixed',
});
const canceled = result.didCancel;
const errorCode = result.errorCode;

Expand All @@ -20,7 +22,7 @@ export const pickImage = ImagePicker
if (!canceled) {
const assets = result.assets.map((asset) => ({
...asset,
duration: asset.duration * 1000, // in milliseconds
duration: asset.duration ? asset.duration * 1000 : undefined, // in milliseconds
name: asset.fileName,
size: asset.fileSize,
source: 'picker',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ export const takePhoto = ImagePicker
}
return {
cancelled: false,
size: photo.size,
source: 'camera',
uri: photo.path,
...size,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { Alert, ImageBackground, Platform, StyleSheet, Text, View } from 'react-
import { TouchableOpacity } from '@gorhom/bottom-sheet';
import { lookup } from 'mime-types';

import type { AttachmentPickerContextValue } from '../../../contexts/attachmentPickerContext/AttachmentPickerContext';
import { AttachmentPickerContextValue } from '../../../contexts/attachmentPickerContext/AttachmentPickerContext';
import { useTheme } from '../../../contexts/themeContext/ThemeContext';
import { useViewport } from '../../../hooks/useViewport';
import { Recorder } from '../../../icons';
Expand All @@ -23,7 +23,6 @@ type AttachmentPickerItemType = Pick<
selected: boolean;
numberOfAttachmentPickerImageColumns?: number;
};

type AttachmentImageProps = Omit<AttachmentPickerItemType, 'setSelectedFiles' | 'selectedFiles'>;

type AttachmentVideoProps = Omit<AttachmentPickerItemType, 'setSelectedImages' | 'selectedImages'>;
Expand Down
1 change: 1 addition & 0 deletions package/src/components/MessageInput/FileUploadPreview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ const styles = StyleSheet.create({
dismiss: {
borderRadius: 24,
height: 24,
marginRight: 4,
position: 'absolute',
right: 8,
top: 8,
Expand Down
109 changes: 65 additions & 44 deletions package/src/components/MessageInput/MessageInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ import {
useTranslationContext,
} from '../../contexts/translationContext/TranslationContext';

import { triggerHaptic } from '../../native';
import { isImageMediaLibraryAvailable, triggerHaptic } from '../../native';
import type { Asset, DefaultStreamChatGenerics } from '../../types/types';
import { AutoCompleteInput } from '../AutoCompleteInput/AutoCompleteInput';

Expand Down Expand Up @@ -118,7 +118,6 @@ type MessageInputPropsWithContext<
| 'FileUploadPreview'
| 'fileUploads'
| 'giphyActive'
| 'hasImagePicker'
| 'ImageUploadPreview'
| 'imageUploads'
| 'Input'
Expand Down Expand Up @@ -185,7 +184,6 @@ const MessageInputWithContext = <
FileUploadPreview,
fileUploads,
giphyActive,
hasImagePicker,
ImageUploadPreview,
imageUploads,
Input,
Expand Down Expand Up @@ -349,46 +347,71 @@ const MessageInputWithContext = <
imagesToRemove.forEach((image) => removeImage(image.id));
};

const uploadFilesHandler = async () => {
const fileToUpload = selectedFiles.find((selectedFile) => {
const uploadedFile = fileUploads.find(
(fileUpload) =>
fileUpload.file.uri === selectedFile.uri || fileUpload.url === selectedFile.uri,
);
return !uploadedFile;
});
if (fileToUpload) await uploadNewFile(fileToUpload);
};

const removeFilesHandler = () => {
const filesToRemove = fileUploads.filter(
(fileUpload) =>
!selectedFiles.find(
(selectedFile) =>
selectedFile.uri === fileUpload.file.uri || selectedFile.uri === fileUpload.url,
),
);
filesToRemove.forEach((file) => removeFile(file.id));
};

/**
* When a user selects or deselects an image in the image picker using media library.
*/
useEffect(() => {
if (imagesForInput) {
if (selectedImagesLength > imageUploadsLength) {
/** User selected an image in bottom sheet attachment picker */
uploadImagesHandler();
} else {
/** User de-selected an image in bottom sheet attachment picker */
removeImagesHandler();
const uploadOrRemoveImage = async () => {
if (imagesForInput) {
if (selectedImagesLength > imageUploadsLength) {
/** User selected an image in bottom sheet attachment picker */
await uploadImagesHandler();
} else {
/** User de-selected an image in bottom sheet attachment picker */
removeImagesHandler();
}
}
}
};
// If image picker is not available, don't do anything
if (!isImageMediaLibraryAvailable()) return;
uploadOrRemoveImage();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [selectedImagesLength]);

/**
* When a user selects or deselects a video in the image picker using media library.
*/
useEffect(() => {
if (selectedFilesLength > fileUploadsLength) {
/** User selected a video in bottom sheet attachment picker */
const fileToUpload = selectedFiles.find((selectedFile) => {
const uploadedFile = fileUploads.find(
(fileUpload) =>
fileUpload.file.uri === selectedFile.uri || fileUpload.url === selectedFile.uri,
);
return !uploadedFile;
});
if (fileToUpload) uploadNewFile(fileToUpload);
} else {
/** User de-selected a video in bottom sheet attachment picker */
const filesToRemove = fileUploads.filter(
(fileUpload) =>
!selectedFiles.find(
(selectedFile) =>
selectedFile.uri === fileUpload.file.uri || selectedFile.uri === fileUpload.url,
),
);
filesToRemove.forEach((file) => removeFile(file.id));
}
const uploadOrRemoveFile = async () => {
if (selectedFilesLength > fileUploadsLength) {
/** User selected a video in bottom sheet attachment picker */
await uploadFilesHandler();
} else {
/** User de-selected a video in bottom sheet attachment picker */
removeFilesHandler();
}
};
uploadOrRemoveFile();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [selectedFilesLength]);

/**
* This is for image attachments selected from attachment picker.
*/
useEffect(() => {
if (imagesForInput && hasImagePicker) {
if (imagesForInput && isImageMediaLibraryAvailable()) {
if (imageUploadsLength < selectedImagesLength) {
// /** User removed some image from seleted images within ImageUploadPreview. */
const updatedSelectedImages = selectedImages.filter((selectedImage) => {
Expand All @@ -401,9 +424,7 @@ const MessageInputWithContext = <
setSelectedImages(updatedSelectedImages);
} else if (imageUploadsLength > selectedImagesLength) {
/**
* User is editing some message which contains image attachments OR
* image attachment is added from custom image picker (other than the default bottomsheet image picker)
* using `uploadNewImage` function from `MessageInputContext`.
* User is editing some message which contains image attachments.
**/
setSelectedImages(
imageUploads
Expand All @@ -418,10 +439,13 @@ const MessageInputWithContext = <
}
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [imageUploadsLength, hasImagePicker]);
}, [imageUploadsLength]);

/**
* This is for video attachments selected from attachment picker.
*/
useEffect(() => {
if (hasImagePicker) {
if (isImageMediaLibraryAvailable()) {
if (fileUploadsLength < selectedFilesLength) {
/** User removed some video from seleted files within ImageUploadPreview. */
const updatedSelectedFiles = selectedFiles.filter((selectedFile) => {
Expand All @@ -434,9 +458,7 @@ const MessageInputWithContext = <
setSelectedFiles(updatedSelectedFiles);
} else if (fileUploadsLength > selectedFilesLength) {
/**
* User is editing some message which contains video attachments OR
* video attachment is added from custom image picker (other than the default bottom-sheet image picker)
* using `uploadNewFile` function from `MessageInputContext`.
* User is editing some message which contains video attachments.
**/
setSelectedFiles(
fileUploads.map((fileUpload) => ({
Expand All @@ -450,9 +472,10 @@ const MessageInputWithContext = <
}
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [fileUploadsLength, hasImagePicker]);
}, [fileUploadsLength]);

const editingExists = !!editing;

useEffect(() => {
if (editing && inputBoxRef.current) {
inputBoxRef.current.focus();
Expand Down Expand Up @@ -1036,7 +1059,6 @@ export const MessageInput = <
FileUploadPreview,
fileUploads,
giphyActive,
hasImagePicker,
ImageUploadPreview,
imageUploads,
Input,
Expand Down Expand Up @@ -1117,7 +1139,6 @@ export const MessageInput = <
FileUploadPreview,
fileUploads,
giphyActive,
hasImagePicker,
ImageUploadPreview,
imageUploads,
Input,
Expand Down
Loading

0 comments on commit 0b9f18a

Please sign in to comment.