diff --git a/src/components/MessageInput/FileUploadPreview.js b/src/components/MessageInput/FileUploadPreview.js
index 1707923e3..1c3a52120 100644
--- a/src/components/MessageInput/FileUploadPreview.js
+++ b/src/components/MessageInput/FileUploadPreview.js
@@ -7,6 +7,7 @@ import UploadProgressIndicator from './UploadProgressIndicator';
import FileIcon from '../Attachment/FileIcon';
+import closeRound from '../../images/icons/close-round.png';
import { themed } from '../../styles/theme';
import { FileState, ProgressIndicatorTypes } from '../../utils/utils';
@@ -39,8 +40,23 @@ const Container = styled.View`
${({ theme }) => theme.messageInput.fileUploadPreview.container.css};
`;
-const DismissText = styled.Text`
- ${({ theme }) => theme.messageInput.fileUploadPreview.dismissText.css};
+const Dismiss = styled.TouchableOpacity`
+ align-items: center;
+ background-color: #fff;
+ border-radius: 20px;
+ height: 20px;
+ justify-content: center;
+ position: absolute;
+ right: 5;
+ top: 5;
+ width: 20px;
+ ${({ theme }) => theme.messageInput.fileUploadPreview.dismiss.css};
+`;
+
+const DismissImage = styled.Image`
+ height: 10px;
+ width: 10px;
+ ${({ theme }) => theme.messageInput.fileUploadPreview.dismissImage.css};
`;
const FilenameText = styled.Text`
@@ -72,28 +88,38 @@ const FileUploadPreview = ({
}
return (
- (retryUpload ? retryUpload(item.id) : null)}
- active={item.state !== FileState.UPLOADED}
- type={type}
- >
-
-
-
-
- {item.file.name.length > 35
- ? item.file.name.substring(0, 35).concat('...')
- : item.file.name}
-
-
- removeFile(item.id)}
- testID='remove-file-upload-preview'
- >
- X
-
-
-
+ <>
+ {
+ if (retryUpload) {
+ retryUpload(item.id);
+ }
+ }}
+ active={item.state !== FileState.UPLOADED}
+ type={type}
+ >
+
+
+
+
+ {item.file.name.length > 35
+ ? item.file.name.substring(0, 35).concat('...')
+ : item.file.name}
+
+
+
+
+ {
+ if (removeFile) {
+ removeFile(item.id);
+ }
+ }}
+ testID='remove-file-upload-preview'
+ >
+
+
+ >
);
};
diff --git a/src/components/MessageInput/ImageUploadPreview.js b/src/components/MessageInput/ImageUploadPreview.js
index 9e0e8b429..72ae22316 100644
--- a/src/components/MessageInput/ImageUploadPreview.js
+++ b/src/components/MessageInput/ImageUploadPreview.js
@@ -69,7 +69,11 @@ const ImageUploadPreview = ({ imageUploads, removeImage, retryUpload }) => {
return (
(retryUpload ? retryUpload(item.id) : null)}
+ action={() => {
+ if (retryUpload) {
+ retryUpload(item.id);
+ }
+ }}
active={item.state !== FileState.UPLOADED}
type={type}
>
@@ -79,7 +83,11 @@ const ImageUploadPreview = ({ imageUploads, removeImage, retryUpload }) => {
/>
removeImage(item.id)}
+ onPress={() => {
+ if (removeImage) {
+ removeImage(item.id);
+ }
+ }}
testID='remove-image-upload-preview'
>
diff --git a/src/components/MessageInput/MessageInput.js b/src/components/MessageInput/MessageInput.js
index f903151ae..f709d4e20 100644
--- a/src/components/MessageInput/MessageInput.js
+++ b/src/components/MessageInput/MessageInput.js
@@ -8,8 +8,8 @@ import { logChatPromiseExecution } from 'stream-chat';
import ActionSheetAttachmentDefault from './ActionSheetAttachment';
import AttachButtonDefault from './AttachButton';
-import FileUploadPreview from './FileUploadPreview';
-import ImageUploadPreview from './ImageUploadPreview';
+import FileUploadPreviewDefault from './FileUploadPreview';
+import ImageUploadPreviewDefault from './ImageUploadPreview';
import SendButtonDefault from './SendButton';
import { useMessageDetailsForState } from './hooks/useMessageDetailsForState';
@@ -123,8 +123,10 @@ const MessageInput = (props) => {
compressImageQuality,
doDocUploadRequest,
doImageUploadRequest,
+ FileUploadPreview = FileUploadPreviewDefault,
hasFilePicker = true,
hasImagePicker = true,
+ ImageUploadPreview = ImageUploadPreviewDefault,
initialValue,
Input,
maxNumberOfFiles,
@@ -870,10 +872,26 @@ MessageInput.propTypes = {
* @param channel Current channel object
* */
doImageUploadRequest: PropTypes.func,
+ /**
+ * Custom UI component for FileUploadPreview.
+ * Defaults to and accepts same props as: https://github.com/GetStream/stream-chat-react-native/blob/master/src/components/MessageInput/FileUploadPreview.js
+ */
+ FileUploadPreview: PropTypes.oneOfType([
+ PropTypes.node,
+ PropTypes.elementType,
+ ]),
/** If component should have file picker functionality */
hasFilePicker: PropTypes.bool,
/** If component should have image picker functionality */
hasImagePicker: PropTypes.bool,
+ /**
+ * Custom UI component for ImageUploadPreview.
+ * Defaults to and accepts same props as: https://github.com/GetStream/stream-chat-react-native/blob/master/src/components/MessageInput/ImageUploadPreview.js
+ */
+ ImageUploadPreview: PropTypes.oneOfType([
+ PropTypes.node,
+ PropTypes.elementType,
+ ]),
/** Initial value to set on input */
initialValue: PropTypes.string,
/** Limit on allowed number of files to attach at a time. */
diff --git a/src/components/MessageInput/UploadProgressIndicator.js b/src/components/MessageInput/UploadProgressIndicator.js
index 0891a4a0f..1998911e2 100644
--- a/src/components/MessageInput/UploadProgressIndicator.js
+++ b/src/components/MessageInput/UploadProgressIndicator.js
@@ -1,5 +1,5 @@
import React from 'react';
-import { ActivityIndicator, Image, TouchableOpacity, View } from 'react-native';
+import { ActivityIndicator, Image, View } from 'react-native';
import styled from '@stream-io/styled-components';
import PropTypes from 'prop-types';
@@ -28,44 +28,53 @@ const Overlay = styled.View`
${({ theme }) => theme.messageInput.uploadProgressIndicator.overlay.css};
`;
+const ActivityIndicatorContainer = styled.View`
+ align-items: center;
+ bottom: 0;
+ justify-content: center;
+ left: 0;
+ position: absolute;
+ right: 0;
+ top: 0;
+`;
+
+const RetryButtonContainer = styled.TouchableOpacity`
+ align-items: center;
+ bottom: 0;
+ justify-content: center;
+ left: 0;
+ position: absolute;
+ right: 0;
+ top: 0;
+`;
+
const UploadProgressIndicator = ({ action, active, children, type }) =>
!active ? (
{children}
) : (
-
+
{children}
{type === ProgressIndicatorTypes.IN_PROGRESS && (
-
+
-
+
)}
{type === ProgressIndicatorTypes.RETRY && (
-
+
+
+
)}
-
+
);
UploadProgressIndicator.propTypes = {
diff --git a/src/components/MessageInput/__tests__/FileUploadPreview.test.js b/src/components/MessageInput/__tests__/FileUploadPreview.test.js
index 1ea8d37ac..0449d007e 100644
--- a/src/components/MessageInput/__tests__/FileUploadPreview.test.js
+++ b/src/components/MessageInput/__tests__/FileUploadPreview.test.js
@@ -49,13 +49,6 @@ describe('FileUploadPreview', () => {
expect(retryUpload).toHaveBeenCalledTimes(0);
});
- fireEvent.press(getAllByTestId('active-upload-progress-indicator')[0]);
-
- await waitFor(() => {
- expect(removeFile).toHaveBeenCalledTimes(1);
- expect(retryUpload).toHaveBeenCalledTimes(1);
- });
-
rerender(
({
@@ -170,7 +163,7 @@ describe('FileUploadPreview', () => {
expect(retryUpload).toHaveBeenCalledTimes(0);
});
- fireEvent.press(getAllByTestId('active-upload-progress-indicator')[0]);
+ fireEvent.press(getAllByTestId('retry-upload-progress-indicator')[0]);
await waitFor(() => {
expect(removeFile).toHaveBeenCalledTimes(1);
diff --git a/src/components/MessageInput/__tests__/ImageUploadPreview.test.js b/src/components/MessageInput/__tests__/ImageUploadPreview.test.js
index 4b9a4df9e..024b68089 100644
--- a/src/components/MessageInput/__tests__/ImageUploadPreview.test.js
+++ b/src/components/MessageInput/__tests__/ImageUploadPreview.test.js
@@ -49,13 +49,6 @@ describe('ImageUploadPreview', () => {
expect(retryUpload).toHaveBeenCalledTimes(0);
});
- fireEvent.press(getAllByTestId('active-upload-progress-indicator')[0]);
-
- await waitFor(() => {
- expect(removeImage).toHaveBeenCalledTimes(1);
- expect(retryUpload).toHaveBeenCalledTimes(1);
- });
-
rerender(
({
@@ -170,7 +163,7 @@ describe('ImageUploadPreview', () => {
expect(retryUpload).toHaveBeenCalledTimes(0);
});
- fireEvent.press(getAllByTestId('active-upload-progress-indicator')[0]);
+ fireEvent.press(getAllByTestId('retry-upload-progress-indicator')[0]);
await waitFor(() => {
expect(removeImage).toHaveBeenCalledTimes(1);
diff --git a/src/components/MessageInput/__tests__/UploadProgressIndicator.test.js b/src/components/MessageInput/__tests__/UploadProgressIndicator.test.js
index f2e9249ca..7dbb7c558 100644
--- a/src/components/MessageInput/__tests__/UploadProgressIndicator.test.js
+++ b/src/components/MessageInput/__tests__/UploadProgressIndicator.test.js
@@ -55,7 +55,7 @@ describe('UploadProgressIndicator', () => {
it('should render an active IN_PROGRESS UploadProgressIndicator', async () => {
const action = jest.fn();
- const { getByTestId, queryByTestId, toJSON } = render(
+ const { queryByTestId, toJSON } = render(
{
await waitFor(() => {
expect(queryByTestId('active-upload-progress-indicator')).toBeTruthy();
expect(queryByTestId('inactive-upload-progress-indicator')).toBeFalsy();
+ expect(queryByTestId('upload-progress-indicator')).toBeTruthy();
+ expect(queryByTestId('retry-upload-progress-indicator')).toBeFalsy();
expect(action).toHaveBeenCalledTimes(0);
});
- fireEvent.press(getByTestId('active-upload-progress-indicator'));
-
- await waitFor(() => expect(action).toHaveBeenCalledTimes(1));
-
const snapshot = toJSON();
await waitFor(() => {
@@ -94,10 +92,12 @@ describe('UploadProgressIndicator', () => {
await waitFor(() => {
expect(queryByTestId('active-upload-progress-indicator')).toBeTruthy();
expect(queryByTestId('inactive-upload-progress-indicator')).toBeFalsy();
+ expect(queryByTestId('upload-progress-indicator')).toBeFalsy();
+ expect(queryByTestId('retry-upload-progress-indicator')).toBeTruthy();
expect(action).toHaveBeenCalledTimes(0);
});
- fireEvent.press(getByTestId('active-upload-progress-indicator'));
+ fireEvent.press(getByTestId('retry-upload-progress-indicator'));
await waitFor(() => expect(action).toHaveBeenCalledTimes(1));
diff --git a/src/components/MessageInput/__tests__/__snapshots__/FileUploadPreview.test.js.snap b/src/components/MessageInput/__tests__/__snapshots__/FileUploadPreview.test.js.snap
index b75ce12bd..31106d1fc 100644
--- a/src/components/MessageInput/__tests__/__snapshots__/FileUploadPreview.test.js.snap
+++ b/src/components/MessageInput/__tests__/__snapshots__/FileUploadPreview.test.js.snap
@@ -78,21 +78,6 @@ exports[`FileUploadPreview should render FileUploadPreview with 1 uploading, 1 u
style={null}
>
-
- X
-
+
+
+
-
- X
-
-
-
+
+
+
+
+
-
- X
-
-
+ >
+
+
+
+
+
@@ -515,21 +608,6 @@ exports[`FileUploadPreview should render FileUploadPreview with all failed files
style={null}
>
-
- X
-
-
+ >
+
+
-
-
+
+
+
+
+
-
- X
-
-
+ >
+
+
-
-
+
+
+
+
+
-
- X
-
+
+
+
+
+
+
+
-
-
+ />
@@ -1063,19 +1282,51 @@ exports[`FileUploadPreview should render FileUploadPreview with all uploaded fil
dummy.pdf
-
- X
-
+
+
+
-
- X
-
+
+
+
-
- X
-
+
+
+
@@ -1316,21 +1631,6 @@ exports[`FileUploadPreview should render FileUploadPreview with all uploading fi
style={null}
>
-
- X
-
-
-
+
+
+
+
+
-
- X
-
-
-
+
+
+
+
+
-
- X
-
+
+
+
diff --git a/src/components/MessageInput/__tests__/__snapshots__/ImageUploadPreview.test.js.snap b/src/components/MessageInput/__tests__/__snapshots__/ImageUploadPreview.test.js.snap
index f535e7db8..f5570ed4b 100644
--- a/src/components/MessageInput/__tests__/__snapshots__/ImageUploadPreview.test.js.snap
+++ b/src/components/MessageInput/__tests__/__snapshots__/ImageUploadPreview.test.js.snap
@@ -93,21 +93,6 @@ exports[`ImageUploadPreview should render ImageUploadPreview with 1 uploading, 1
}
>
-
+ >
+
+
-
+ >
+
+
-
+ >
+
+
-
+ >
+
+
-
+ >
+
+
`;
diff --git a/src/images/reload1.png b/src/images/reload1.png
index a42a28ec1..fad57208c 100644
Binary files a/src/images/reload1.png and b/src/images/reload1.png differ
diff --git a/src/styles/theme.js b/src/styles/theme.js
index 446e5b442..f1319f414 100644
--- a/src/styles/theme.js
+++ b/src/styles/theme.js
@@ -202,8 +202,10 @@ export const defaultTheme = {
attachmentContainerView: {},
attachmentView: {},
container: {},
- dismissText: {},
+ dismiss: {},
+ dismissImage: {},
filenameText: {},
+ itemContainer: {},
},
imageUploadPreview: {
container: {},
diff --git a/types/index.d.ts b/types/index.d.ts
index 84ca80d3b..af5b729f9 100644
--- a/types/index.d.ts
+++ b/types/index.d.ts
@@ -264,33 +264,32 @@ export interface MessageInputProps
SuggestionsContextValue,
TranslationContextValue,
StyledComponentProps {
- /** Callback that is called when the text input's text changes. Changed text is passed as a single string argument to the callback handler. */
- onChangeText?(newText: string): void;
- /** Initial value to set on input */
+ ActionSheetAttachment?: React.ElementType;
+ /** https://github.com/beefe/react-native-actionsheet/blob/master/lib/styles.js */
+ actionSheetStyles?: object;
+ additionalTextInputProps?: object;
+ AttachButton?: React.ElementType;
+ AttachmentFileIcon?: React.ElementType;
+ compressImageQuality?: number;
+ /** Override file upload request */
+ doFileUploadRequest?(file: File): Promise;
+ /** Override image upload request */
+ doImageUploadRequest?(file: File): Promise;
+ FileUploadPreview?: React.ElementType;
+ hasFilePicker?: boolean;
+ hasImagePicker?: boolean;
+ ImageUploadPreview?: React.ElementType;
initialValue?: string;
/** The parent message object when replying on a thread */
- parent?: Client.Message | null;
-
/** The component handling how the input is rendered */
Input?: React.ElementType;
-
- /** Override image upload request */
- doImageUploadRequest?(file: File): Promise;
-
- /** Override file upload request */
- doFileUploadRequest?(file: File): Promise;
maxNumberOfFiles?: number;
- hasImagePicker?: boolean;
- hasFilePicker?: boolean;
- focus?: boolean;
- sendImageAsync?: boolean;
- /** https://github.com/beefe/react-native-actionsheet/blob/master/lib/styles.js */
- actionSheetStyles?: object;
- AttachmentFileIcon?: React.ElementType;
- AttachButton?: React.ElementType;
- ActionSheetAttachment?: React.ElementType;
+ /** Callback that is called when the text input's text changes. Changed text is passed as a single string argument to the callback handler. */
+ onChangeText?(newText: string): void;
+ /** Initial value to set on input */
+ parent?: Client.Message | null;
SendButton: React.ElementType;
- additionalTextInputProps?: object;
+ sendImageAsync?: boolean;
}
export interface DocumentPickerFile {