diff --git a/app/components/__snapshots__/send_button.test.js.snap b/app/components/__snapshots__/send_button.test.js.snap index ba764cb7db..4062649972 100644 --- a/app/components/__snapshots__/send_button.test.js.snap +++ b/app/components/__snapshots__/send_button.test.js.snap @@ -5,8 +5,7 @@ exports[`SendButton should change theme backgroundColor to 0.3 opacity 1`] = ` style={ Object { "justifyContent": "flex-end", - "paddingHorizontal": 5, - "paddingVertical": 2, + "paddingRight": 8, } } > @@ -17,10 +16,9 @@ exports[`SendButton should change theme backgroundColor to 0.3 opacity 1`] = ` "alignItems": "center", "backgroundColor": "#166de0", "borderRadius": 4, - "height": 28, + "height": 32, "justifyContent": "center", - "paddingLeft": 3, - "width": 72, + "width": 80, }, Object { "backgroundColor": "rgba(22,109,224,0.3)", @@ -29,9 +27,9 @@ exports[`SendButton should change theme backgroundColor to 0.3 opacity 1`] = ` } > @@ -43,8 +41,7 @@ exports[`SendButton should match snapshot 1`] = ` style={ Object { "justifyContent": "flex-end", - "paddingHorizontal": 5, - "paddingVertical": 2, + "paddingRight": 8, } } type="opacity" @@ -55,17 +52,16 @@ exports[`SendButton should match snapshot 1`] = ` "alignItems": "center", "backgroundColor": "#166de0", "borderRadius": 4, - "height": 28, + "height": 32, "justifyContent": "center", - "paddingLeft": 3, - "width": 72, + "width": 80, } } > @@ -77,8 +73,7 @@ exports[`SendButton should render theme backgroundColor 1`] = ` style={ Object { "justifyContent": "flex-end", - "paddingHorizontal": 5, - "paddingVertical": 2, + "paddingRight": 8, } } type="opacity" @@ -89,17 +84,16 @@ exports[`SendButton should render theme backgroundColor 1`] = ` "alignItems": "center", "backgroundColor": "#166de0", "borderRadius": 4, - "height": 28, + "height": 32, "justifyContent": "center", - "paddingLeft": 3, - "width": 72, + "width": 80, } } > diff --git a/app/components/attachment_button/index.js b/app/components/attachment_button/index.js index 7b96cb410a..58be8d1763 100644 --- a/app/components/attachment_button/index.js +++ b/app/components/attachment_button/index.js @@ -329,18 +329,19 @@ export default class AttachmentButton extends PureComponent { hasStoragePermission = async () => { if (Platform.OS === 'android') { const {formatMessage} = this.context.intl; + const storagePermission = Permissions.PERMISSIONS.ANDROID.READ_EXTERNAL_STORAGE; let permissionRequest; - const hasPermissionToStorage = await Permissions.check('storage'); + const hasPermissionToStorage = await Permissions.check(storagePermission); switch (hasPermissionToStorage) { case Permissions.RESULTS.DENIED: - permissionRequest = await Permissions.request('storage'); + permissionRequest = await Permissions.request(storagePermission); if (permissionRequest !== Permissions.RESULTS.GRANTED) { return false; } break; case Permissions.RESULTS.BLOCKED: { - const {title, text} = this.getPermissionDeniedMessage('storage'); + const {title, text} = this.getPermissionDeniedMessage(storagePermission); Alert.alert( title, diff --git a/app/components/file_upload_preview/file_upload_item/file_upload_item.js b/app/components/file_upload_preview/file_upload_item/file_upload_item.js index df3ff436da..9270a57e67 100644 --- a/app/components/file_upload_preview/file_upload_item/file_upload_item.js +++ b/app/components/file_upload_preview/file_upload_item/file_upload_item.js @@ -3,7 +3,7 @@ import React, {PureComponent} from 'react'; import PropTypes from 'prop-types'; -import {Platform, StyleSheet, Text, View} from 'react-native'; +import {Text, View} from 'react-native'; import RNFetchBlob from 'rn-fetch-blob'; import {AnimatedCircularProgress} from 'react-native-circular-progress'; @@ -17,6 +17,7 @@ import mattermostBucket from 'app/mattermost_bucket'; import {buildFileUploadData, encodeHeaderURIStringToUTF8} from 'app/utils/file'; import {emptyFunction} from 'app/utils/general'; import ImageCacheManager from 'app/utils/image_cache_manager'; +import {makeStyleSheetFromTheme, changeOpacity} from 'app/utils/theme'; export default class FileUploadItem extends PureComponent { static propTypes = { @@ -163,6 +164,7 @@ export default class FileUploadItem extends PureComponent { }; renderProgress = (fill) => { + const styles = getStyleSheet(this.props.theme); const realFill = Number(fill.toFixed(0)); return ( @@ -184,23 +186,28 @@ export default class FileUploadItem extends PureComponent { theme, } = this.props; const {progress} = this.state; + const styles = getStyleSheet(theme); let filePreviewComponent; if (this.isImageType()) { filePreviewComponent = ( - + + + ); } else { filePreviewComponent = ( - + + + ); } @@ -209,7 +216,7 @@ export default class FileUploadItem extends PureComponent { key={file.clientId} style={styles.preview} > - + {filePreviewComponent} {file.failed && ({ preview: { - justifyContent: 'flex-end', - height: 115, - width: 115, + paddingTop: 12, + marginLeft: 12, }, - previewShadow: { - height: 100, - width: 100, + previewContainer: { + height: 64, + width: 64, elevation: 10, - borderRadius: 5, - ...Platform.select({ - ios: { - backgroundColor: '#fff', - shadowColor: '#000', - shadowOpacity: 0.5, - shadowRadius: 4, - shadowOffset: { - width: 0, - height: 0, - }, - }, - }), + borderRadius: 4, }, progressCircle: { alignItems: 'center', @@ -278,10 +272,10 @@ const styles = StyleSheet.create({ progressCircleContent: { alignItems: 'center', backgroundColor: 'rgba(0, 0, 0, 0.4)', - height: 100, + height: 64, justifyContent: 'center', position: 'absolute', - width: 100, + width: 64, }, progressCirclePercentage: { alignItems: 'center', @@ -300,4 +294,11 @@ const styles = StyleSheet.create({ color: 'white', fontSize: 18, }, -}); + filePreview: { + borderColor: changeOpacity(theme.centerChannelColor, 0.15), + borderRadius: 5, + borderWidth: 1, + width: 64, + height: 64, + }, +})); diff --git a/app/components/file_upload_preview/file_upload_item/file_upload_item.test.js b/app/components/file_upload_preview/file_upload_item/file_upload_item.test.js index 45d9f016bd..eca4744f34 100644 --- a/app/components/file_upload_preview/file_upload_item/file_upload_item.test.js +++ b/app/components/file_upload_preview/file_upload_item/file_upload_item.test.js @@ -3,6 +3,7 @@ import React from 'react'; import {shallow} from 'enzyme'; +import {Preferences} from 'mattermost-redux/constants'; import ImageCacheManager from 'app/utils/image_cache_manager'; import FileUploadItem from './file_upload_item'; @@ -18,7 +19,7 @@ describe('FileUploadItem', () => { file: { loading: false, }, - theme: {}, + theme: Preferences.THEMES.default, }; describe('downloadAndUploadFile', () => { diff --git a/app/components/file_upload_preview/file_upload_preview.js b/app/components/file_upload_preview/file_upload_preview.js index 7f909bb2c6..01d460f579 100644 --- a/app/components/file_upload_preview/file_upload_preview.js +++ b/app/components/file_upload_preview/file_upload_preview.js @@ -4,19 +4,26 @@ import React, {PureComponent} from 'react'; import PropTypes from 'prop-types'; import { - Platform, + InteractionManager, ScrollView, Text, View, } from 'react-native'; -import {makeStyleSheetFromTheme} from 'app/utils/theme'; +import * as Animatable from 'react-native-animatable'; import EventEmitter from 'mattermost-redux/utils/event_emitter'; import FormattedText from 'app/components/formatted_text'; +import {makeStyleSheetFromTheme} from 'app/utils/theme'; import FileUploadItem from './file_upload_item'; +const initial = {opacity: 0, scale: 0}; +const final = {opacity: 1, scale: 1}; +const showFiles = {opacity: 1, height: 81}; +const hideFiles = {opacity: 0, height: 0}; +const hideError = {height: 0}; + export default class FileUploadPreview extends PureComponent { static propTypes = { channelId: PropTypes.string.isRequired, @@ -36,9 +43,17 @@ export default class FileUploadPreview extends PureComponent { showFileMaxWarning: false, }; + errorRef = React.createRef(); + errorContainerRef = React.createRef(); + containerRef = React.createRef(); + componentDidMount() { EventEmitter.on('fileMaxWarning', this.handleFileMaxWarning); EventEmitter.on('fileSizeWarning', this.handleFileSizeWarning); + + if (this.props.files.length) { + InteractionManager.runAfterInteractions(this.showOrHideContainer); + } } componentWillUnmount() { @@ -46,6 +61,12 @@ export default class FileUploadPreview extends PureComponent { EventEmitter.off('fileSizeWarning', this.handleFileSizeWarning); } + componentDidUpdate(prevProps) { + if (this.containerRef.current && this.props.files.length !== prevProps.files.length) { + InteractionManager.runAfterInteractions(this.showOrHideContainer); + } + } + buildFilePreviews = () => { return this.props.files.map((file) => { return ( @@ -60,35 +81,88 @@ export default class FileUploadPreview extends PureComponent { }); }; + clearErrorsFromState = (delay) => { + setTimeout(() => { + this.setState({ + showFileMaxWarning: false, + fileSizeWarning: null, + }); + }, delay || 0); + } + handleFileMaxWarning = () => { this.setState({showFileMaxWarning: true}); - setTimeout(() => { - this.setState({showFileMaxWarning: false}); - }, 3000); + if (this.errorRef.current) { + this.makeErrorVisible(true, 20, null, () => { + this.errorRef.current.transition(initial, final, 350, 'ease-in'); + }); + setTimeout(() => { + this.makeErrorVisible(false, 20, 350, () => { + this.errorRef.current.transition(final, initial, 350, 'ease-out'); + this.clearErrorsFromState(400); + }); + }, 5000); + } }; handleFileSizeWarning = (message) => { - this.setState({fileSizeWarning: message}); + if (this.errorRef.current) { + if (message) { + this.setState({fileSizeWarning: message}); + this.makeErrorVisible(true, 42, null, () => { + this.errorRef.current.transition(initial, final, 350, 'ease-in'); + }); + } else { + this.makeErrorVisible(false, 42, 350, () => { + this.errorRef.current.transition(final, initial, 350, 'ease-out'); + this.clearErrorsFromState(400); + }); + } + } }; - render() { + makeErrorVisible = (visible, height, delay, callback) => { + if (this.errorContainerRef.current) { + if (visible) { + this.errorContainerRef.current.transition(hideError, {height}, 100); + setTimeout(callback, delay || 150); + } else { + callback(); + setTimeout(() => { + this.errorContainerRef.current.transition({height}, hideError, 300); + }, delay || 150); + } + } + } + + showOrHideContainer = () => { const { channelIsLoading, filesUploadingForCurrentChannel, files, } = this.props; + + if ((channelIsLoading || (!files.length && !filesUploadingForCurrentChannel))) { + this.containerRef.current.transition(showFiles, hideFiles, 150, 'ease-out'); + this.shown = false; + } else if (files.length && !this.shown) { + this.containerRef.current.transition(hideFiles, showFiles, 350, 'ease-in'); + this.shown = true; + } + } + + render() { const {fileSizeWarning, showFileMaxWarning} = this.state; const style = getStyleSheet(this.props.theme); - if ( - !fileSizeWarning && !showFileMaxWarning && - (channelIsLoading || (!files.length && !filesUploadingForCurrentChannel)) - ) { - return null; - } return ( - + {this.buildFilePreviews()} - - - {showFileMaxWarning && ( - - )} - {Boolean(fileSizeWarning) && - - {fileSizeWarning} - - } - + + + + {showFileMaxWarning && ( + + )} + {Boolean(fileSizeWarning) && + + {fileSizeWarning} + + } + + ); } @@ -119,32 +204,36 @@ export default class FileUploadPreview extends PureComponent { const getStyleSheet = makeStyleSheetFromTheme((theme) => { return { - fileContainer: { - display: 'flex', - flexDirection: 'row', - }, - errorContainer: { - height: 18, - }, previewContainer: { display: 'flex', flexDirection: 'column', }, + fileContainer: { + display: 'flex', + flexDirection: 'row', + height: 0, + alignItems: 'center', + }, + errorContainer: { + height: 0, + }, + errorTextContainer: { + marginTop: 5, + marginHorizontal: 12, + opacity: 0, + flex: 1, + }, scrollView: { flex: 1, - marginBottom: 10, }, scrollViewContent: { alignItems: 'flex-end', - marginLeft: 14, + paddingRight: 12, }, warning: { color: theme.errorTextColor, - marginLeft: 14, - marginBottom: Platform.select({ - android: 14, - ios: 0, - }), + flex: 1, + flexWrap: 'wrap', }, }; }); diff --git a/app/components/file_upload_preview/file_upload_remove.js b/app/components/file_upload_preview/file_upload_remove.js index fa0abd42f6..51dbcfde89 100644 --- a/app/components/file_upload_preview/file_upload_remove.js +++ b/app/components/file_upload_preview/file_upload_remove.js @@ -3,9 +3,9 @@ import React, {PureComponent} from 'react'; import PropTypes from 'prop-types'; -import {Platform} from 'react-native'; +import {View} from 'react-native'; import Icon from 'react-native-vector-icons/MaterialCommunityIcons'; -import {makeStyleSheetFromTheme} from 'app/utils/theme'; +import {makeStyleSheetFromTheme, changeOpacity} from 'app/utils/theme'; import TouchableWithFeedback from 'app/components/touchable_with_feedback'; @@ -25,19 +25,21 @@ export default class FileUploadRemove extends PureComponent { }; render() { - const style = getStyleSheet(this.props.theme); + const {theme} = this.props; + const style = getStyleSheet(theme); return ( - + + + ); } @@ -45,25 +47,20 @@ export default class FileUploadRemove extends PureComponent { const getStyleSheet = makeStyleSheetFromTheme((theme) => { return { - removeButtonIcon: Platform.select({ - ios: { - marginTop: 2, - }, - }), - removeButtonWrapper: { - alignItems: 'center', - justifyContent: 'center', + tappableContainer: { position: 'absolute', - overflow: 'hidden', elevation: 11, - top: 7, - right: 7, - width: 24, - height: 24, - borderRadius: 12, + top: -2, + right: -16, + width: 32, + height: 32, + }, + removeButton: { + borderRadius: 20, + alignSelf: 'center', + paddingTop: 6, + paddingHorizontal: 1, backgroundColor: theme.centerChannelBg, - borderWidth: 2, - borderColor: theme.centerChannelBg, }, }; }); diff --git a/app/components/pasteable_text_input/index.js b/app/components/pasteable_text_input/index.js index 04b748fe46..abdb0fd989 100644 --- a/app/components/pasteable_text_input/index.js +++ b/app/components/pasteable_text_input/index.js @@ -18,9 +18,7 @@ export class PasteableTextInput extends React.PureComponent { forwardRef: PropTypes.any, } - state = { - inputHeight: new Animated.Value(33), - }; + inputHeight = new Animated.Value(ViewTypes.INPUT_INITIAL_HEIGHT); componentDidMount() { this.subscription = OnPasteEventEmitter.addListener('onPaste', this.onPaste); @@ -40,22 +38,33 @@ export class PasteableTextInput extends React.PureComponent { animateHeight = (event) => { if (Platform.OS === 'ios') { const {height} = event.nativeEvent.contentSize; - const {style} = this.props; - const {inputHeight} = this.state; + const {style, value} = this.props; const newHeight = Math.min(style.maxHeight, height + ViewTypes.INPUT_VERTICAL_PADDING); - const transitionSpeed = height === ViewTypes.INPUT_LINE_HEIGHT ? 500 : 1; - Animated.timing(inputHeight, { - toValue: newHeight, - duration: transitionSpeed, - easing: Easing.inOut(Easing.sin), - }).start(); + if (value) { + this.inputHeight.setValue(newHeight); + } else { + requestAnimationFrame(() => { + Animated.timing(this.inputHeight, { + toValue: ViewTypes.INPUT_INITIAL_HEIGHT, + duration: 350, + delay: 100, + easing: Easing.inOut(Easing.sin), + }).start(); + }); + } } } wrapperLayout = (children) => { - const {inputHeight} = this.state; - return {children}; + return ( + + {children} + + ); } render() { diff --git a/app/components/post_textbox/__snapshots__/post_textbox.test.js.snap b/app/components/post_textbox/__snapshots__/post_textbox.test.js.snap index 0fea5b5ecf..34227db227 100644 --- a/app/components/post_textbox/__snapshots__/post_textbox.test.js.snap +++ b/app/components/post_textbox/__snapshots__/post_textbox.test.js.snap @@ -14,7 +14,7 @@ exports[`PostTextBox should match, full snapshot 1`] = ` "borderTopWidth": 1, "flexDirection": "row", "justifyContent": "center", - "paddingVertical": 4, + "paddingBottom": 8, }, null, ] @@ -36,11 +36,8 @@ exports[`PostTextBox should match, full snapshot 1`] = ` style={ Array [ Object { - "backgroundColor": "#ffffff", "flex": 1, "flexDirection": "column", - "marginLeft": 10, - "marginRight": 10, }, ] } @@ -61,100 +58,249 @@ exports[`PostTextBox should match, full snapshot 1`] = ` style={ Object { "color": "#3d3c40", - "fontSize": 14, + "fontSize": 16, + "lineHeight": 20, "maxHeight": 150, - "paddingBottom": 8, - "paddingLeft": 12, - "paddingRight": 12, - "paddingTop": 8, + "minHeight": 38, + "paddingBottom": 6, + "paddingHorizontal": 12, + "paddingTop": 12, } } underlineColorAndroid="transparent" value="" /> - - + + - - - - - + + + + + + - - + + + - - - - + diff --git a/app/components/post_textbox/components/cameraButton.js b/app/components/post_textbox/components/cameraButton.js index c1e79226e9..2b1eb15013 100644 --- a/app/components/post_textbox/components/cameraButton.js +++ b/app/components/post_textbox/components/cameraButton.js @@ -106,7 +106,7 @@ export default class AttachmentButton extends PureComponent { if (Platform.OS === 'ios') { const {formatMessage} = this.context.intl; let permissionRequest; - const targetSource = 'camera'; + const targetSource = Permissions.PERMISSIONS.IOS.CAMERA; const hasPermissionToStorage = await Permissions.check(targetSource); switch (hasPermissionToStorage) { diff --git a/app/components/post_textbox/components/fileUploadButton.js b/app/components/post_textbox/components/fileUploadButton.js index d8c1b7933d..e790b6b148 100644 --- a/app/components/post_textbox/components/fileUploadButton.js +++ b/app/components/post_textbox/components/fileUploadButton.js @@ -96,11 +96,12 @@ export default class FileUploadButton extends PureComponent { if (Platform.OS === 'android') { const {formatMessage} = this.context.intl; let permissionRequest; - const hasPermissionToStorage = await Permissions.check('storage'); + const storagePermission = Permissions.PERMISSIONS.ANDROID.READ_EXTERNAL_STORAGE; + const hasPermissionToStorage = await Permissions.check(storagePermission); switch (hasPermissionToStorage) { case Permissions.RESULTS.UNAVAILABLE: - permissionRequest = await Permissions.request('storage'); + permissionRequest = await Permissions.request(storagePermission); if (permissionRequest !== Permissions.RESULTS.AUTHORIZED) { return false; } diff --git a/app/components/post_textbox/components/imageUploadButton.js b/app/components/post_textbox/components/imageUploadButton.js index f41458e452..334a44165a 100644 --- a/app/components/post_textbox/components/imageUploadButton.js +++ b/app/components/post_textbox/components/imageUploadButton.js @@ -108,7 +108,7 @@ export default class ImageUploadButton extends PureComponent { if (Platform.OS === 'ios') { const {formatMessage} = this.context.intl; let permissionRequest; - const targetSource = 'photo'; + const targetSource = Permissions.PERMISSIONS.IOS.PHOTO_LIBRARY; const hasPermissionToStorage = await Permissions.check(targetSource); switch (hasPermissionToStorage) { diff --git a/app/components/post_textbox/post_textbox_base.js b/app/components/post_textbox/post_textbox_base.js index 6c2afad217..803ad21006 100644 --- a/app/components/post_textbox/post_textbox_base.js +++ b/app/components/post_textbox/post_textbox_base.js @@ -19,6 +19,7 @@ import { View, } from 'react-native'; import {intlShape} from 'react-intl'; +import RNFetchBlob from 'rn-fetch-blob'; import Button from 'react-native-button'; import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons'; import slashForwardBoxIcon from 'assets/images/icons/slash-forward-box.png'; @@ -35,7 +36,7 @@ import FormattedText from 'app/components/formatted_text'; import PasteableTextInput from 'app/components/pasteable_text_input'; import {paddingHorizontal as padding} from 'app/components/safe_area_view/iphone_x_spacing'; import SendButton from 'app/components/send_button'; -import {INSERT_TO_COMMENT, INSERT_TO_DRAFT, IS_REACTION_REGEX, MAX_FILE_COUNT} from 'app/constants/post_textbox'; +import {INSERT_TO_COMMENT, INSERT_TO_DRAFT, IS_REACTION_REGEX, MAX_FILE_COUNT, ICON_SIZE} from 'app/constants/post_textbox'; import {NOTIFY_ALL_MEMBERS} from 'app/constants/view'; import FileUploadPreview from 'app/components/file_upload_preview'; @@ -239,13 +240,23 @@ export default class PostTextBoxBase extends PureComponent { } }; + startAtMention = () => { + this.handleTextChange(`${this.state.value}@`, true); + this.focus(); + }; + + startSlashCommand = () => { + this.handleTextChange('/', true); + this.focus(); + }; + getTextInputButton = (actionType) => { const {channelIsReadOnly, theme} = this.props; const style = getStyleSheet(theme); let button = null; const buttonStyle = []; - let iconColor = theme.centerChannelColor; + let iconColor = changeOpacity(theme.centerChannelColor, 0.64); let isDisabled = false; if (!channelIsReadOnly) { @@ -253,21 +264,18 @@ export default class PostTextBoxBase extends PureComponent { case 'at': isDisabled = this.state.value[this.state.value.length - 1] === '@'; if (isDisabled) { - iconColor = changeOpacity(theme.centerChannelColor, 0.6); + iconColor = changeOpacity(theme.centerChannelColor, 0.16); } button = ( { - this.handleTextChange(`${this.state.value}@`, true); - this.focus(); - }} + onPress={this.startAtMention} style={style.iconWrapper} > ); @@ -282,10 +290,7 @@ export default class PostTextBoxBase extends PureComponent { button = ( { - this.handleTextChange('/', true); - this.focus(); - }} + onPress={this.startSlashCommand} style={style.iconWrapper} > { const {canUploadFiles, channelIsReadOnly, files, maxFileSize, theme} = this.props; + const style = getStyleSheet(theme); let button = null; const props = { blurTextBox: this.blur, @@ -313,6 +319,7 @@ export default class PostTextBoxBase extends PureComponent { uploadFiles: this.handleUploadFiles, maxFileSize, theme, + buttonContainerStyle: style.iconWrapper, }; if (canUploadFiles && !channelIsReadOnly) { @@ -504,8 +511,20 @@ export default class PostTextBoxBase extends PureComponent { } }; - handleUploadFiles = (files) => { - this.props.actions.initUploadFiles(files, this.props.rootId); + handleUploadFiles = async (files) => { + const file = files[0]; + if (!file.fileSize | !file.fileName) { + const path = (file.path || file.uri).replace('file://', ''); + const fileInfo = await RNFetchBlob.fs.stat(path); + file.fileSize = fileInfo.size; + file.fileName = fileInfo.filename; + } + + if (file.fileSize > this.props.maxFileSize) { + this.onShowFileSizeWarning(file.fileName); + } else { + this.props.actions.initUploadFiles(files, this.props.rootId); + } }; isFileLoading = () => { @@ -722,7 +741,7 @@ export default class PostTextBoxBase extends PureComponent { EventEmitter.emit('fileSizeWarning', fileSizeWarning); setTimeout(() => { EventEmitter.emit('fileSizeWarning', null); - }, 3000); + }, 5000); }; onCloseChannelPress = () => { @@ -835,6 +854,12 @@ export default class PostTextBoxBase extends PureComponent { const textValue = channelIsLoading ? '' : value; const placeholder = this.getPlaceHolder(); + let maxHeight = 150; + + if (isLandscape) { + maxHeight = 88; + } + return ( - - - - - - - {this.getTextInputButton('at')} - - {this.getTextInputButton('slash')} - - {this.getMediaButton('file')} - - {this.getMediaButton('image')} - - {this.getMediaButton('camera')} - - - + - + + + + + {this.getTextInputButton('at')} + + {this.getTextInputButton('slash')} + + {this.getMediaButton('file')} + + {this.getMediaButton('image')} + + {this.getMediaButton('camera')} + + + + + + } ); @@ -910,37 +938,36 @@ const getStyleSheet = makeStyleSheetFromTheme((theme) => { alignItems: 'center', }, slashIcon: { - width: 20, - height: 20, + width: ICON_SIZE, + height: ICON_SIZE, opacity: 1, - tintColor: theme.centerChannelColor, + tintColor: changeOpacity(theme.centerChannelColor, 0.64), }, iconDisabled: { - tintColor: changeOpacity(theme.centerChannelColor, 0.6), + tintColor: changeOpacity(theme.centerChannelColor, 0.16), }, iconWrapper: { - paddingLeft: 10, - paddingRight: 10, + alignItems: 'center', + justifyContent: 'center', + padding: 10, }, quickActionsContainer: { display: 'flex', flexDirection: 'row', + height: 44, }, input: { color: theme.centerChannelColor, - fontSize: 14, - paddingBottom: 8, - paddingLeft: 12, - paddingRight: 12, - paddingTop: 8, - maxHeight: 150, + fontSize: 16, + lineHeight: 20, + paddingHorizontal: 12, + paddingTop: 12, + paddingBottom: 6, + minHeight: 38, }, inputContainer: { flex: 1, flexDirection: 'column', - backgroundColor: theme.centerChannelBg, - marginRight: 10, - marginLeft: 10, }, inputContentContainer: { alignItems: 'stretch', @@ -949,7 +976,7 @@ const getStyleSheet = makeStyleSheetFromTheme((theme) => { alignItems: 'flex-end', flexDirection: 'row', justifyContent: 'center', - paddingVertical: 4, + paddingBottom: 8, backgroundColor: theme.centerChannelBg, borderTopWidth: 1, borderTopColor: changeOpacity(theme.centerChannelColor, 0.20), diff --git a/app/components/send_button.js b/app/components/send_button.js index bf4cee0e4c..b500edbcc2 100644 --- a/app/components/send_button.js +++ b/app/components/send_button.js @@ -2,7 +2,7 @@ // See LICENSE.txt for license information. import React, {memo} from 'react'; -import {Platform, View} from 'react-native'; +import {View} from 'react-native'; import PropTypes from 'prop-types'; import TouchableWithFeedback from 'app/components/touchable_with_feedback'; @@ -18,19 +18,15 @@ function SendButton(props) { PaperPlane = require('app/components/paper_plane').default; } - const icon = ( - - ); - if (props.disabled) { return ( - {icon} + ); @@ -43,7 +39,11 @@ function SendButton(props) { type={'opacity'} > - {icon} + ); @@ -62,20 +62,15 @@ const getStyleSheet = makeStyleSheetFromTheme((theme) => { }, sendButtonContainer: { justifyContent: 'flex-end', - paddingHorizontal: 5, - paddingVertical: Platform.select({ - android: 8, - ios: 2, - }), + paddingRight: 8, }, sendButton: { backgroundColor: theme.buttonBg, borderRadius: 4, - height: 28, - width: 72, + height: 32, + width: 80, alignItems: 'center', justifyContent: 'center', - paddingLeft: 3, }, }; }); diff --git a/app/constants/post_textbox.js b/app/constants/post_textbox.js index 462a4406d9..082ecf56a6 100644 --- a/app/constants/post_textbox.js +++ b/app/constants/post_textbox.js @@ -5,3 +5,4 @@ export const MAX_FILE_COUNT = 5; export const IS_REACTION_REGEX = /(^\+:([^:\s]*):)$/i; export const INSERT_TO_DRAFT = 'insert_to_draft'; export const INSERT_TO_COMMENT = 'insert_to_comment'; +export const ICON_SIZE = 24; \ No newline at end of file diff --git a/app/constants/view.js b/app/constants/view.js index b59639f2f0..34791a1a9e 100644 --- a/app/constants/view.js +++ b/app/constants/view.js @@ -121,6 +121,7 @@ export default { NotificationLevels, SidebarSectionTypes, IOS_HORIZONTAL_LANDSCAPE: 44, - INPUT_LINE_HEIGHT: 17, - INPUT_VERTICAL_PADDING: 16, + INPUT_LINE_HEIGHT: 20, + INPUT_VERTICAL_PADDING: 18, + INPUT_INITIAL_HEIGHT: 38, }; diff --git a/index.js b/index.js index 26d39923fc..e9612ada76 100644 --- a/index.js +++ b/index.js @@ -18,6 +18,7 @@ if (Platform.OS === 'android') { if (__DEV__) { YellowBox.ignoreWarnings([ 'Warning: componentWillReceiveProps', + '`-[RCTRootView cancelTouches]`', // Hide warnings caused by React Native (https://github.com/facebook/react-native/issues/20841) 'Require cycle: node_modules/react-native/Libraries/Network/fetch.js',