forked from Ivasoft/mattermost-mobile
Fixing post draft style to comply with design specs (#3818)
* Polishing post draft to comply with design specs * changed maxHeight in landscape mode, fixed icon sizes - Refactored code so that post draft icon sizes are taken from same constant value - Set maxHeight value in landscape mode to be smaller (tests pending) - Removed repeated styles for button wrappers (passing them down as props to child components) - Increased size of image attachment remote icon, and increased tappable area * Removing repeated logic for file upload * Fixing failed snapshot tests / style checks * Fixing file upload remove icon to have 64% opacity * post draft UX/UI improvements * Fix input box extra spacing * input box line height and attachment border * Animate to original state even if error is showing * Fix permissions * Improve attachment error animation * Fix iOS post input height * Update snapshots
This commit is contained in:
committed by
Amit Uttam
parent
e05207412f
commit
0b81a9b4e0
@@ -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`] = `
|
||||
}
|
||||
>
|
||||
<PaperPlane
|
||||
color="#ffffff"
|
||||
height={13}
|
||||
width={15}
|
||||
color="rgba(255,255,255,0.5)"
|
||||
height={16}
|
||||
width={19}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
@@ -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,
|
||||
}
|
||||
}
|
||||
>
|
||||
<PaperPlane
|
||||
color="#ffffff"
|
||||
height={13}
|
||||
width={15}
|
||||
height={16}
|
||||
width={19}
|
||||
/>
|
||||
</View>
|
||||
</TouchableWithFeedbackIOS>
|
||||
@@ -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,
|
||||
}
|
||||
}
|
||||
>
|
||||
<PaperPlane
|
||||
color="#ffffff"
|
||||
height={13}
|
||||
width={15}
|
||||
height={16}
|
||||
width={19}
|
||||
/>
|
||||
</View>
|
||||
</TouchableWithFeedbackIOS>
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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 = (
|
||||
<FileAttachmentImage
|
||||
file={file}
|
||||
theme={theme}
|
||||
/>
|
||||
<View style={styles.filePreview}>
|
||||
<FileAttachmentImage
|
||||
file={file}
|
||||
theme={theme}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
} else {
|
||||
filePreviewComponent = (
|
||||
<FileAttachmentIcon
|
||||
file={file}
|
||||
theme={theme}
|
||||
wrapperHeight={100}
|
||||
wrapperWidth={100}
|
||||
/>
|
||||
<View style={styles.filePreview}>
|
||||
<FileAttachmentIcon
|
||||
file={file}
|
||||
theme={theme}
|
||||
wrapperHeight={60}
|
||||
wrapperWidth={60}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -209,7 +216,7 @@ export default class FileUploadItem extends PureComponent {
|
||||
key={file.clientId}
|
||||
style={styles.preview}
|
||||
>
|
||||
<View style={styles.previewShadow}>
|
||||
<View style={styles.previewContainer}>
|
||||
{filePreviewComponent}
|
||||
{file.failed &&
|
||||
<FileUploadRetry
|
||||
@@ -220,7 +227,7 @@ export default class FileUploadItem extends PureComponent {
|
||||
{file.loading && !file.failed &&
|
||||
<View style={styles.progressCircleContent}>
|
||||
<AnimatedCircularProgress
|
||||
size={100}
|
||||
size={64}
|
||||
fill={progress}
|
||||
width={4}
|
||||
backgroundColor='rgba(255, 255, 255, 0.5)'
|
||||
@@ -245,29 +252,16 @@ export default class FileUploadItem extends PureComponent {
|
||||
}
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
const getStyleSheet = makeStyleSheetFromTheme((theme) => ({
|
||||
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,
|
||||
},
|
||||
}));
|
||||
|
||||
@@ -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', () => {
|
||||
|
||||
@@ -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 (
|
||||
<View style={style.previewContainer}>
|
||||
<View style={style.fileContainer}>
|
||||
<Animatable.View
|
||||
style={style.fileContainer}
|
||||
ref={this.containerRef}
|
||||
isInteraction={true}
|
||||
duration={300}
|
||||
>
|
||||
<ScrollView
|
||||
horizontal={true}
|
||||
style={style.scrollView}
|
||||
@@ -97,21 +171,32 @@ export default class FileUploadPreview extends PureComponent {
|
||||
>
|
||||
{this.buildFilePreviews()}
|
||||
</ScrollView>
|
||||
</View>
|
||||
<View style={style.errorContainer}>
|
||||
{showFileMaxWarning && (
|
||||
<FormattedText
|
||||
style={style.warning}
|
||||
id='mobile.file_upload.max_warning'
|
||||
defaultMessage='Uploads limited to 5 files maximum.'
|
||||
/>
|
||||
)}
|
||||
{Boolean(fileSizeWarning) &&
|
||||
<Text style={style.warning}>
|
||||
{fileSizeWarning}
|
||||
</Text>
|
||||
}
|
||||
</View>
|
||||
</Animatable.View>
|
||||
<Animatable.View
|
||||
ref={this.errorContainerRef}
|
||||
style={style.errorContainer}
|
||||
isInteraction={true}
|
||||
>
|
||||
<Animatable.View
|
||||
ref={this.errorRef}
|
||||
isInteraction={true}
|
||||
style={style.errorTextContainer}
|
||||
useNativeDriver={true}
|
||||
>
|
||||
{showFileMaxWarning && (
|
||||
<FormattedText
|
||||
style={style.warning}
|
||||
id='mobile.file_upload.max_warning'
|
||||
defaultMessage='Uploads limited to 5 files maximum.'
|
||||
/>
|
||||
)}
|
||||
{Boolean(fileSizeWarning) &&
|
||||
<Text style={style.warning}>
|
||||
{fileSizeWarning}
|
||||
</Text>
|
||||
}
|
||||
</Animatable.View>
|
||||
</Animatable.View>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
@@ -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',
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
@@ -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 (
|
||||
<TouchableWithFeedback
|
||||
style={style.removeButtonWrapper}
|
||||
style={style.tappableContainer}
|
||||
onPress={this.handleOnPress}
|
||||
type={'opacity'}
|
||||
>
|
||||
<Icon
|
||||
name='close-circle'
|
||||
color={this.props.theme.centerChannelColor}
|
||||
size={20}
|
||||
style={style.removeButtonIcon}
|
||||
/>
|
||||
<View style={style.removeButton}>
|
||||
<Icon
|
||||
name='close-circle'
|
||||
color={changeOpacity(theme.centerChannelColor, 0.64)}
|
||||
size={18}
|
||||
/>
|
||||
</View>
|
||||
</TouchableWithFeedback>
|
||||
);
|
||||
}
|
||||
@@ -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,
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
@@ -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 <Animated.View style={{flex: 1, height: inputHeight}}>{children}</Animated.View>;
|
||||
return (
|
||||
<Animated.View
|
||||
ref={this.containerRef}
|
||||
style={{height: this.inputHeight}}
|
||||
>
|
||||
{children}
|
||||
</Animated.View>
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
|
||||
@@ -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=""
|
||||
/>
|
||||
<Connect(FileUploadPreview)
|
||||
files={Array []}
|
||||
rootId=""
|
||||
/>
|
||||
<View
|
||||
style={
|
||||
Object {
|
||||
"alignItems": "center",
|
||||
"display": "flex",
|
||||
"flexDirection": "row",
|
||||
"justifyContent": "space-between",
|
||||
}
|
||||
}
|
||||
>
|
||||
<React.Fragment>
|
||||
<Connect(FileUploadPreview)
|
||||
files={Array []}
|
||||
rootId=""
|
||||
/>
|
||||
<View
|
||||
style={
|
||||
Object {
|
||||
"alignItems": "center",
|
||||
"display": "flex",
|
||||
"flexDirection": "row",
|
||||
"justifyContent": "space-between",
|
||||
}
|
||||
}
|
||||
>
|
||||
<TouchableOpacity
|
||||
activeOpacity={0.2}
|
||||
disabled={false}
|
||||
onPress={[Function]}
|
||||
<View
|
||||
style={
|
||||
Object {
|
||||
"paddingLeft": 10,
|
||||
"paddingRight": 10,
|
||||
"display": "flex",
|
||||
"flexDirection": "row",
|
||||
"height": 44,
|
||||
}
|
||||
}
|
||||
>
|
||||
<Icon
|
||||
allowFontScaling={false}
|
||||
color="#3d3c40"
|
||||
name="at"
|
||||
size={20}
|
||||
/>
|
||||
</TouchableOpacity>
|
||||
<TouchableOpacity
|
||||
activeOpacity={0.2}
|
||||
disabled={false}
|
||||
onPress={[Function]}
|
||||
style={
|
||||
Object {
|
||||
"paddingLeft": 10,
|
||||
"paddingRight": 10,
|
||||
}
|
||||
}
|
||||
>
|
||||
<Image
|
||||
source={
|
||||
<TouchableOpacity
|
||||
activeOpacity={0.2}
|
||||
disabled={false}
|
||||
onPress={[Function]}
|
||||
style={
|
||||
Object {
|
||||
"testUri": "../../../dist/assets/images/icons/slash-forward-box.png",
|
||||
"alignItems": "center",
|
||||
"justifyContent": "center",
|
||||
"padding": 10,
|
||||
}
|
||||
}
|
||||
>
|
||||
<Icon
|
||||
allowFontScaling={false}
|
||||
color="rgba(61,60,64,0.64)"
|
||||
name="at"
|
||||
size={24}
|
||||
/>
|
||||
</TouchableOpacity>
|
||||
<TouchableOpacity
|
||||
activeOpacity={0.2}
|
||||
disabled={false}
|
||||
onPress={[Function]}
|
||||
style={
|
||||
Array [
|
||||
Object {
|
||||
"alignItems": "center",
|
||||
"justifyContent": "center",
|
||||
"padding": 10,
|
||||
}
|
||||
}
|
||||
>
|
||||
<Image
|
||||
source={
|
||||
Object {
|
||||
"height": 20,
|
||||
"opacity": 1,
|
||||
"tintColor": "#3d3c40",
|
||||
"width": 20,
|
||||
},
|
||||
]
|
||||
"testUri": "../../../dist/assets/images/icons/slash-forward-box.png",
|
||||
}
|
||||
}
|
||||
style={
|
||||
Array [
|
||||
Object {
|
||||
"height": 24,
|
||||
"opacity": 1,
|
||||
"tintColor": "rgba(61,60,64,0.64)",
|
||||
"width": 24,
|
||||
},
|
||||
]
|
||||
}
|
||||
/>
|
||||
</TouchableOpacity>
|
||||
<FileUploadButton
|
||||
blurTextBox={[Function]}
|
||||
browseFileTypes="public.item"
|
||||
buttonContainerStyle={
|
||||
Object {
|
||||
"alignItems": "center",
|
||||
"justifyContent": "center",
|
||||
"padding": 10,
|
||||
}
|
||||
}
|
||||
canBrowseFiles={true}
|
||||
canBrowsePhotoLibrary={true}
|
||||
canBrowseVideoLibrary={true}
|
||||
canTakePhoto={true}
|
||||
canTakeVideo={true}
|
||||
extraOptions={null}
|
||||
fileCount={0}
|
||||
maxFileCount={5}
|
||||
maxFileSize={1024}
|
||||
onShowFileMaxWarning={[Function]}
|
||||
onShowFileSizeWarning={[Function]}
|
||||
theme={
|
||||
Object {
|
||||
"awayIndicator": "#ffbc42",
|
||||
"buttonBg": "#166de0",
|
||||
"buttonColor": "#ffffff",
|
||||
"centerChannelBg": "#ffffff",
|
||||
"centerChannelColor": "#3d3c40",
|
||||
"codeTheme": "github",
|
||||
"dndIndicator": "#f74343",
|
||||
"errorTextColor": "#fd5960",
|
||||
"linkColor": "#2389d7",
|
||||
"mentionBg": "#ffffff",
|
||||
"mentionBj": "#ffffff",
|
||||
"mentionColor": "#145dbf",
|
||||
"mentionHighlightBg": "#ffe577",
|
||||
"mentionHighlightLink": "#166de0",
|
||||
"newMessageSeparator": "#ff8800",
|
||||
"onlineIndicator": "#06d6a0",
|
||||
"sidebarBg": "#145dbf",
|
||||
"sidebarHeaderBg": "#1153ab",
|
||||
"sidebarHeaderTextColor": "#ffffff",
|
||||
"sidebarText": "#ffffff",
|
||||
"sidebarTextActiveBorder": "#579eff",
|
||||
"sidebarTextActiveColor": "#ffffff",
|
||||
"sidebarTextHoverBg": "#4578bf",
|
||||
"sidebarUnreadText": "#ffffff",
|
||||
"type": "Mattermost",
|
||||
}
|
||||
}
|
||||
uploadFiles={[Function]}
|
||||
validMimeTypes={Array []}
|
||||
/>
|
||||
</TouchableOpacity>
|
||||
<FileUploadButton
|
||||
blurTextBox={[Function]}
|
||||
browseFileTypes="public.item"
|
||||
canBrowseFiles={true}
|
||||
canBrowsePhotoLibrary={true}
|
||||
canBrowseVideoLibrary={true}
|
||||
canTakePhoto={true}
|
||||
canTakeVideo={true}
|
||||
extraOptions={null}
|
||||
fileCount={0}
|
||||
maxFileCount={5}
|
||||
maxFileSize={1024}
|
||||
onShowFileMaxWarning={[Function]}
|
||||
onShowFileSizeWarning={[Function]}
|
||||
<ImageUploadButton
|
||||
blurTextBox={[Function]}
|
||||
browseFileTypes="public.item"
|
||||
buttonContainerStyle={
|
||||
Object {
|
||||
"alignItems": "center",
|
||||
"justifyContent": "center",
|
||||
"padding": 10,
|
||||
}
|
||||
}
|
||||
canBrowseFiles={true}
|
||||
canBrowsePhotoLibrary={true}
|
||||
canBrowseVideoLibrary={true}
|
||||
canTakePhoto={true}
|
||||
canTakeVideo={true}
|
||||
extraOptions={null}
|
||||
fileCount={0}
|
||||
maxFileCount={5}
|
||||
maxFileSize={1024}
|
||||
onShowFileMaxWarning={[Function]}
|
||||
onShowFileSizeWarning={[Function]}
|
||||
theme={
|
||||
Object {
|
||||
"awayIndicator": "#ffbc42",
|
||||
"buttonBg": "#166de0",
|
||||
"buttonColor": "#ffffff",
|
||||
"centerChannelBg": "#ffffff",
|
||||
"centerChannelColor": "#3d3c40",
|
||||
"codeTheme": "github",
|
||||
"dndIndicator": "#f74343",
|
||||
"errorTextColor": "#fd5960",
|
||||
"linkColor": "#2389d7",
|
||||
"mentionBg": "#ffffff",
|
||||
"mentionBj": "#ffffff",
|
||||
"mentionColor": "#145dbf",
|
||||
"mentionHighlightBg": "#ffe577",
|
||||
"mentionHighlightLink": "#166de0",
|
||||
"newMessageSeparator": "#ff8800",
|
||||
"onlineIndicator": "#06d6a0",
|
||||
"sidebarBg": "#145dbf",
|
||||
"sidebarHeaderBg": "#1153ab",
|
||||
"sidebarHeaderTextColor": "#ffffff",
|
||||
"sidebarText": "#ffffff",
|
||||
"sidebarTextActiveBorder": "#579eff",
|
||||
"sidebarTextActiveColor": "#ffffff",
|
||||
"sidebarTextHoverBg": "#4578bf",
|
||||
"sidebarUnreadText": "#ffffff",
|
||||
"type": "Mattermost",
|
||||
}
|
||||
}
|
||||
uploadFiles={[Function]}
|
||||
validMimeTypes={Array []}
|
||||
/>
|
||||
<AttachmentButton
|
||||
blurTextBox={[Function]}
|
||||
buttonContainerStyle={
|
||||
Object {
|
||||
"alignItems": "center",
|
||||
"justifyContent": "center",
|
||||
"padding": 10,
|
||||
}
|
||||
}
|
||||
canTakePhoto={true}
|
||||
canTakeVideo={true}
|
||||
fileCount={0}
|
||||
maxFileCount={5}
|
||||
maxFileSize={1024}
|
||||
onShowFileMaxWarning={[Function]}
|
||||
onShowFileSizeWarning={[Function]}
|
||||
theme={
|
||||
Object {
|
||||
"awayIndicator": "#ffbc42",
|
||||
"buttonBg": "#166de0",
|
||||
"buttonColor": "#ffffff",
|
||||
"centerChannelBg": "#ffffff",
|
||||
"centerChannelColor": "#3d3c40",
|
||||
"codeTheme": "github",
|
||||
"dndIndicator": "#f74343",
|
||||
"errorTextColor": "#fd5960",
|
||||
"linkColor": "#2389d7",
|
||||
"mentionBg": "#ffffff",
|
||||
"mentionBj": "#ffffff",
|
||||
"mentionColor": "#145dbf",
|
||||
"mentionHighlightBg": "#ffe577",
|
||||
"mentionHighlightLink": "#166de0",
|
||||
"newMessageSeparator": "#ff8800",
|
||||
"onlineIndicator": "#06d6a0",
|
||||
"sidebarBg": "#145dbf",
|
||||
"sidebarHeaderBg": "#1153ab",
|
||||
"sidebarHeaderTextColor": "#ffffff",
|
||||
"sidebarText": "#ffffff",
|
||||
"sidebarTextActiveBorder": "#579eff",
|
||||
"sidebarTextActiveColor": "#ffffff",
|
||||
"sidebarTextHoverBg": "#4578bf",
|
||||
"sidebarUnreadText": "#ffffff",
|
||||
"type": "Mattermost",
|
||||
}
|
||||
}
|
||||
uploadFiles={[Function]}
|
||||
validMimeTypes={Array []}
|
||||
/>
|
||||
</View>
|
||||
<SendButton
|
||||
disabled={true}
|
||||
handleSendMessage={[Function]}
|
||||
theme={
|
||||
Object {
|
||||
"awayIndicator": "#ffbc42",
|
||||
@@ -184,131 +330,9 @@ exports[`PostTextBox should match, full snapshot 1`] = `
|
||||
"type": "Mattermost",
|
||||
}
|
||||
}
|
||||
uploadFiles={[Function]}
|
||||
validMimeTypes={Array []}
|
||||
/>
|
||||
<ImageUploadButton
|
||||
blurTextBox={[Function]}
|
||||
browseFileTypes="public.item"
|
||||
canBrowseFiles={true}
|
||||
canBrowsePhotoLibrary={true}
|
||||
canBrowseVideoLibrary={true}
|
||||
canTakePhoto={true}
|
||||
canTakeVideo={true}
|
||||
extraOptions={null}
|
||||
fileCount={0}
|
||||
maxFileCount={5}
|
||||
maxFileSize={1024}
|
||||
onShowFileMaxWarning={[Function]}
|
||||
onShowFileSizeWarning={[Function]}
|
||||
theme={
|
||||
Object {
|
||||
"awayIndicator": "#ffbc42",
|
||||
"buttonBg": "#166de0",
|
||||
"buttonColor": "#ffffff",
|
||||
"centerChannelBg": "#ffffff",
|
||||
"centerChannelColor": "#3d3c40",
|
||||
"codeTheme": "github",
|
||||
"dndIndicator": "#f74343",
|
||||
"errorTextColor": "#fd5960",
|
||||
"linkColor": "#2389d7",
|
||||
"mentionBg": "#ffffff",
|
||||
"mentionBj": "#ffffff",
|
||||
"mentionColor": "#145dbf",
|
||||
"mentionHighlightBg": "#ffe577",
|
||||
"mentionHighlightLink": "#166de0",
|
||||
"newMessageSeparator": "#ff8800",
|
||||
"onlineIndicator": "#06d6a0",
|
||||
"sidebarBg": "#145dbf",
|
||||
"sidebarHeaderBg": "#1153ab",
|
||||
"sidebarHeaderTextColor": "#ffffff",
|
||||
"sidebarText": "#ffffff",
|
||||
"sidebarTextActiveBorder": "#579eff",
|
||||
"sidebarTextActiveColor": "#ffffff",
|
||||
"sidebarTextHoverBg": "#4578bf",
|
||||
"sidebarUnreadText": "#ffffff",
|
||||
"type": "Mattermost",
|
||||
}
|
||||
}
|
||||
uploadFiles={[Function]}
|
||||
validMimeTypes={Array []}
|
||||
/>
|
||||
<AttachmentButton
|
||||
blurTextBox={[Function]}
|
||||
canTakePhoto={true}
|
||||
canTakeVideo={true}
|
||||
fileCount={0}
|
||||
maxFileCount={5}
|
||||
maxFileSize={1024}
|
||||
onShowFileMaxWarning={[Function]}
|
||||
onShowFileSizeWarning={[Function]}
|
||||
theme={
|
||||
Object {
|
||||
"awayIndicator": "#ffbc42",
|
||||
"buttonBg": "#166de0",
|
||||
"buttonColor": "#ffffff",
|
||||
"centerChannelBg": "#ffffff",
|
||||
"centerChannelColor": "#3d3c40",
|
||||
"codeTheme": "github",
|
||||
"dndIndicator": "#f74343",
|
||||
"errorTextColor": "#fd5960",
|
||||
"linkColor": "#2389d7",
|
||||
"mentionBg": "#ffffff",
|
||||
"mentionBj": "#ffffff",
|
||||
"mentionColor": "#145dbf",
|
||||
"mentionHighlightBg": "#ffe577",
|
||||
"mentionHighlightLink": "#166de0",
|
||||
"newMessageSeparator": "#ff8800",
|
||||
"onlineIndicator": "#06d6a0",
|
||||
"sidebarBg": "#145dbf",
|
||||
"sidebarHeaderBg": "#1153ab",
|
||||
"sidebarHeaderTextColor": "#ffffff",
|
||||
"sidebarText": "#ffffff",
|
||||
"sidebarTextActiveBorder": "#579eff",
|
||||
"sidebarTextActiveColor": "#ffffff",
|
||||
"sidebarTextHoverBg": "#4578bf",
|
||||
"sidebarUnreadText": "#ffffff",
|
||||
"type": "Mattermost",
|
||||
}
|
||||
}
|
||||
uploadFiles={[Function]}
|
||||
validMimeTypes={Array []}
|
||||
/>
|
||||
</View>
|
||||
<SendButton
|
||||
disabled={true}
|
||||
handleSendMessage={[Function]}
|
||||
theme={
|
||||
Object {
|
||||
"awayIndicator": "#ffbc42",
|
||||
"buttonBg": "#166de0",
|
||||
"buttonColor": "#ffffff",
|
||||
"centerChannelBg": "#ffffff",
|
||||
"centerChannelColor": "#3d3c40",
|
||||
"codeTheme": "github",
|
||||
"dndIndicator": "#f74343",
|
||||
"errorTextColor": "#fd5960",
|
||||
"linkColor": "#2389d7",
|
||||
"mentionBg": "#ffffff",
|
||||
"mentionBj": "#ffffff",
|
||||
"mentionColor": "#145dbf",
|
||||
"mentionHighlightBg": "#ffe577",
|
||||
"mentionHighlightLink": "#166de0",
|
||||
"newMessageSeparator": "#ff8800",
|
||||
"onlineIndicator": "#06d6a0",
|
||||
"sidebarBg": "#145dbf",
|
||||
"sidebarHeaderBg": "#1153ab",
|
||||
"sidebarHeaderTextColor": "#ffffff",
|
||||
"sidebarText": "#ffffff",
|
||||
"sidebarTextActiveBorder": "#579eff",
|
||||
"sidebarTextActiveColor": "#ffffff",
|
||||
"sidebarTextHoverBg": "#4578bf",
|
||||
"sidebarUnreadText": "#ffffff",
|
||||
"type": "Mattermost",
|
||||
}
|
||||
}
|
||||
/>
|
||||
</View>
|
||||
</React.Fragment>
|
||||
</ScrollView>
|
||||
</View>
|
||||
</React.Fragment>
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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 = (
|
||||
<TouchableOpacity
|
||||
disabled={isDisabled}
|
||||
onPress={() => {
|
||||
this.handleTextChange(`${this.state.value}@`, true);
|
||||
this.focus();
|
||||
}}
|
||||
onPress={this.startAtMention}
|
||||
style={style.iconWrapper}
|
||||
>
|
||||
<MaterialCommunityIcons
|
||||
color={iconColor}
|
||||
name='at'
|
||||
size={20}
|
||||
size={ICON_SIZE}
|
||||
/>
|
||||
</TouchableOpacity>
|
||||
);
|
||||
@@ -282,10 +290,7 @@ export default class PostTextBoxBase extends PureComponent {
|
||||
button = (
|
||||
<TouchableOpacity
|
||||
disabled={isDisabled}
|
||||
onPress={() => {
|
||||
this.handleTextChange('/', true);
|
||||
this.focus();
|
||||
}}
|
||||
onPress={this.startSlashCommand}
|
||||
style={style.iconWrapper}
|
||||
>
|
||||
<Image
|
||||
@@ -303,6 +308,7 @@ export default class PostTextBoxBase extends PureComponent {
|
||||
|
||||
getMediaButton = (actionType) => {
|
||||
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 (
|
||||
<View
|
||||
style={[style.inputWrapper, padding(isLandscape)]}
|
||||
@@ -861,7 +886,7 @@ export default class PostTextBoxBase extends PureComponent {
|
||||
multiline={true}
|
||||
blurOnSubmit={false}
|
||||
underlineColorAndroid='transparent'
|
||||
style={style.input}
|
||||
style={{...style.input, maxHeight}}
|
||||
keyboardType={this.state.keyboardType}
|
||||
onEndEditing={this.handleEndEditing}
|
||||
disableFullscreenUI={true}
|
||||
@@ -869,32 +894,35 @@ export default class PostTextBoxBase extends PureComponent {
|
||||
onPaste={this.handlePasteFiles}
|
||||
keyboardAppearance={getKeyboardAppearanceFromTheme(theme)}
|
||||
/>
|
||||
|
||||
<FileUploadPreview
|
||||
files={files}
|
||||
rootId={rootId}
|
||||
/>
|
||||
|
||||
<View style={style.buttonsContainer}>
|
||||
<View style={style.quickActionsContainer}>
|
||||
|
||||
{this.getTextInputButton('at')}
|
||||
|
||||
{this.getTextInputButton('slash')}
|
||||
|
||||
{this.getMediaButton('file')}
|
||||
|
||||
{this.getMediaButton('image')}
|
||||
|
||||
{this.getMediaButton('camera')}
|
||||
|
||||
</View>
|
||||
<SendButton
|
||||
disabled={!this.isSendButtonEnabled()}
|
||||
handleSendMessage={this.handleSendMessage}
|
||||
theme={theme}
|
||||
{!channelIsReadOnly &&
|
||||
<React.Fragment>
|
||||
<FileUploadPreview
|
||||
files={files}
|
||||
rootId={rootId}
|
||||
/>
|
||||
</View>
|
||||
|
||||
<View style={style.buttonsContainer}>
|
||||
<View style={style.quickActionsContainer}>
|
||||
|
||||
{this.getTextInputButton('at')}
|
||||
|
||||
{this.getTextInputButton('slash')}
|
||||
|
||||
{this.getMediaButton('file')}
|
||||
|
||||
{this.getMediaButton('image')}
|
||||
|
||||
{this.getMediaButton('camera')}
|
||||
|
||||
</View>
|
||||
<SendButton
|
||||
disabled={!this.isSendButtonEnabled()}
|
||||
handleSendMessage={this.handleSendMessage}
|
||||
theme={theme}
|
||||
/>
|
||||
</View>
|
||||
</React.Fragment>
|
||||
}
|
||||
</ScrollView>
|
||||
</View>
|
||||
);
|
||||
@@ -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),
|
||||
|
||||
@@ -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 = (
|
||||
<PaperPlane
|
||||
height={13}
|
||||
width={15}
|
||||
color={theme.buttonColor}
|
||||
/>
|
||||
);
|
||||
|
||||
if (props.disabled) {
|
||||
return (
|
||||
<View style={style.sendButtonContainer}>
|
||||
<View style={[style.sendButton, style.disableButton]}>
|
||||
{icon}
|
||||
<PaperPlane
|
||||
height={16}
|
||||
width={19}
|
||||
color={changeOpacity(theme.buttonColor, 0.5)}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
@@ -43,7 +39,11 @@ function SendButton(props) {
|
||||
type={'opacity'}
|
||||
>
|
||||
<View style={style.sendButton}>
|
||||
{icon}
|
||||
<PaperPlane
|
||||
height={16}
|
||||
width={19}
|
||||
color={theme.buttonColor}
|
||||
/>
|
||||
</View>
|
||||
</TouchableWithFeedback>
|
||||
);
|
||||
@@ -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,
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
@@ -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;
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
1
index.js
1
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',
|
||||
|
||||
Reference in New Issue
Block a user