diff --git a/app/components/conditionalWrapper.js b/app/components/conditionalWrapper.js
deleted file mode 100644
index bb5dd9f1f..000000000
--- a/app/components/conditionalWrapper.js
+++ /dev/null
@@ -1,5 +0,0 @@
-// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See LICENSE.txt for license information.
-
-/* eslint-disable no-confusing-arrow */
-export const ConditionalWrapper = ({conditional, wrapper, children}) => conditional ? wrapper(children) : children;
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 9270a57e6..19d9b4613 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
@@ -168,12 +168,10 @@ export default class FileUploadItem extends PureComponent {
const realFill = Number(fill.toFixed(0));
return (
-
-
-
- {`${realFill}%`}
-
-
+
+
+ {`${realFill}%`}
+
);
};
@@ -204,8 +202,8 @@ export default class FileUploadItem extends PureComponent {
);
@@ -227,13 +225,12 @@ export default class FileUploadItem extends PureComponent {
{file.loading && !file.failed &&
{this.renderProgress}
@@ -254,51 +251,33 @@ export default class FileUploadItem extends PureComponent {
const getStyleSheet = makeStyleSheetFromTheme((theme) => ({
preview: {
- paddingTop: 12,
+ paddingTop: 5,
marginLeft: 12,
},
previewContainer: {
- height: 64,
- width: 64,
- elevation: 10,
+ height: 56,
+ width: 56,
borderRadius: 4,
},
- progressCircle: {
- alignItems: 'center',
- height: '100%',
- justifyContent: 'center',
- width: '100%',
- },
progressCircleContent: {
alignItems: 'center',
- backgroundColor: 'rgba(0, 0, 0, 0.4)',
- height: 64,
+ backgroundColor: 'rgba(0, 0, 0, 0.7)',
+ height: 56,
+ width: 56,
justifyContent: 'center',
position: 'absolute',
- width: 64,
- },
- progressCirclePercentage: {
- alignItems: 'center',
- flex: 1,
- justifyContent: 'center',
- },
- progressContent: {
- alignItems: 'center',
- height: '100%',
- justifyContent: 'center',
- left: 0,
- position: 'absolute',
- width: '100%',
+ borderRadius: 4,
},
progressText: {
color: 'white',
- fontSize: 18,
+ fontSize: 11,
+ fontWeight: 'bold',
},
filePreview: {
borderColor: changeOpacity(theme.centerChannelColor, 0.15),
- borderRadius: 5,
+ borderRadius: 4,
borderWidth: 1,
- width: 64,
- height: 64,
+ width: 56,
+ height: 56,
},
}));
diff --git a/app/components/file_upload_preview/file_upload_preview.js b/app/components/file_upload_preview/file_upload_preview.js
index 01d460f57..b114e9057 100644
--- a/app/components/file_upload_preview/file_upload_preview.js
+++ b/app/components/file_upload_preview/file_upload_preview.js
@@ -8,6 +8,7 @@ import {
ScrollView,
Text,
View,
+ Platform,
} from 'react-native';
import * as Animatable from 'react-native-animatable';
@@ -18,9 +19,7 @@ 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 showFiles = {opacity: 1, height: 68};
const hideFiles = {opacity: 0, height: 0};
const hideError = {height: 0};
@@ -93,14 +92,9 @@ export default class FileUploadPreview extends PureComponent {
handleFileMaxWarning = () => {
this.setState({showFileMaxWarning: true});
if (this.errorRef.current) {
- this.makeErrorVisible(true, 20, null, () => {
- this.errorRef.current.transition(initial, final, 350, 'ease-in');
- });
+ this.makeErrorVisible(true, 20);
setTimeout(() => {
- this.makeErrorVisible(false, 20, 350, () => {
- this.errorRef.current.transition(final, initial, 350, 'ease-out');
- this.clearErrorsFromState(400);
- });
+ this.makeErrorVisible(false, 20);
}, 5000);
}
};
@@ -108,29 +102,20 @@ export default class FileUploadPreview extends PureComponent {
handleFileSizeWarning = (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');
- });
+ this.setState({fileSizeWarning: message.replace(': ', ':\n')});
+ this.makeErrorVisible(true, 40);
} else {
- this.makeErrorVisible(false, 42, 350, () => {
- this.errorRef.current.transition(final, initial, 350, 'ease-out');
- this.clearErrorsFromState(400);
- });
+ this.makeErrorVisible(false, 20);
}
}
};
- makeErrorVisible = (visible, height, delay, callback) => {
+ makeErrorVisible = (visible, height) => {
if (this.errorContainerRef.current) {
if (visible) {
- this.errorContainerRef.current.transition(hideError, {height}, 100);
- setTimeout(callback, delay || 150);
+ this.errorContainerRef.current.transition(hideError, {height}, 200, 'ease-out');
} else {
- callback();
- setTimeout(() => {
- this.errorContainerRef.current.transition({height}, hideError, 300);
- }, delay || 150);
+ this.errorContainerRef.current.transition({height}, hideError, 200, 'ease-in');
}
}
}
@@ -153,15 +138,18 @@ export default class FileUploadPreview extends PureComponent {
render() {
const {fileSizeWarning, showFileMaxWarning} = this.state;
- const style = getStyleSheet(this.props.theme);
+ const {theme, files} = this.props;
+ const style = getStyleSheet(theme);
+ const fileContainerStyle = {
+ paddingBottom: files.length ? 5 : 0,
+ };
return (
{
display: 'flex',
flexDirection: 'row',
height: 0,
- alignItems: 'center',
},
errorContainer: {
height: 0,
},
errorTextContainer: {
- marginTop: 5,
+ marginTop: Platform.select({
+ ios: 4,
+ android: 2,
+ }),
marginHorizontal: 12,
- opacity: 0,
flex: 1,
},
scrollView: {
diff --git a/app/components/file_upload_preview/file_upload_remove.js b/app/components/file_upload_preview/file_upload_remove.js
index 51dbcfde8..f39c57a87 100644
--- a/app/components/file_upload_preview/file_upload_remove.js
+++ b/app/components/file_upload_preview/file_upload_remove.js
@@ -3,7 +3,7 @@
import React, {PureComponent} from 'react';
import PropTypes from 'prop-types';
-import {View} from 'react-native';
+import {View, Platform} from 'react-native';
import Icon from 'react-native-vector-icons/MaterialCommunityIcons';
import {makeStyleSheetFromTheme, changeOpacity} from 'app/utils/theme';
@@ -37,7 +37,8 @@ export default class FileUploadRemove extends PureComponent {
@@ -50,17 +51,26 @@ const getStyleSheet = makeStyleSheetFromTheme((theme) => {
tappableContainer: {
position: 'absolute',
elevation: 11,
- top: -2,
- right: -16,
+ top: -5,
+ right: -10,
width: 32,
height: 32,
},
removeButton: {
- borderRadius: 20,
+ borderRadius: 12,
alignSelf: 'center',
- paddingTop: 6,
- paddingHorizontal: 1,
+ marginTop: Platform.select({
+ ios: 5.4,
+ android: 4.75,
+ }),
backgroundColor: theme.centerChannelBg,
},
+ removeIcon: {
+ position: 'relative',
+ top: Platform.select({
+ ios: 1,
+ android: 0,
+ }),
+ },
};
});
diff --git a/app/components/file_upload_preview/file_upload_retry.js b/app/components/file_upload_preview/file_upload_retry.js
index e073cefea..781ecf052 100644
--- a/app/components/file_upload_preview/file_upload_retry.js
+++ b/app/components/file_upload_preview/file_upload_retry.js
@@ -29,7 +29,7 @@ export default class FileUploadRetry extends PureComponent {
>
@@ -45,5 +45,6 @@ const style = StyleSheet.create({
width: '100%',
alignItems: 'center',
justifyContent: 'center',
+ borderRadius: 4,
},
});
diff --git a/app/components/pasteable_text_input/__snapshots__/index.test.js.snap b/app/components/pasteable_text_input/__snapshots__/index.test.js.snap
index c5d9cec42..be4db3f1b 100644
--- a/app/components/pasteable_text_input/__snapshots__/index.test.js.snap
+++ b/app/components/pasteable_text_input/__snapshots__/index.test.js.snap
@@ -1,18 +1,12 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`PasteableTextInput should render pasteable text input 1`] = `
-
-
- My Text
-
-
+ My Text
+
`;
diff --git a/app/components/pasteable_text_input/index.js b/app/components/pasteable_text_input/index.js
index abdb0fd98..0f3fe44d2 100644
--- a/app/components/pasteable_text_input/index.js
+++ b/app/components/pasteable_text_input/index.js
@@ -3,10 +3,8 @@
import React from 'react';
import PropTypes from 'prop-types';
-import {Animated, Easing, NativeEventEmitter, NativeModules, Platform, TextInput} from 'react-native';
+import {TextInput, NativeEventEmitter, NativeModules} from 'react-native';
import CustomTextInput from './custom_text_input';
-import {ConditionalWrapper} from 'app/components/conditionalWrapper';
-import {ViewTypes} from 'app/constants';
const {OnPasteEventManager} = NativeModules;
const OnPasteEventEmitter = new NativeEventEmitter(OnPasteEventManager);
@@ -18,8 +16,6 @@ export class PasteableTextInput extends React.PureComponent {
forwardRef: PropTypes.any,
}
- inputHeight = new Animated.Value(ViewTypes.INPUT_INITIAL_HEIGHT);
-
componentDidMount() {
this.subscription = OnPasteEventEmitter.addListener('onPaste', this.onPaste);
}
@@ -35,52 +31,14 @@ export class PasteableTextInput extends React.PureComponent {
return onPaste?.(null, event);
}
- animateHeight = (event) => {
- if (Platform.OS === 'ios') {
- const {height} = event.nativeEvent.contentSize;
- const {style, value} = this.props;
- const newHeight = Math.min(style.maxHeight, height + ViewTypes.INPUT_VERTICAL_PADDING);
-
- 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) => {
- return (
-
- {children}
-
- );
- }
-
render() {
const {forwardRef, ...props} = this.props;
return (
-
-
-
+
);
}
}
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 34227db22..0ede5d69e 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",
- "paddingBottom": 8,
+ "paddingBottom": 2,
},
null,
]
@@ -24,6 +24,7 @@ exports[`PostTextBox should match, full snapshot 1`] = `
contentContainerStyle={
Object {
"alignItems": "stretch",
+ "paddingTop": 7,
}
}
disableScrollViewPanResponder={true}
@@ -50,6 +51,7 @@ exports[`PostTextBox should match, full snapshot 1`] = `
keyboardType="default"
multiline={true}
onChangeText={[Function]}
+ onContentSizeChange={null}
onEndEditing={[Function]}
onPaste={[Function]}
onSelectionChange={[Function]}
@@ -58,13 +60,13 @@ exports[`PostTextBox should match, full snapshot 1`] = `
style={
Object {
"color": "#3d3c40",
- "fontSize": 16,
+ "fontSize": 15,
"lineHeight": 20,
"maxHeight": 150,
- "minHeight": 38,
+ "minHeight": 30,
"paddingBottom": 6,
"paddingHorizontal": 12,
- "paddingTop": 12,
+ "paddingTop": 6,
}
}
underlineColorAndroid="transparent"
@@ -82,6 +84,7 @@ exports[`PostTextBox should match, full snapshot 1`] = `
"display": "flex",
"flexDirection": "row",
"justifyContent": "space-between",
+ "paddingBottom": 1,
}
}
>
diff --git a/app/components/post_textbox/post_textbox_base.js b/app/components/post_textbox/post_textbox_base.js
index 0b3209284..5793486f6 100644
--- a/app/components/post_textbox/post_textbox_base.js
+++ b/app/components/post_textbox/post_textbox_base.js
@@ -8,8 +8,6 @@ import {
AppState,
BackHandler,
findNodeHandle,
- Image,
- InteractionManager,
Keyboard,
NativeModules,
Platform,
@@ -17,6 +15,7 @@ import {
TouchableOpacity,
ScrollView,
View,
+ Image,
} from 'react-native';
import {intlShape} from 'react-intl';
import RNFetchBlob from 'rn-fetch-blob';
@@ -51,6 +50,8 @@ import {
} from 'app/utils/theme';
const {RNTextInputReset} = NativeModules;
+const INPUT_LINE_HEIGHT = 20;
+const EXTRA_INPUT_PADDING = 3;
export default class PostTextBoxBase extends PureComponent {
static propTypes = {
@@ -122,6 +123,7 @@ export default class PostTextBoxBase extends PureComponent {
channelId: props.channelId,
channelTimezoneCount: 0,
longMessageAlertShown: false,
+ extraInputPadding: 0,
};
}
@@ -651,10 +653,26 @@ export default class PostTextBoxBase extends PureComponent {
actions.handleClearFiles(channelId, rootId);
}
- InteractionManager.runAfterInteractions(() => {
+ if (Platform.OS === 'ios') {
+ // On iOS, if the PostTextbox height increases from its
+ // initial height (due to a multiline post or a post whose
+ // message wraps, for example), then when the text is cleared
+ // the PostTextbox height decrease will be animated. This
+ // animation in conjunction with the PostList animation as it
+ // receives the newly created post is causing issues in the iOS
+ // PostList component as it fails to properly react to its content
+ // size changes. While a proper fix is determined for the PostList
+ // component, a small delay in triggering the height decrease
+ // animation gives the PostList enough time to first handle content
+ // size changes from the new post.
+ setTimeout(() => {
+ this.handleTextChange('');
+ this.setState({sendingMessage: false});
+ }, 250);
+ } else {
this.handleTextChange('');
this.setState({sendingMessage: false});
- });
+ }
this.changeDraft('');
@@ -838,6 +856,16 @@ export default class PostTextBoxBase extends PureComponent {
}
};
+ handleInputSizeChange = ({nativeEvent: {contentSize}}) => {
+ const {extraInputPadding} = this.state;
+ const numLines = contentSize.height / INPUT_LINE_HEIGHT;
+ if (numLines >= 2 && extraInputPadding !== EXTRA_INPUT_PADDING) {
+ this.setState({extraInputPadding: EXTRA_INPUT_PADDING});
+ } else if (numLines < 2 && extraInputPadding !== 0) {
+ this.setState({extraInputPadding: 0});
+ }
+ }
+
renderDeactivatedChannel = () => {
const {intl} = this.context;
const style = getStyleSheet(this.props.theme);
@@ -861,7 +889,7 @@ export default class PostTextBoxBase extends PureComponent {
return this.archivedView(theme, style);
}
- const {value} = this.state;
+ const {value, extraInputPadding} = this.state;
const textValue = channelIsLoading ? '' : value;
const placeholder = this.getPlaceHolder();
@@ -871,6 +899,12 @@ export default class PostTextBoxBase extends PureComponent {
maxHeight = 88;
}
+ const inputStyle = {};
+ if (extraInputPadding) {
+ inputStyle.paddingBottom = style.input.paddingBottom + extraInputPadding;
+ inputStyle.paddingTop = style.input.paddingTop + extraInputPadding;
+ }
+
return (
{!channelIsReadOnly &&
@@ -947,6 +982,10 @@ const getStyleSheet = makeStyleSheetFromTheme((theme) => {
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
+ paddingBottom: Platform.select({
+ ios: 1,
+ android: 2,
+ }),
},
slashIcon: {
width: ICON_SIZE,
@@ -969,12 +1008,18 @@ const getStyleSheet = makeStyleSheetFromTheme((theme) => {
},
input: {
color: theme.centerChannelColor,
- fontSize: 16,
- lineHeight: 20,
+ fontSize: 15,
+ lineHeight: INPUT_LINE_HEIGHT,
paddingHorizontal: 12,
- paddingTop: 12,
- paddingBottom: 6,
- minHeight: 38,
+ paddingTop: Platform.select({
+ ios: 6,
+ android: 8,
+ }),
+ paddingBottom: Platform.select({
+ ios: 6,
+ android: 2,
+ }),
+ minHeight: 30,
},
inputContainer: {
flex: 1,
@@ -982,12 +1027,16 @@ const getStyleSheet = makeStyleSheetFromTheme((theme) => {
},
inputContentContainer: {
alignItems: 'stretch',
+ paddingTop: Platform.select({
+ ios: 7,
+ android: 0,
+ }),
},
inputWrapper: {
alignItems: 'flex-end',
flexDirection: 'row',
justifyContent: 'center',
- paddingBottom: 8,
+ paddingBottom: 2,
backgroundColor: theme.centerChannelBg,
borderTopWidth: 1,
borderTopColor: changeOpacity(theme.centerChannelColor, 0.20),
diff --git a/app/constants/view.js b/app/constants/view.js
index 34791a1a9..9bb077a31 100644
--- a/app/constants/view.js
+++ b/app/constants/view.js
@@ -121,7 +121,4 @@ export default {
NotificationLevels,
SidebarSectionTypes,
IOS_HORIZONTAL_LANDSCAPE: 44,
- INPUT_LINE_HEIGHT: 20,
- INPUT_VERTICAL_PADDING: 18,
- INPUT_INITIAL_HEIGHT: 38,
};