From 00ce1e18426b33088732c76359d36dcf934e1844 Mon Sep 17 00:00:00 2001 From: Chris Duarte Date: Thu, 14 Dec 2017 10:19:31 -0800 Subject: [PATCH] Enforce max file count and active send button (#1241) * Enforce max file count and wait until all images finish loading Replaced Text with FormattedText Remove unnecessary Text import Clean up post_textbox and file_upload_preview * Fix localization string for mobile * change MAX_IMAGE_COUNT to MAX_FILE_COUNT --- .../file_upload_preview.js | 28 +++++++++++++-- .../components/attachment_button.js | 12 ++++++- app/components/post_textbox/post_textbox.js | 36 ++++++++++++++++--- assets/base/i18n/en.json | 1 + 4 files changed, 69 insertions(+), 8 deletions(-) diff --git a/app/components/file_upload_preview/file_upload_preview.js b/app/components/file_upload_preview/file_upload_preview.js index ef5fd1b00..9ba2ac7d6 100644 --- a/app/components/file_upload_preview/file_upload_preview.js +++ b/app/components/file_upload_preview/file_upload_preview.js @@ -12,6 +12,7 @@ import { } from 'react-native'; import Icon from 'react-native-vector-icons/Ionicons'; +import FormattedText from 'app/components/formatted_text'; import FileAttachmentImage from 'app/components/file_attachment_list/file_attachment_image'; import FileAttachmentIcon from 'app/components/file_attachment_list/file_attachment_icon'; @@ -31,7 +32,8 @@ export default class FileUploadPreview extends PureComponent { inputHeight: PropTypes.number.isRequired, rootId: PropTypes.string, theme: PropTypes.object.isRequired, - filesUploadingForCurrentChannel: PropTypes.bool.isRequired + filesUploadingForCurrentChannel: PropTypes.bool.isRequired, + showFileMaxWarning: PropTypes.bool.isRequired }; handleRetryFileUpload = (file) => { @@ -98,13 +100,20 @@ export default class FileUploadPreview extends PureComponent { }; render() { - if (this.props.channelIsLoading || (!this.props.files.length && !this.props.filesUploadingForCurrentChannel)) { + const { + showFileMaxWarning, + channelIsLoading, + filesUploadingForCurrentChannel, + deviceHeight, + files + } = this.props; + if (channelIsLoading || (!files.length && !filesUploadingForCurrentChannel)) { return null; } return ( - + {this.buildFilePreviews()} + {showFileMaxWarning && ( + + )} + ); @@ -186,5 +203,10 @@ const style = StyleSheet.create({ scrollViewContent: { alignItems: 'flex-end', marginLeft: 14 + }, + warning: { + color: 'white', + marginLeft: 14, + marginBottom: 12 } }); diff --git a/app/components/post_textbox/components/attachment_button.js b/app/components/post_textbox/components/attachment_button.js index b8ae1f469..3ee902d3f 100644 --- a/app/components/post_textbox/components/attachment_button.js +++ b/app/components/post_textbox/components/attachment_button.js @@ -17,7 +17,10 @@ class AttachmentButton extends PureComponent { intl: intlShape.isRequired, navigator: PropTypes.object.isRequired, theme: PropTypes.object.isRequired, - uploadFiles: PropTypes.func.isRequired + uploadFiles: PropTypes.func.isRequired, + fileCount: PropTypes.number, + maxFileCount: PropTypes.number.isRequired, + onShowFileMaxWarning: PropTypes.func.isRequired }; attachFileFromCamera = () => { @@ -142,6 +145,13 @@ class AttachmentButton extends PureComponent { } showFileAttachmentOptions = () => { + const {fileCount, maxFileCount, onShowFileMaxWarning} = this.props; + + if (fileCount === maxFileCount) { + onShowFileMaxWarning(); + return; + } + this.props.blurTextBox(); const options = { items: [{ diff --git a/app/components/post_textbox/post_textbox.js b/app/components/post_textbox/post_textbox.js index f6d2a2af9..a7921910a 100644 --- a/app/components/post_textbox/post_textbox.js +++ b/app/components/post_textbox/post_textbox.js @@ -18,6 +18,7 @@ import Typing from './components/typing'; const INITIAL_HEIGHT = Platform.OS === 'ios' ? 34 : 36; const MAX_CONTENT_HEIGHT = 100; const MAX_MESSAGE_LENGTH = 4000; +const MAX_FILE_COUNT = 5; const IS_REACTION_REGEX = /(^\+:([^:\s]*):)$/i; class PostTextbox extends PureComponent { @@ -62,7 +63,8 @@ class PostTextbox extends PureComponent { contentHeight: INITIAL_HEIGHT, inputWidth: null, keyboardType: 'default', - value: props.value + value: props.value, + showFileMaxWarning: false }; } @@ -100,7 +102,19 @@ class PostTextbox extends PureComponent { const valueLength = value.trim().length; if (files.length) { - return valueLength <= MAX_MESSAGE_LENGTH && uploadFileRequestStatus !== RequestStatus.STARTED; + const filesLoading = []; + const filesFailed = []; + files.forEach((file) => { + if (file.loading) { + filesLoading.push(file); + } + if (!file.failed) { + filesFailed.push(file); + } + }); + const loadingComplete = filesLoading.length === 0; + const noneFailed = filesFailed.length > 0; + return valueLength <= MAX_MESSAGE_LENGTH && uploadFileRequestStatus !== RequestStatus.STARTED && noneFailed && loadingComplete; } return valueLength > 0 && valueLength <= MAX_MESSAGE_LENGTH; @@ -268,7 +282,7 @@ class PostTextbox extends PureComponent { }; renderSendButton = () => { - const {theme, uploadFileRequestStatus} = this.props; + const {files, theme} = this.props; const style = getStyleSheet(theme); const icon = ( @@ -280,7 +294,8 @@ class PostTextbox extends PureComponent { ); let button = null; - if (uploadFileRequestStatus === RequestStatus.STARTED) { + const imagesLoading = files.filter((f) => f.loading).length > 0; + if (imagesLoading) { button = ( @@ -368,6 +383,14 @@ class PostTextbox extends PureComponent { this.changeDraft(''); }; + onShowFileMaxWarning = () => { + this.setState({showFileMaxWarning: true}, () => { + setTimeout(() => { + this.setState({showFileMaxWarning: false}); + }, 3000); + }); + }; + render() { const { canUploadFiles, @@ -379,6 +402,7 @@ class PostTextbox extends PureComponent { rootId, theme } = this.props; + const {showFileMaxWarning} = this.state; const style = getStyleSheet(theme); const textInputHeight = Math.min(this.state.contentHeight, MAX_CONTENT_HEIGHT); @@ -400,6 +424,9 @@ class PostTextbox extends PureComponent { blurTextBox={this.blur} theme={theme} navigator={navigator} + fileCount={files.length} + maxFileCount={MAX_FILE_COUNT} + onShowFileMaxWarning={this.onShowFileMaxWarning} uploadFiles={this.handleUploadFiles} /> ); @@ -421,6 +448,7 @@ class PostTextbox extends PureComponent { files={files} inputHeight={textInputHeight} rootId={rootId} + showFileMaxWarning={showFileMaxWarning} />