diff --git a/app/components/__snapshots__/send_button.test.js.snap b/app/components/__snapshots__/send_button.test.js.snap
index 37886e755..24b03107c 100644
--- a/app/components/__snapshots__/send_button.test.js.snap
+++ b/app/components/__snapshots__/send_button.test.js.snap
@@ -37,8 +37,7 @@ exports[`SendButton should change theme backgroundColor to 0.3 opacity 1`] = `
`;
exports[`SendButton should match snapshot 1`] = `
-
-
+
`;
exports[`SendButton should render theme backgroundColor 1`] = `
-
-
+
`;
diff --git a/app/components/attachment_button/__snapshots__/attachment_button.test.js.snap b/app/components/attachment_button/__snapshots__/attachment_button.test.js.snap
index accd5a17b..ecb7cc3f7 100644
--- a/app/components/attachment_button/__snapshots__/attachment_button.test.js.snap
+++ b/app/components/attachment_button/__snapshots__/attachment_button.test.js.snap
@@ -1,8 +1,7 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`AttachmentButton should match snapshot 1`] = `
-
-
+
`;
diff --git a/app/components/attachment_button/attachment_button.js b/app/components/attachment_button/attachment_button.js
index 92e5c1af9..f6128a171 100644
--- a/app/components/attachment_button/attachment_button.js
+++ b/app/components/attachment_button/attachment_button.js
@@ -8,7 +8,6 @@ import {
NativeModules,
Platform,
StyleSheet,
- TouchableOpacity,
} from 'react-native';
import RNFetchBlob from 'rn-fetch-blob';
import DeviceInfo from 'react-native-device-info';
@@ -21,6 +20,7 @@ import Permissions from 'react-native-permissions';
import {lookupMimeType} from 'mattermost-redux/utils/file_utils';
+import TouchableWithFeedback from 'app/components/touchable_with_feedback';
import {PermissionTypes} from 'app/constants';
import {changeOpacity} from 'app/utils/theme';
import {t} from 'app/utils/i18n';
@@ -493,18 +493,20 @@ export default class AttachmentButton extends PureComponent {
if (wrapper) {
return (
-
{children}
-
+
);
}
return (
-
-
+
);
}
}
diff --git a/app/components/autocomplete/at_mention_item/at_mention_item.js b/app/components/autocomplete/at_mention_item/at_mention_item.js
index fcdb6573e..9592d3093 100644
--- a/app/components/autocomplete/at_mention_item/at_mention_item.js
+++ b/app/components/autocomplete/at_mention_item/at_mention_item.js
@@ -5,13 +5,13 @@ import React, {PureComponent} from 'react';
import PropTypes from 'prop-types';
import {
Text,
- TouchableOpacity,
View,
} from 'react-native';
import ProfilePicture from 'app/components/profile_picture';
import BotTag from 'app/components/bot_tag';
import GuestTag from 'app/components/guest_tag';
+import TouchableWithFeedback from 'app/components/touchable_with_feedback';
import {makeStyleSheetFromTheme} from 'app/utils/theme';
import {paddingHorizontal as padding} from 'app/components/safe_area_view/iphone_x_spacing';
@@ -54,10 +54,11 @@ export default class AtMentionItem extends PureComponent {
const hasFullName = firstName.length > 0 && lastName.length > 0;
return (
-
{hasFullName && {' - '}}
{hasFullName && {`${firstName} ${lastName}`}}
-
+
);
}
}
diff --git a/app/components/autocomplete/channel_mention_item/channel_mention_item.js b/app/components/autocomplete/channel_mention_item/channel_mention_item.js
index cbf2f95c4..b110f26cf 100644
--- a/app/components/autocomplete/channel_mention_item/channel_mention_item.js
+++ b/app/components/autocomplete/channel_mention_item/channel_mention_item.js
@@ -5,14 +5,13 @@ import React, {PureComponent} from 'react';
import PropTypes from 'prop-types';
import {
Text,
- TouchableOpacity,
} from 'react-native';
import {General} from 'mattermost-redux/constants';
import BotTag from 'app/components/bot_tag';
-import {paddingHorizontal as padding} from 'app/components/safe_area_view/iphone_x_spacing';
import GuestTag from 'app/components/guest_tag';
-
+import {paddingHorizontal as padding} from 'app/components/safe_area_view/iphone_x_spacing';
+import TouchableWithFeedback from 'app/components/touchable_with_feedback';
import {makeStyleSheetFromTheme} from 'app/utils/theme';
export default class ChannelMentionItem extends PureComponent {
@@ -56,10 +55,11 @@ export default class ChannelMentionItem extends PureComponent {
return null;
}
return (
-
{'@' + displayName}
-
+
);
}
return (
-
{displayName}
{` (~${name})`}
-
+
);
}
}
diff --git a/app/components/autocomplete/emoji_suggestion/emoji_suggestion.js b/app/components/autocomplete/emoji_suggestion/emoji_suggestion.js
index 00cecd461..a03ab05a7 100644
--- a/app/components/autocomplete/emoji_suggestion/emoji_suggestion.js
+++ b/app/components/autocomplete/emoji_suggestion/emoji_suggestion.js
@@ -7,7 +7,6 @@ import {
FlatList,
Platform,
Text,
- TouchableOpacity,
View,
} from 'react-native';
@@ -15,6 +14,7 @@ import {isMinimumServerVersion} from 'mattermost-redux/utils/helpers';
import AutocompleteDivider from 'app/components/autocomplete/autocomplete_divider';
import Emoji from 'app/components/emoji';
+import TouchableWithFeedback from 'app/components/touchable_with_feedback';
import {makeStyleSheetFromTheme} from 'app/utils/theme';
const EMOJI_REGEX = /(^|\s|^\+|^-)(:([^:\s]*))$/i;
@@ -171,9 +171,10 @@ export default class EmojiSuggestion extends Component {
const style = getStyleFromTheme(this.props.theme);
return (
- this.completeSuggestion(item)}
style={style.row}
+ type={'opacity'}
>
{`:${item}:`}
-
+
);
};
diff --git a/app/components/autocomplete/slash_suggestion/slash_suggestion_item.js b/app/components/autocomplete/slash_suggestion/slash_suggestion_item.js
index 667637fa4..207bbbb93 100644
--- a/app/components/autocomplete/slash_suggestion/slash_suggestion_item.js
+++ b/app/components/autocomplete/slash_suggestion/slash_suggestion_item.js
@@ -3,13 +3,11 @@
import React, {PureComponent} from 'react';
import PropTypes from 'prop-types';
-import {
- Text,
- TouchableOpacity,
-} from 'react-native';
+import {Text} from 'react-native';
-import {changeOpacity, makeStyleSheetFromTheme} from 'app/utils/theme';
import {paddingHorizontal as padding} from 'app/components/safe_area_view/iphone_x_spacing';
+import TouchableWithFeedback from 'app/components/touchable_with_feedback';
+import {changeOpacity, makeStyleSheetFromTheme} from 'app/utils/theme';
export default class SlashSuggestionItem extends PureComponent {
static propTypes = {
@@ -38,13 +36,14 @@ export default class SlashSuggestionItem extends PureComponent {
const style = getStyleFromTheme(theme);
return (
-
{`/${trigger} ${hint}`}
{description}
-
+
);
}
}
diff --git a/app/components/autocomplete/special_mention_item.js b/app/components/autocomplete/special_mention_item.js
index 1ce8587cc..090afa6bf 100644
--- a/app/components/autocomplete/special_mention_item.js
+++ b/app/components/autocomplete/special_mention_item.js
@@ -5,12 +5,12 @@ import React, {PureComponent} from 'react';
import PropTypes from 'prop-types';
import {
Text,
- TouchableOpacity,
View,
} from 'react-native';
import Icon from 'react-native-vector-icons/FontAwesome';
import FormattedText from 'app/components/formatted_text';
+import TouchableWithFeedback from 'app/components/touchable_with_feedback';
import {makeStyleSheetFromTheme, changeOpacity} from 'app/utils/theme';
export default class SpecialMentionItem extends PureComponent {
@@ -40,9 +40,10 @@ export default class SpecialMentionItem extends PureComponent {
const style = getStyleFromTheme(theme);
return (
-
-
+
);
}
}
diff --git a/app/components/autocomplete_selector/autocomplete_selector.js b/app/components/autocomplete_selector/autocomplete_selector.js
index 2817da990..9b8d24754 100644
--- a/app/components/autocomplete_selector/autocomplete_selector.js
+++ b/app/components/autocomplete_selector/autocomplete_selector.js
@@ -2,7 +2,7 @@
// See LICENSE.txt for license information.
import React, {PureComponent} from 'react';
-import {Text, TouchableOpacity, View} from 'react-native';
+import {Text, View} from 'react-native';
import PropTypes from 'prop-types';
import {intlShape} from 'react-intl';
import Icon from 'react-native-vector-icons/FontAwesome';
@@ -10,6 +10,7 @@ import Icon from 'react-native-vector-icons/FontAwesome';
import {displayUsername} from 'mattermost-redux/utils/user_utils';
import FormattedText from 'app/components/formatted_text';
+import TouchableWithFeedback from 'app/components/touchable_with_feedback';
import {preventDoubleTap} from 'app/utils/tap';
import {makeStyleSheetFromTheme, changeOpacity} from 'app/utils/theme';
import {ViewTypes} from 'app/constants';
@@ -181,9 +182,10 @@ export default class AutocompleteSelector extends PureComponent {
return (
{labelContent}
-
-
+
{helpTextContent}
{errorTextContent}
diff --git a/app/components/button.js b/app/components/button.js
deleted file mode 100644
index b8df20efe..000000000
--- a/app/components/button.js
+++ /dev/null
@@ -1,60 +0,0 @@
-// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See LICENSE.txt for license information.
-
-import React, {PureComponent} from 'react';
-import PropTypes from 'prop-types';
-
-import {ActivityIndicator, StyleSheet, TouchableHighlight, View} from 'react-native';
-
-import {GlobalStyles} from 'app/styles';
-
-const styles = StyleSheet.create({
- container: {
- flex: 1,
- flexDirection: 'row',
- },
-
- loading: {
- marginLeft: 3,
- },
-});
-
-export default class Button extends PureComponent {
- static propTypes = {
- children: PropTypes.node,
- loading: PropTypes.bool,
- onPress: PropTypes.func.isRequired,
- };
-
- onPress = () => {
- if (!this.props.loading) {
- this.props.onPress();
- }
- };
-
- render() {
- let loading = null;
- if (this.props.loading) {
- loading = (
-
- );
- }
-
- return (
-
-
- {this.props.children}
- {loading}
-
-
- );
- }
-}
diff --git a/app/components/channel_intro/channel_intro.js b/app/components/channel_intro/channel_intro.js
index 2ff50fa9c..9efe499f2 100644
--- a/app/components/channel_intro/channel_intro.js
+++ b/app/components/channel_intro/channel_intro.js
@@ -5,16 +5,17 @@ import React, {PureComponent} from 'react';
import PropTypes from 'prop-types';
import {
Text,
- TouchableOpacity,
View,
} from 'react-native';
import {getFullName} from 'mattermost-redux/utils/user_utils';
import {General} from 'mattermost-redux/constants';
import {injectIntl, intlShape} from 'react-intl';
-import {paddingHorizontal as padding} from 'app/components/safe_area_view/iphone_x_spacing';
-import ProfilePicture from 'app/components/profile_picture';
+
import BotTag from 'app/components/bot_tag';
import GuestTag from 'app/components/guest_tag';
+import ProfilePicture from 'app/components/profile_picture';
+import {paddingHorizontal as padding} from 'app/components/safe_area_view/iphone_x_spacing';
+import TouchableWithFeedback from 'app/components/touchable_with_feedback';
import {preventDoubleTap} from 'app/utils/tap';
import {changeOpacity, makeStyleSheetFromTheme} from 'app/utils/theme';
import {t} from 'app/utils/i18n';
@@ -67,10 +68,11 @@ class ChannelIntro extends PureComponent {
const style = getStyleSheet(theme);
return currentChannelMembers.map((member) => (
- this.goToUserProfile(member.id))}
style={style.profile}
+ type={'opacity'}
>
-
+
));
};
@@ -88,9 +90,10 @@ class ChannelIntro extends PureComponent {
return currentChannelMembers.map((member, index) => {
return (
- this.goToUserProfile(member.id))}
+ type={'opacity'}
>
@@ -108,7 +111,7 @@ class ChannelIntro extends PureComponent {
{index === currentChannelMembers.length - 1 ? '' : ', '}
-
+
);
});
};
diff --git a/app/components/file_attachment_list/file_attachment.js b/app/components/file_attachment_list/file_attachment.js
index 9a41f8724..256eedf77 100644
--- a/app/components/file_attachment_list/file_attachment.js
+++ b/app/components/file_attachment_list/file_attachment.js
@@ -5,12 +5,12 @@ import React, {PureComponent} from 'react';
import PropTypes from 'prop-types';
import {
Text,
- TouchableOpacity,
View,
} from 'react-native';
import * as Utils from 'mattermost-redux/utils/file_utils.js';
+import TouchableWithFeedback from 'app/components/touchable_with_feedback';
import {isDocument, isGif} from 'app/utils/file';
import {changeOpacity, makeStyleSheetFromTheme} from 'app/utils/theme';
@@ -98,17 +98,18 @@ export default class FileAttachment extends PureComponent {
let fileAttachmentComponent;
if ((data && data.has_preview_image) || file.loading || isGif(data)) {
fileAttachmentComponent = (
-
-
+
);
} else if (isDocument(data)) {
fileAttachmentComponent = (
@@ -122,29 +123,32 @@ export default class FileAttachment extends PureComponent {
);
} else {
fileAttachmentComponent = (
-
-
+
);
}
return (
{fileAttachmentComponent}
-
- {this.renderFileInfo()}
-
+
+
+ {this.renderFileInfo()}
+
+
);
}
diff --git a/app/components/file_attachment_list/file_attachment_document/file_attachment_document.js b/app/components/file_attachment_list/file_attachment_document/file_attachment_document.js
index d699b9a29..d6e988cc3 100644
--- a/app/components/file_attachment_list/file_attachment_document/file_attachment_document.js
+++ b/app/components/file_attachment_list/file_attachment_document/file_attachment_document.js
@@ -10,7 +10,6 @@ import {
Platform,
StatusBar,
StyleSheet,
- TouchableOpacity,
View,
} from 'react-native';
import OpenFile from 'react-native-doc-viewer';
@@ -21,12 +20,12 @@ import tinyColor from 'tinycolor2';
import {getFileUrl} from 'mattermost-redux/utils/file_utils.js';
+import FileAttachmentIcon from 'app/components/file_attachment_list/file_attachment_icon';
+import TouchableWithFeedback from 'app/components/touchable_with_feedback';
import {DeviceTypes} from 'app/constants/';
import mattermostBucket from 'app/mattermost_bucket';
import {changeOpacity} from 'app/utils/theme';
-import FileAttachmentIcon from 'app/components/file_attachment_list/file_attachment_icon';
-
const {DOCUMENTS_PATH} = DeviceTypes;
const DOWNLOADING_OFFSET = 28;
const TEXT_PREVIEW_FORMATS = [
@@ -386,12 +385,13 @@ export default class FileAttachmentDocument extends PureComponent {
}
return (
-
{fileAttachmentComponent}
-
+
);
}
}
diff --git a/app/components/file_upload_preview/file_upload_remove.js b/app/components/file_upload_preview/file_upload_remove.js
index 86931d741..944352e03 100644
--- a/app/components/file_upload_preview/file_upload_remove.js
+++ b/app/components/file_upload_preview/file_upload_remove.js
@@ -3,9 +3,11 @@
import React, {PureComponent} from 'react';
import PropTypes from 'prop-types';
-import {Platform, StyleSheet, TouchableOpacity} from 'react-native';
+import {Platform, StyleSheet} from 'react-native';
import Icon from 'react-native-vector-icons/Ionicons';
+import TouchableWithFeedback from 'app/components/touchable_with_feedback';
+
export default class FileUploadRemove extends PureComponent {
static propTypes = {
channelId: PropTypes.string,
@@ -22,9 +24,10 @@ export default class FileUploadRemove extends PureComponent {
render() {
return (
-
-
+
);
}
}
diff --git a/app/components/file_upload_preview/file_upload_retry.js b/app/components/file_upload_preview/file_upload_retry.js
index 5ca656d1b..e073cefea 100644
--- a/app/components/file_upload_preview/file_upload_retry.js
+++ b/app/components/file_upload_preview/file_upload_retry.js
@@ -3,9 +3,11 @@
import React, {PureComponent} from 'react';
import PropTypes from 'prop-types';
-import {StyleSheet, TouchableOpacity} from 'react-native';
+import {StyleSheet} from 'react-native';
import Icon from 'react-native-vector-icons/Ionicons';
+import TouchableWithFeedback from 'app/components/touchable_with_feedback';
+
export default class FileUploadRetry extends PureComponent {
static propTypes = {
file: PropTypes.object.isRequired,
@@ -20,16 +22,17 @@ export default class FileUploadRetry extends PureComponent {
render() {
return (
-
-
+
);
}
}
diff --git a/app/components/load_more_posts/load_more_posts.js b/app/components/load_more_posts/load_more_posts.js
index a0c892e20..15e7c94b1 100644
--- a/app/components/load_more_posts/load_more_posts.js
+++ b/app/components/load_more_posts/load_more_posts.js
@@ -5,16 +5,15 @@ import React, {PureComponent} from 'react';
import PropTypes from 'prop-types';
import {
ActivityIndicator,
- TouchableOpacity,
View,
ViewPropTypes,
} from 'react-native';
+import FormattedText from 'app/components/formatted_text';
+import TouchableWithFeedback from 'app/components/touchable_with_feedback';
import {makeStyleSheetFromTheme} from 'app/utils/theme';
import {t} from 'app/utils/i18n';
-import FormattedText from 'app/components/formatted_text';
-
export default class LoadMorePosts extends PureComponent {
static propTypes = {
channelId: PropTypes.string.isRequired, // eslint-disable-line react/no-unused-prop-types
@@ -56,9 +55,12 @@ export default class LoadMorePosts extends PureComponent {
const style = getStyleSheet(this.props.theme);
return (
-
+
{this.renderText(style)}
-
+
);
}
diff --git a/app/components/markdown/markdown_code_block/markdown_code_block.js b/app/components/markdown/markdown_code_block/markdown_code_block.js
index eaef682e2..83020acea 100644
--- a/app/components/markdown/markdown_code_block/markdown_code_block.js
+++ b/app/components/markdown/markdown_code_block/markdown_code_block.js
@@ -8,12 +8,12 @@ import {
Clipboard,
StyleSheet,
Text,
- TouchableOpacity,
View,
} from 'react-native';
import CustomPropTypes from 'app/constants/custom_prop_types';
import FormattedText from 'app/components/formatted_text';
+import TouchableWithFeedback from 'app/components/touchable_with_feedback';
import BottomSheet from 'app/utils/bottom_sheet';
import {getDisplayNameForLanguage} from 'app/utils/markdown';
import {preventDoubleTap} from 'app/utils/tap';
@@ -153,9 +153,10 @@ export default class MarkdownCodeBlock extends React.PureComponent {
}
return (
-
@@ -173,7 +174,7 @@ export default class MarkdownCodeBlock extends React.PureComponent {
{language}
-
+
);
}
}
diff --git a/app/components/markdown/markdown_image/markdown_image.js b/app/components/markdown/markdown_image/markdown_image.js
index 882d4fbc6..779870206 100644
--- a/app/components/markdown/markdown_image/markdown_image.js
+++ b/app/components/markdown/markdown_image/markdown_image.js
@@ -11,12 +11,12 @@ import {
Platform,
StyleSheet,
Text,
- TouchableHighlight,
View,
} from 'react-native';
import FormattedText from 'app/components/formatted_text';
import ProgressiveImage from 'app/components/progressive_image';
+import TouchableWithFeedback from 'app/components/touchable_with_feedback';
import CustomPropTypes from 'app/constants/custom_prop_types';
import EphemeralStore from 'app/store/ephemeral_store';
import mattermostManaged from 'app/mattermost_managed';
@@ -250,7 +250,7 @@ export default class MarkdownImage extends React.Component {
}
image = (
-
-
+
);
}
} else if (this.state.failed) {
@@ -275,12 +275,12 @@ export default class MarkdownImage extends React.Component {
if (image && this.props.linkDestination) {
image = (
-
{image}
-
+
);
}
diff --git a/app/components/markdown/markdown_table/markdown_table.js b/app/components/markdown/markdown_table/markdown_table.js
index deffa3174..de97017ba 100644
--- a/app/components/markdown/markdown_table/markdown_table.js
+++ b/app/components/markdown/markdown_table/markdown_table.js
@@ -6,14 +6,14 @@ import React from 'react';
import {intlShape} from 'react-intl';
import {
ScrollView,
- TouchableOpacity,
View,
} from 'react-native';
import LinearGradient from 'react-native-linear-gradient';
+import {CELL_WIDTH} from 'app/components/markdown/markdown_table_cell/markdown_table_cell';
+import TouchableWithFeedback from 'app/components/touchable_with_feedback';
import {preventDoubleTap} from 'app/utils/tap';
import {changeOpacity, makeStyleSheetFromTheme} from 'app/utils/theme';
-import {CELL_WIDTH} from 'app/components/markdown/markdown_table_cell/markdown_table_cell';
const MAX_HEIGHT = 300;
@@ -128,7 +128,10 @@ export default class MarkdownTable extends React.PureComponent {
}
return (
-
+
{moreRight}
{moreBelow}
-
+
);
}
}
diff --git a/app/components/message_attachments/attachment_image/__snapshots__/attachment_image.test.js.snap b/app/components/message_attachments/attachment_image/__snapshots__/attachment_image.test.js.snap
index 175d971cf..75cf22a00 100644
--- a/app/components/message_attachments/attachment_image/__snapshots__/attachment_image.test.js.snap
+++ b/app/components/message_attachments/attachment_image/__snapshots__/attachment_image.test.js.snap
@@ -1,7 +1,7 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`AttachmentImage it matches snapshot 1`] = `
-
-
+
`;
diff --git a/app/components/message_attachments/attachment_image/attachment_image.js b/app/components/message_attachments/attachment_image/attachment_image.js
index 5b8165a0f..45d75fe47 100644
--- a/app/components/message_attachments/attachment_image/attachment_image.js
+++ b/app/components/message_attachments/attachment_image/attachment_image.js
@@ -3,9 +3,10 @@
import React, {PureComponent} from 'react';
import PropTypes from 'prop-types';
-import {Image, TouchableWithoutFeedback, View} from 'react-native';
+import {Image, View} from 'react-native';
import ProgressiveImage from 'app/components/progressive_image';
+import TouchableWithFeedback from 'app/components/touchable_with_feedback';
import {isGifTooLarge, previewImageAtIndex, calculateDimensions} from 'app/utils/images';
import ImageCacheManager from 'app/utils/image_cache_manager';
import {changeOpacity, makeStyleSheetFromTheme} from 'app/utils/theme';
@@ -145,9 +146,10 @@ export default class AttachmentImage extends PureComponent {
}
return (
-
{progressiveImage}
-
+
);
}
}
diff --git a/app/components/post/post.js b/app/components/post/post.js
index b402c6305..00b3be652 100644
--- a/app/components/post/post.js
+++ b/app/components/post/post.js
@@ -6,7 +6,6 @@ import PropTypes from 'prop-types';
import {
Keyboard,
Platform,
- TouchableHighlight,
View,
ViewPropTypes,
} from 'react-native';
@@ -16,6 +15,7 @@ import PostBody from 'app/components/post_body';
import PostHeader from 'app/components/post_header';
import PostPreHeader from 'app/components/post_header/post_pre_header';
import PostProfilePicture from 'app/components/post_profile_picture';
+import TouchableWithFeedback from 'app/components/touchable_with_feedback';
import {NavigationTypes} from 'app/constants';
import {fromAutoResponder} from 'app/utils/general';
import {preventDoubleTap} from 'app/utils/tap';
@@ -145,6 +145,7 @@ export default class Post extends PureComponent {
};
handlePress = preventDoubleTap(() => {
+ this.onPressDetected = true;
const {
onPress,
post,
@@ -157,6 +158,10 @@ export default class Post extends PureComponent {
} else if ((isPostEphemeral(post) || post.state === Posts.POST_DELETED) && !showLongPost) {
this.onRemovePost(post);
}
+
+ setTimeout(() => {
+ this.onPressDetected = false;
+ }, 300);
});
handleReply = preventDoubleTap(() => {
@@ -214,7 +219,7 @@ export default class Post extends PureComponent {
});
showPostOptions = () => {
- if (this.postBodyRef?.current) {
+ if (this.postBodyRef?.current && !this.onPressDetected) {
this.postBodyRef.current.showPostOptions();
}
};
@@ -302,12 +307,13 @@ export default class Post extends PureComponent {
const rightColumnStyle = [style.rightColumn, (commentedOnPost && isLastReply && style.rightColumnPadding)];
return (
-
-
+
);
}
}
diff --git a/app/components/post_attachment_image/__snapshots__/index.test.js.snap b/app/components/post_attachment_image/__snapshots__/index.test.js.snap
index c78be4bf6..b384ec63a 100644
--- a/app/components/post_attachment_image/__snapshots__/index.test.js.snap
+++ b/app/components/post_attachment_image/__snapshots__/index.test.js.snap
@@ -1,7 +1,7 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`PostAttachmentImage should match snapshot 1`] = `
-
-
+
`;
diff --git a/app/components/post_attachment_image/index.js b/app/components/post_attachment_image/index.js
index 7216fec5c..d45c0441f 100644
--- a/app/components/post_attachment_image/index.js
+++ b/app/components/post_attachment_image/index.js
@@ -3,9 +3,10 @@
import PropTypes from 'prop-types';
import React from 'react';
-import {StyleSheet, TouchableWithoutFeedback, View} from 'react-native';
+import {StyleSheet, View} from 'react-native';
import ProgressiveImage from 'app/components/progressive_image';
+import TouchableWithFeedback from 'app/components/touchable_with_feedback';
import {isGifTooLarge} from 'app/utils/images';
export default class PostAttachmentImage extends React.PureComponent {
@@ -40,9 +41,10 @@ export default class PostAttachmentImage extends React.PureComponent {
// Note that TouchableWithoutFeedback only works if its child is a View
return (
-
-
+
);
}
}
diff --git a/app/components/post_attachment_opengraph/__snapshots__/post_attachment_opengraph.test.js.snap b/app/components/post_attachment_opengraph/__snapshots__/post_attachment_opengraph.test.js.snap
index 6c72da334..4da6f6ecb 100644
--- a/app/components/post_attachment_opengraph/__snapshots__/post_attachment_opengraph.test.js.snap
+++ b/app/components/post_attachment_opengraph/__snapshots__/post_attachment_opengraph.test.js.snap
@@ -44,14 +44,14 @@ exports[`PostAttachmentOpenGraph should match snapshot, without image and descri
}
}
>
-
Title
-
+
-
-
+
`;
@@ -133,14 +134,14 @@ exports[`PostAttachmentOpenGraph should match snapshot, without site_name 1`] =
}
}
>
-
Title
-
+
`;
@@ -186,14 +187,14 @@ exports[`PostAttachmentOpenGraph should match snapshot, without title and url 1`
}
}
>
-
https://mattermost.com/
-
+
`;
@@ -264,8 +265,9 @@ exports[`PostAttachmentOpenGraph should match state and snapshot, on renderImage
]
}
>
-
-
+
`;
diff --git a/app/components/post_attachment_opengraph/post_attachment_opengraph.js b/app/components/post_attachment_opengraph/post_attachment_opengraph.js
index cb7d413ef..e80f1b732 100644
--- a/app/components/post_attachment_opengraph/post_attachment_opengraph.js
+++ b/app/components/post_attachment_opengraph/post_attachment_opengraph.js
@@ -7,12 +7,11 @@ import {
Image,
Linking,
Text,
- TouchableOpacity,
- TouchableWithoutFeedback,
View,
} from 'react-native';
import {TABLET_WIDTH} from 'app/components/sidebars/drawer_layout';
+import TouchableWithFeedback from 'app/components/touchable_with_feedback';
import {DeviceTypes} from 'app/constants';
import ImageCacheManager from 'app/utils/image_cache_manager';
@@ -255,15 +254,16 @@ export default class PostAttachmentOpenGraph extends PureComponent {
ref='item'
style={[style.imageContainer, {width, height}]}
>
-
-
+
);
};
@@ -302,9 +302,10 @@ export default class PostAttachmentOpenGraph extends PureComponent {
if (title) {
siteTitle = (
-
{title}
-
+
);
}
diff --git a/app/components/post_attachment_opengraph/post_attachment_opengraph.test.js b/app/components/post_attachment_opengraph/post_attachment_opengraph.test.js
index dc1b926ff..dca90cac2 100644
--- a/app/components/post_attachment_opengraph/post_attachment_opengraph.test.js
+++ b/app/components/post_attachment_opengraph/post_attachment_opengraph.test.js
@@ -3,12 +3,9 @@
import React from 'react';
import {shallow} from 'enzyme';
-import {
- Image,
- TouchableWithoutFeedback,
- TouchableOpacity,
-} from 'react-native';
+import {Image} from 'react-native';
+import TouchableWithFeedback from 'app/components/touchable_with_feedback';
import Preferences from 'mattermost-redux/constants/preferences';
import PostAttachmentOpenGraph from './post_attachment_opengraph';
@@ -50,7 +47,7 @@ describe('PostAttachmentOpenGraph', () => {
wrapper.setProps({openGraphData});
expect(wrapper.getElement()).toMatchSnapshot();
- expect(wrapper.find(TouchableOpacity).exists()).toEqual(true);
+ expect(wrapper.find(TouchableWithFeedback).exists()).toEqual(true);
});
test('should match snapshot, without site_name', () => {
@@ -86,7 +83,7 @@ describe('PostAttachmentOpenGraph', () => {
expect(wrapper.instance().renderImage()).toMatchSnapshot();
expect(wrapper.state('hasImage')).toEqual(false);
expect(wrapper.find(Image).exists()).toEqual(false);
- expect(wrapper.find(TouchableWithoutFeedback).exists()).toEqual(false);
+ expect(wrapper.find(TouchableWithFeedback).exists()).toEqual(false);
const images = [{height: 440, width: 1200, url: 'https://mattermost.com/logo.png'}];
const openGraphDataWithImage = {...openGraphData, images};
@@ -95,7 +92,7 @@ describe('PostAttachmentOpenGraph', () => {
expect(wrapper.instance().renderImage()).toMatchSnapshot();
expect(wrapper.state('hasImage')).toEqual(true);
expect(wrapper.find(Image).exists()).toEqual(true);
- expect(wrapper.find(TouchableWithoutFeedback).exists()).toEqual(true);
+ expect(wrapper.find(TouchableWithFeedback).exists()).toEqual(true);
});
test('should match state and snapshot, on renderDescription', () => {
diff --git a/app/components/post_body/post_body.js b/app/components/post_body/post_body.js
index 26e279fe3..d5c5c1d0f 100644
--- a/app/components/post_body/post_body.js
+++ b/app/components/post_body/post_body.js
@@ -5,13 +5,10 @@ import React, {PureComponent} from 'react';
import PropTypes from 'prop-types';
import {
Keyboard,
- ScrollView,
- TouchableOpacity,
View,
} from 'react-native';
import {intlShape} from 'react-intl';
import Icon from 'react-native-vector-icons/Ionicons';
-
import {Posts} from 'mattermost-redux/constants';
import CombinedSystemMessage from 'app/components/combined_system_message';
@@ -19,6 +16,7 @@ import FormattedText from 'app/components/formatted_text';
import Markdown from 'app/components/markdown';
import MarkdownEmoji from 'app/components/markdown/markdown_emoji';
import ShowMoreButton from 'app/components/show_more_button';
+import TouchableWithFeedback from 'app/components/touchable_with_feedback';
import {emptyFunction} from 'app/utils/general';
import {getMarkdownTextStyles, getMarkdownBlockStyles} from 'app/utils/markdown';
@@ -414,15 +412,11 @@ export default class PostBody extends PureComponent {
if (!hasBeenDeleted) {
body = (
-
{messageComponent}
-
+
{isLongPost &&
{body}
{isFailed &&
-
-
+
}
);
diff --git a/app/components/post_body_additional_content/post_body_additional_content.js b/app/components/post_body_additional_content/post_body_additional_content.js
index f5b311d16..13c88735f 100644
--- a/app/components/post_body_additional_content/post_body_additional_content.js
+++ b/app/components/post_body_additional_content/post_body_additional_content.js
@@ -9,7 +9,6 @@ import {
Linking,
Platform,
StyleSheet,
- TouchableOpacity,
StatusBar,
} from 'react-native';
import {YouTubeStandaloneAndroid, YouTubeStandaloneIOS} from 'react-native-youtube';
@@ -20,6 +19,7 @@ import EventEmitter from 'mattermost-redux/utils/event_emitter';
import {TABLET_WIDTH} from 'app/components/sidebars/drawer_layout';
import PostAttachmentImage from 'app/components/post_attachment_image';
import ProgressiveImage from 'app/components/progressive_image';
+import TouchableWithFeedback from 'app/components/touchable_with_feedback';
import {DeviceTypes} from 'app/constants';
import CustomPropTypes from 'app/constants/custom_prop_types';
@@ -231,9 +231,10 @@ export default class PostBodyAdditionalContent extends PureComponent {
const thumbUrl = `https://i.ytimg.com/vi/${videoId}/default.jpg`;
return (
-
-
-
+
-
+
);
}
diff --git a/app/components/post_header/post_header.js b/app/components/post_header/post_header.js
index fee5d3406..b2dd60d4f 100644
--- a/app/components/post_header/post_header.js
+++ b/app/components/post_header/post_header.js
@@ -6,7 +6,6 @@ import PropTypes from 'prop-types';
import {
Platform,
Text,
- TouchableOpacity,
View,
} from 'react-native';
@@ -16,6 +15,7 @@ import FormattedDate from 'app/components/formatted_date';
import ReplyIcon from 'app/components/reply_icon';
import BotTag from 'app/components/bot_tag';
import GuestTag from 'app/components/guest_tag';
+import TouchableWithFeedback from 'app/components/touchable_with_feedback';
import {emptyFunction} from 'app/utils/general';
import {changeOpacity, makeStyleSheetFromTheme} from 'app/utils/theme';
@@ -87,7 +87,10 @@ export default class PostHeader extends PureComponent {
);
} else if (isBot) {
return (
-
+
{this.props.displayName}
@@ -96,11 +99,14 @@ export default class PostHeader extends PureComponent {
theme={this.props.theme}
/>
-
+
);
} else if (isGuest) {
return (
-
+
{this.props.displayName}
@@ -109,7 +115,7 @@ export default class PostHeader extends PureComponent {
theme={this.props.theme}
/>
-
+
);
} else if (fromAutoResponder) {
let name = this.props.displayName;
@@ -139,11 +145,14 @@ export default class PostHeader extends PureComponent {
);
} else if (this.props.displayName) {
return (
-
+
{this.props.displayName}
-
+
);
}
@@ -254,9 +263,10 @@ export default class PostHeader extends PureComponent {
{showReply &&
-
{commentCount}
}
-
+
}
{commentedOnDisplayName !== '' &&
diff --git a/app/components/post_list_retry.js b/app/components/post_list_retry.js
index 70c0c8d24..303cff7e1 100644
--- a/app/components/post_list_retry.js
+++ b/app/components/post_list_retry.js
@@ -5,12 +5,12 @@ import React, {PureComponent} from 'react';
import PropTypes from 'prop-types';
import {
Platform,
- TouchableOpacity,
View,
} from 'react-native';
import Icon from 'react-native-vector-icons/Ionicons';
import FormattedText from 'app/components/formatted_text';
+import TouchableWithFeedback from 'app/components/touchable_with_feedback';
import {makeStyleSheetFromTheme} from 'app/utils/theme';
export default class PostListRetry extends PureComponent {
@@ -25,9 +25,10 @@ export default class PostListRetry extends PureComponent {
return (
-
-
+
);
}
diff --git a/app/components/post_profile_picture/post_profile_picture.js b/app/components/post_profile_picture/post_profile_picture.js
index d985f8d11..ec2ec981a 100644
--- a/app/components/post_profile_picture/post_profile_picture.js
+++ b/app/components/post_profile_picture/post_profile_picture.js
@@ -3,10 +3,11 @@
import React, {PureComponent} from 'react';
import PropTypes from 'prop-types';
-import {Image, TouchableOpacity, View} from 'react-native';
+import {Image, View} from 'react-native';
import AppIcon from 'app/components/app_icon';
import ProfilePicture from 'app/components/profile_picture';
+import TouchableWithFeedback from 'app/components/touchable_with_feedback';
import {emptyFunction} from 'app/utils/general';
import webhookIcon from 'assets/images/icons/webhook.jpg';
import {ViewTypes} from 'app/constants';
@@ -94,9 +95,12 @@ export default class PostProfilePicture extends PureComponent {
if (!fromWebHook) {
component = (
-
+
{component}
-
+
);
}
diff --git a/app/components/reactions/reaction.js b/app/components/reactions/reaction.js
index c5c669030..227fe80b2 100644
--- a/app/components/reactions/reaction.js
+++ b/app/components/reactions/reaction.js
@@ -5,10 +5,10 @@ import React, {PureComponent} from 'react';
import PropTypes from 'prop-types';
import {
Text,
- TouchableOpacity,
} from 'react-native';
import Emoji from 'app/components/emoji';
+import TouchableWithFeedback from 'app/components/touchable_with_feedback';
import {changeOpacity, makeStyleSheetFromTheme} from 'app/utils/theme';
export default class Reaction extends PureComponent {
@@ -37,11 +37,12 @@ export default class Reaction extends PureComponent {
const styles = getStyleSheet(theme);
return (
-
{count}
-
+
);
}
}
diff --git a/app/components/reactions/reactions.js b/app/components/reactions/reactions.js
index 5548ed180..a4e90ee7d 100644
--- a/app/components/reactions/reactions.js
+++ b/app/components/reactions/reactions.js
@@ -6,11 +6,11 @@ import PropTypes from 'prop-types';
import {
Image,
ScrollView,
- TouchableOpacity,
} from 'react-native';
import {intlShape} from 'react-intl';
import MaterialIcon from 'react-native-vector-icons/MaterialIcons';
+import TouchableWithFeedback from 'app/components/touchable_with_feedback';
import {preventDoubleTap} from 'app/utils/tap';
import {changeOpacity, makeStyleSheetFromTheme} from 'app/utils/theme';
import addReactionIcon from 'assets/images/icons/reaction.png';
@@ -72,12 +72,17 @@ export default class Reactions extends PureComponent {
};
handleReactionPress = (emoji, remove) => {
+ this.onPressDetected = true;
const {actions, postId} = this.props;
if (remove && this.props.canRemoveReaction) {
actions.removeReaction(postId, emoji);
} else if (!remove && this.props.canAddReaction) {
actions.addReaction(postId, emoji);
}
+
+ setTimeout(() => {
+ this.onPressDetected = false;
+ }, 300);
};
showReactionList = () => {
@@ -88,8 +93,10 @@ export default class Reactions extends PureComponent {
postId,
};
- actions.showModalOverCurrentContext(screen, passProps);
- }
+ if (!this.onPressDetected) {
+ actions.showModalOverCurrentContext(screen, passProps);
+ }
+ };
renderReactions = () => {
const {currentUserId, reactions, theme, postId} = this.props;
@@ -135,16 +142,17 @@ export default class Reactions extends PureComponent {
let addMoreReactions = null;
if (canAddReaction) {
addMoreReactions = (
-
-
+
);
}
diff --git a/app/components/send_button.js b/app/components/send_button.js
index b508e57aa..7de856193 100644
--- a/app/components/send_button.js
+++ b/app/components/send_button.js
@@ -2,10 +2,10 @@
// See LICENSE.txt for license information.
import React, {memo} from 'react';
-import {TouchableOpacity, View} from 'react-native';
-
+import {View} from 'react-native';
import PropTypes from 'prop-types';
+import TouchableWithFeedback from 'app/components/touchable_with_feedback';
import {changeOpacity, makeStyleSheetFromTheme} from 'app/utils/theme';
let PaperPlane = null;
@@ -37,14 +37,15 @@ function SendButton(props) {
}
return (
-
{icon}
-
+
);
}
diff --git a/app/components/show_more_button/__snapshots__/show_more_button.test.js.snap b/app/components/show_more_button/__snapshots__/show_more_button.test.js.snap
index 2c71c8615..eccccdbd7 100644
--- a/app/components/show_more_button/__snapshots__/show_more_button.test.js.snap
+++ b/app/components/show_more_button/__snapshots__/show_more_button.test.js.snap
@@ -96,8 +96,7 @@ exports[`ShowMoreButton should match, full snapshot 1`] = `
}
}
/>
-
-
+
-
{this.renderButton(showMore, style)}
-
+
diff --git a/app/components/show_more_button/show_more_button.test.js b/app/components/show_more_button/show_more_button.test.js
index 1b34a65dd..112a496b4 100644
--- a/app/components/show_more_button/show_more_button.test.js
+++ b/app/components/show_more_button/show_more_button.test.js
@@ -2,13 +2,12 @@
// See LICENSE.txt for license information.
import React from 'react';
-import {TouchableOpacity} from 'react-native';
import {shallow} from 'enzyme';
+import LinearGradient from 'react-native-linear-gradient';
import Preferences from 'mattermost-redux/constants/preferences';
-import LinearGradient from 'react-native-linear-gradient';
-
+import TouchableWithFeedback from 'app/components/touchable_with_feedback';
import ShowMoreButton from './show_more_button';
describe('ShowMoreButton', () => {
@@ -55,7 +54,7 @@ describe('ShowMoreButton', () => {
/>
);
- wrapper.find(TouchableOpacity).props().onPress();
+ wrapper.find(TouchableWithFeedback).props().onPress();
expect(onPress).toHaveBeenCalledTimes(1);
});
});
diff --git a/app/components/touchable_with_feedback/index.js b/app/components/touchable_with_feedback/index.js
new file mode 100644
index 000000000..4ff5d96d4
--- /dev/null
+++ b/app/components/touchable_with_feedback/index.js
@@ -0,0 +1,5 @@
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
+
+import TouchableWithFeedback from './touchable_with_feedback';
+export default TouchableWithFeedback;
diff --git a/app/components/touchable_with_feedback/touchable_with_feedback.android.js b/app/components/touchable_with_feedback/touchable_with_feedback.android.js
new file mode 100644
index 000000000..fe5e1fbb7
--- /dev/null
+++ b/app/components/touchable_with_feedback/touchable_with_feedback.android.js
@@ -0,0 +1,58 @@
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
+
+/* eslint-disable new-cap */
+
+import React, {PureComponent} from 'react';
+import {TouchableNativeFeedback, TouchableOpacity, TouchableWithoutFeedback, View} from 'react-native';
+import PropTypes from 'prop-types';
+
+import CustomPropTypes from 'app/constants/custom_prop_types';
+
+export default class TouchableWithFeedbackAndroid extends PureComponent {
+ static propTypes = {
+ children: CustomPropTypes.Children,
+ underlayColor: PropTypes.string,
+ type: PropTypes.oneOf(['native', 'opacity', 'none']),
+ };
+
+ static defaultProps = {
+ type: 'native',
+ };
+
+ render() {
+ const {children, underlayColor, type, ...props} = this.props;
+
+ switch (type) {
+ case 'native':
+ return (
+
+
+ {children}
+
+
+ );
+ case 'opacity':
+ return (
+
+ {children}
+
+ );
+ case 'none':
+ return (
+
+ {children}
+
+ );
+ }
+
+ return null;
+ }
+}
diff --git a/app/components/touchable_with_feedback/touchable_with_feedback.ios.js b/app/components/touchable_with_feedback/touchable_with_feedback.ios.js
new file mode 100644
index 000000000..3c250d6ce
--- /dev/null
+++ b/app/components/touchable_with_feedback/touchable_with_feedback.ios.js
@@ -0,0 +1,65 @@
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
+
+import React, {PureComponent} from 'react';
+import {PanResponder, TouchableHighlight, TouchableOpacity, TouchableWithoutFeedback, View} from 'react-native';
+import PropTypes from 'prop-types';
+
+import CustomPropTypes from 'app/constants/custom_prop_types';
+
+export default class TouchableWithFeedbackIOS extends PureComponent {
+ static propTypes = {
+ children: CustomPropTypes.Children,
+ cancelTouchOnPanning: PropTypes.bool,
+ type: PropTypes.oneOf(['native', 'opacity', 'none']),
+ };
+
+ static defaultProps = {
+ type: 'native',
+ };
+
+ constructor(props) {
+ super(props);
+
+ this.panResponder = PanResponder.create({
+ onMoveShouldSetPanResponderCapture: (evt, gestureState) => {
+ return this.props.cancelTouchOnPanning && (gestureState.dx >= 5 || gestureState.dy >= 5 || gestureState.vx > 5);
+ },
+ });
+ }
+
+ render() {
+ const {children, type, ...props} = this.props;
+
+ switch (type) {
+ case 'native':
+ return (
+
+
+ {children}
+
+
+ );
+ case 'opacity':
+ return (
+
+ {children}
+
+ );
+ case 'none':
+ return (
+
+ {children}
+
+ );
+ }
+
+ return null;
+ }
+}
diff --git a/app/screens/user_profile/user_profile_row.js b/app/screens/user_profile/user_profile_row.js
index e08628cbb..7d5d7bbcb 100644
--- a/app/screens/user_profile/user_profile_row.js
+++ b/app/screens/user_profile/user_profile_row.js
@@ -6,14 +6,14 @@ import PropTypes from 'prop-types';
import {
Switch,
Text,
- TouchableHighlight,
View,
} from 'react-native';
import {changeOpacity, makeStyleSheetFromTheme} from 'app/utils/theme';
import FormattedText from 'app/components/formatted_text';
-import VectorIcon from 'app/components/vector_icon.js';
import {paddingHorizontal as padding} from 'app/components/safe_area_view/iphone_x_spacing';
+import TouchableWithFeedback from 'app/components/touchable_with_feedback';
+import VectorIcon from 'app/components/vector_icon';
const createStyleSheet = makeStyleSheetFromTheme((theme) => {
return {
@@ -55,9 +55,9 @@ const createStyleSheet = makeStyleSheetFromTheme((theme) => {
function createTouchableComponent(children, action) {
return (
-
+
{children}
-
+
);
}
diff --git a/package-lock.json b/package-lock.json
index 812859060..56e44a471 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -16537,9 +16537,9 @@
"integrity": "sha512-e2zv0BiP9SRdr1vLDUyC2WbWHfgNV1a3BhRxK1ENjXVRY8mu+dfaaIHhFXdvYue//MEuGUQstu61NZoiO1u2KA=="
},
"react-native-gesture-handler": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/react-native-gesture-handler/-/react-native-gesture-handler-1.2.1.tgz",
- "integrity": "sha512-c1+L72Vjc/bwHKcIJ8a2/88SW9l3/axcAIpg3zB1qTzwdCxHZJeQn6d58cQXHPepxFBbgfTCo60B7SipSfo+zw==",
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/react-native-gesture-handler/-/react-native-gesture-handler-1.3.0.tgz",
+ "integrity": "sha512-ASRFIXBuKRvqlmwkWJhV8yP2dTpvcqVrLNpd7FKVBFHYWr6SAxjGyO9Ik8w1lAxDhMlRP2IcJ9p9eq5X2WWeLQ==",
"requires": {
"hoist-non-react-statics": "^2.3.1",
"invariant": "^2.2.2",
diff --git a/package.json b/package.json
index 160546995..4a8480b20 100644
--- a/package.json
+++ b/package.json
@@ -38,7 +38,7 @@
"react-native-doc-viewer": "2.7.8",
"react-native-document-picker": "2.3.0",
"react-native-exception-handler": "2.10.7",
- "react-native-gesture-handler": "1.2.1",
+ "react-native-gesture-handler": "1.3.0",
"react-native-haptic-feedback": "1.8.2",
"react-native-image-gallery": "github:mattermost/react-native-image-gallery#c1a9f7118e90cc87d47620bc0584c9cac4b0cf38",
"react-native-image-picker": "0.28.1",