diff --git a/NOTICE.txt b/NOTICE.txt index 766baf1a3..45ab02693 100644 --- a/NOTICE.txt +++ b/NOTICE.txt @@ -2076,41 +2076,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. --- -## react-native-tooltip - -This product contains 'react-native-tooltip' by Chirag Jain. - -A react-native wrapper for showing tooltips - -* HOMEPAGE: - * https://github.com/chirag04/react-native-tooltip#readme - -* LICENSE: MIT - -The MIT License (MIT) - -Copyright (c) 2015-2016 Chirag Jain - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - ---- - ## react-native-vector-icons This product contains 'react-native-vector-icons' by Joel Arvidsson. diff --git a/app/components/at_mention/at_mention.js b/app/components/at_mention/at_mention.js index f800ef4a2..d39351fd4 100644 --- a/app/components/at_mention/at_mention.js +++ b/app/components/at_mention/at_mention.js @@ -8,10 +8,9 @@ import {intlShape} from 'react-intl'; import {displayUsername} from 'mattermost-redux/utils/user_utils'; -import {emptyFunction} from 'app/utils/general'; - import CustomPropTypes from 'app/constants/custom_prop_types'; import mattermostManaged from 'app/mattermost_managed'; +import BottomSheet from 'app/utils/bottom_sheet'; export default class AtMention extends React.PureComponent { static propTypes = { @@ -19,7 +18,6 @@ export default class AtMention extends React.PureComponent { mentionName: PropTypes.string.isRequired, mentionStyle: CustomPropTypes.Style, navigator: PropTypes.object.isRequired, - onLongPress: PropTypes.func.isRequired, onPostPress: PropTypes.func, textStyle: CustomPropTypes.Style, teammateNameDisplay: PropTypes.string, @@ -27,10 +25,6 @@ export default class AtMention extends React.PureComponent { usersByUsername: PropTypes.object.isRequired, }; - static defaultProps = { - onLongPress: emptyFunction, - }; - static contextTypes = { intl: intlShape, }; @@ -101,26 +95,33 @@ export default class AtMention extends React.PureComponent { } handleLongPress = async () => { - const {intl} = this.context; + const {formatMessage} = this.context.intl; const config = await mattermostManaged.getLocalConfig(); - let action; if (config.copyAndPasteProtection !== 'false') { - action = { - text: intl.formatMessage({ - id: 'mobile.mention.copy_mention', - defaultMessage: 'Copy Mention', - }), - onPress: this.handleCopyMention, - }; - } + const cancelText = formatMessage({id: 'mobile.post.cancel', defaultMessage: 'Cancel'}); + const actionText = formatMessage({id: 'mobile.mention.copy_mention', defaultMessage: 'Copy Mention'}); - this.props.onLongPress(action); + BottomSheet.showBottomSheetWithOptions({ + options: [actionText, cancelText], + cancelButtonIndex: 1, + }, (value) => { + if (value !== 1) { + this.handleCopyMention(); + } + }); + } }; handleCopyMention = () => { - const {username} = this.state; + const {user} = this.state; + const {mentionName} = this.props; + let username = mentionName; + if (user.username) { + username = user.username; + } + Clipboard.setString(`@${username}`); }; diff --git a/app/components/file_attachment_list/file_attachment.js b/app/components/file_attachment_list/file_attachment.js index 2b6ebcb45..628f3b231 100644 --- a/app/components/file_attachment_list/file_attachment.js +++ b/app/components/file_attachment_list/file_attachment.js @@ -25,6 +25,7 @@ export default class FileAttachment extends PureComponent { file: PropTypes.object.isRequired, index: PropTypes.number.isRequired, onCaptureRef: PropTypes.func, + onLongPress: PropTypes.func, onPreviewPress: PropTypes.func, theme: PropTypes.object.isRequired, navigator: PropTypes.object, @@ -92,6 +93,7 @@ export default class FileAttachment extends PureComponent { file, theme, navigator, + onLongPress, } = this.props; const {data} = file; const style = getStyleSheet(theme); @@ -99,7 +101,10 @@ export default class FileAttachment extends PureComponent { let fileAttachmentComponent; if ((data && data.has_preview_image) || file.loading || isGif(data)) { fileAttachmentComponent = ( - + ); } else { fileAttachmentComponent = ( - + {fileAttachmentComponent} diff --git a/app/components/file_attachment_list/file_attachment_document.js b/app/components/file_attachment_list/file_attachment_document.js index 6911bfa2f..69d7d0b0b 100644 --- a/app/components/file_attachment_list/file_attachment_document.js +++ b/app/components/file_attachment_list/file_attachment_document.js @@ -47,6 +47,7 @@ export default class FileAttachmentDocument extends PureComponent { file: PropTypes.object.isRequired, theme: PropTypes.object.isRequired, navigator: PropTypes.object, + onLongPress: PropTypes.func, wrapperHeight: PropTypes.number, wrapperWidth: PropTypes.number, }; @@ -349,7 +350,7 @@ export default class FileAttachmentDocument extends PureComponent { } render() { - const {theme, wrapperHeight} = this.props; + const {onLongPress, theme, wrapperHeight} = this.props; const {downloading, progress} = this.state; let fileAttachmentComponent; @@ -371,8 +372,11 @@ export default class FileAttachmentDocument extends PureComponent { } return ( - - + + {fileAttachmentComponent} @@ -389,7 +393,7 @@ const style = StyleSheet.create({ position: 'absolute', top: 0, }, - whiteBackgroud: { + whiteBackground: { backgroundColor: '#fff', }, }); diff --git a/app/components/file_attachment_list/file_attachment_list.js b/app/components/file_attachment_list/file_attachment_list.js index 8ac26bc22..96a4f42c0 100644 --- a/app/components/file_attachment_list/file_attachment_list.js +++ b/app/components/file_attachment_list/file_attachment_list.js @@ -8,7 +8,6 @@ import { Platform, ScrollView, StyleSheet, - TouchableOpacity, View, } from 'react-native'; @@ -30,7 +29,6 @@ export default class FileAttachmentList extends Component { deviceWidth: PropTypes.number.isRequired, fileIds: PropTypes.array.isRequired, files: PropTypes.array.isRequired, - hideOptionsContext: PropTypes.func.isRequired, isFailed: PropTypes.bool, navigator: PropTypes.object, onLongPress: PropTypes.func, @@ -121,7 +119,6 @@ export default class FileAttachmentList extends Component { }; handlePreviewPress = preventDoubleTap((idx) => { - this.props.hideOptionsContext(); Keyboard.dismiss(); previewImageAtIndex(this.props.navigator, this.items, idx, this.galleryFiles); }); @@ -157,23 +154,18 @@ export default class FileAttachmentList extends Component { }; return ( - - - + theme={this.props.theme} + /> ); }); }; diff --git a/app/components/formatted_markdown_text.js b/app/components/formatted_markdown_text.js index cb11833a2..965280d45 100644 --- a/app/components/formatted_markdown_text.js +++ b/app/components/formatted_markdown_text.js @@ -116,7 +116,6 @@ class FormattedMarkdownText extends React.PureComponent { mentionStyle={this.props.textStyles.mention} mentionName={mentionName} navigator={this.props.navigator} - onLongPress={this.props.onPostPress} onPostPress={this.props.onPostPress} textStyle={this.computeTextStyle(this.props.baseTextStyle, context)} /> @@ -145,4 +144,4 @@ const getStyleSheet = makeStyleSheetFromTheme((theme) => { }; }); -export default injectIntl(FormattedMarkdownText); \ No newline at end of file +export default injectIntl(FormattedMarkdownText); diff --git a/app/components/markdown/markdown.js b/app/components/markdown/markdown.js index b37d68299..0c0c14e26 100644 --- a/app/components/markdown/markdown.js +++ b/app/components/markdown/markdown.js @@ -49,7 +49,6 @@ export default class Markdown extends PureComponent { navigator: PropTypes.object.isRequired, onChannelLinkPress: PropTypes.func, onHashtagPress: PropTypes.func, - onLongPress: PropTypes.func, onPermalinkPress: PropTypes.func, onPostPress: PropTypes.func, textStyles: PropTypes.object, @@ -80,13 +79,13 @@ export default class Markdown extends PureComponent { return new Parser({ urlFilter: this.urlFilter, }); - } + }; urlFilter = (url) => { const scheme = getScheme(url); return !scheme || this.props.autolinkedUrlSchemes.indexOf(scheme) !== -1; - } + }; createRenderer = () => { return new Renderer({ @@ -130,7 +129,7 @@ export default class Markdown extends PureComponent { renderParagraphsInLists: true, getExtraPropsForNode: this.getExtraPropsForNode, }); - } + }; getExtraPropsForNode = (node) => { const extraProps = { @@ -144,11 +143,11 @@ export default class Markdown extends PureComponent { } return extraProps; - } + }; computeTextStyle = (baseStyle, context) => { return concatStyles(baseStyle, context.map((type) => this.props.textStyles[type])); - } + }; renderText = ({context, literal}) => { if (context.indexOf('image') !== -1) { @@ -160,19 +159,17 @@ export default class Markdown extends PureComponent { const style = this.computeTextStyle(this.props.baseTextStyle, context); return {literal}; - } + }; renderCodeSpan = ({context, literal}) => { return {literal}; - } + }; renderImage = ({linkDestination, reactChildren, context, src}) => { if (context.indexOf('table') !== -1) { // We have enough problems rendering images as is, so just render a link inside of a table return ( {reactChildren} ); - } + }; renderAtMention = ({context, mentionName}) => { if (this.props.disableAtMentions) { @@ -207,12 +203,11 @@ export default class Markdown extends PureComponent { textStyle={this.computeTextStyle(this.props.baseTextStyle, context)} isSearchResult={this.props.isSearchResult} mentionName={mentionName} - onLongPress={this.props.onLongPress} onPostPress={this.props.onPostPress} navigator={this.props.navigator} /> ); - } + }; renderChannelLink = ({context, channelName}) => { if (this.props.disableChannelLink) { @@ -227,7 +222,7 @@ export default class Markdown extends PureComponent { channelName={channelName} /> ); - } + }; renderEmoji = ({context, emojiName, literal}) => { return ( @@ -237,7 +232,7 @@ export default class Markdown extends PureComponent { textStyle={this.computeTextStyle(this.props.baseTextStyle, context)} /> ); - } + }; renderHashtag = ({context, hashtag}) => { if (this.props.disableHashtags) { @@ -252,7 +247,7 @@ export default class Markdown extends PureComponent { navigator={this.props.navigator} /> ); - } + }; renderParagraph = ({children, first}) => { if (!children || children.length === 0) { @@ -271,7 +266,7 @@ export default class Markdown extends PureComponent { ); - } + }; renderHeading = ({children, level}) => { const containerStyle = [ @@ -286,7 +281,7 @@ export default class Markdown extends PureComponent { ); - } + }; renderCodeBlock = (props) => { // These sometimes include a trailing newline @@ -298,10 +293,9 @@ export default class Markdown extends PureComponent { content={content} language={props.language} textStyle={this.props.textStyles.codeBlock} - onLongPress={this.props.onLongPress} /> ); - } + }; renderBlockQuote = ({children, ...otherProps}) => { return ( @@ -312,7 +306,7 @@ export default class Markdown extends PureComponent { {children} ); - } + }; renderList = ({children, start, tight, type}) => { return ( @@ -324,7 +318,7 @@ export default class Markdown extends PureComponent { {children} ); - } + }; renderListItem = ({children, context, ...otherProps}) => { const level = context.filter((type) => type === 'list').length; @@ -338,19 +332,19 @@ export default class Markdown extends PureComponent { {children} ); - } + }; renderHardBreak = () => { return {'\n'}; - } + }; renderThematicBreak = () => { return ; - } + }; renderSoftBreak = () => { return {'\n'}; - } + }; renderHtml = (props) => { let rendered = this.renderText(props); @@ -366,7 +360,7 @@ export default class Markdown extends PureComponent { } return rendered; - } + }; renderTable = ({children}) => { return ( @@ -374,19 +368,18 @@ export default class Markdown extends PureComponent { {children} ); - } + }; renderLink = ({children, href}) => { return ( {children} ); - } + }; renderEditedIndicator = ({context}) => { let spacer = ''; @@ -411,7 +404,7 @@ export default class Markdown extends PureComponent { /> ); - } + }; render() { let ast = this.parser.parse(this.props.value); 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 f2341cf30..2cdace7ca 100644 --- a/app/components/markdown/markdown_code_block/markdown_code_block.js +++ b/app/components/markdown/markdown_code_block/markdown_code_block.js @@ -14,6 +14,7 @@ import { import CustomPropTypes from 'app/constants/custom_prop_types'; import FormattedText from 'app/components/formatted_text'; +import BottomSheet from 'app/utils/bottom_sheet'; import {getDisplayNameForLanguage} from 'app/utils/markdown'; import {preventDoubleTap} from 'app/utils/tap'; import {changeOpacity, makeStyleSheetFromTheme} from 'app/utils/theme'; @@ -28,7 +29,6 @@ export default class MarkdownCodeBlock extends React.PureComponent { language: PropTypes.string, content: PropTypes.string.isRequired, textStyle: CustomPropTypes.Style, - onLongPress: PropTypes.func.isRequired, }; static defaultProps = { @@ -84,20 +84,23 @@ export default class MarkdownCodeBlock extends React.PureComponent { const config = await mattermostManaged.getLocalConfig(); - let action; if (config.copyAndPasteProtection !== 'true') { - action = { - text: formatMessage({id: 'mobile.markdown.code.copy_code', defaultMessage: 'Copy Code'}), - onPress: this.handleCopyCode, - }; + const cancelText = formatMessage({id: 'mobile.post.cancel', defaultMessage: 'Cancel'}); + const actionText = formatMessage({id: 'mobile.markdown.code.copy_code', defaultMessage: 'Copy Code'}); + BottomSheet.showBottomSheetWithOptions({ + options: [actionText, cancelText], + cancelButtonIndex: 1, + }, (value) => { + if (value !== 1) { + this.handleCopyCode(); + } + }); } - - this.props.onLongPress(action); - } + }; handleCopyCode = () => { Clipboard.setString(this.props.content); - } + }; trimContent = (content) => { const lines = content.split('\n'); diff --git a/app/components/markdown/markdown_image/markdown_image.js b/app/components/markdown/markdown_image/markdown_image.js index 489b89859..6ab72389e 100644 --- a/app/components/markdown/markdown_image/markdown_image.js +++ b/app/components/markdown/markdown_image/markdown_image.js @@ -19,6 +19,7 @@ import FormattedText from 'app/components/formatted_text'; import ProgressiveImage from 'app/components/progressive_image'; import CustomPropTypes from 'app/constants/custom_prop_types'; import mattermostManaged from 'app/mattermost_managed'; +import BottomSheet from 'app/utils/bottom_sheet'; import ImageCacheManager from 'app/utils/image_cache_manager'; import {previewImageAtIndex, calculateDimensions} from 'app/utils/images'; import {normalizeProtocol} from 'app/utils/url'; @@ -38,7 +39,6 @@ export default class MarkdownImage extends React.Component { linkDestination: PropTypes.string, isReplyPost: PropTypes.bool, navigator: PropTypes.object.isRequired, - onLongPress: PropTypes.func, serverURL: PropTypes.string.isRequired, source: PropTypes.string.isRequired, errorTextStyle: CustomPropTypes.Style, @@ -138,15 +138,18 @@ export default class MarkdownImage extends React.Component { const config = await mattermostManaged.getLocalConfig(); - let action; if (config.copyAndPasteProtection !== 'true') { - action = { - text: formatMessage({id: 'mobile.markdown.link.copy_url', defaultMessage: 'Copy URL'}), - onPress: this.handleLinkCopy, - }; + const cancelText = formatMessage({id: 'mobile.post.cancel', defaultMessage: 'Cancel'}); + const actionText = formatMessage({id: 'mobile.markdown.link.copy_url', defaultMessage: 'Copy URL'}); + BottomSheet.showBottomSheetWithOptions({ + options: [actionText, cancelText], + cancelButtonIndex: 1, + }, (value) => { + if (value !== 1) { + this.handleLinkCopy(); + } + }); } - - this.props.onLongPress(action); }; handleLinkCopy = () => { diff --git a/app/components/markdown/markdown_link/markdown_link.js b/app/components/markdown/markdown_link/markdown_link.js index 52867c020..3148eb094 100644 --- a/app/components/markdown/markdown_link/markdown_link.js +++ b/app/components/markdown/markdown_link/markdown_link.js @@ -9,24 +9,22 @@ import {intlShape} from 'react-intl'; import CustomPropTypes from 'app/constants/custom_prop_types'; import mattermostManaged from 'app/mattermost_managed'; - -import Config from 'assets/config'; - +import BottomSheet from 'app/utils/bottom_sheet'; import {preventDoubleTap} from 'app/utils/tap'; import {matchPermalink, normalizeProtocol} from 'app/utils/url'; +import Config from 'assets/config'; + export default class MarkdownLink extends PureComponent { static propTypes = { children: CustomPropTypes.Children.isRequired, href: PropTypes.string.isRequired, - onLongPress: PropTypes.func, onPermalinkPress: PropTypes.func, serverURL: PropTypes.string.isRequired, siteURL: PropTypes.string.isRequired, }; static defaultProps = { - onLongPress: () => true, onPermalinkPress: () => true, }; @@ -89,27 +87,30 @@ export default class MarkdownLink extends PureComponent { ...otherChildProps, }; }); - } + }; handleLongPress = async () => { const {formatMessage} = this.context.intl; const config = await mattermostManaged.getLocalConfig(); - let action; if (config.copyAndPasteProtection !== 'true') { - action = { - text: formatMessage({id: 'mobile.markdown.link.copy_url', defaultMessage: 'Copy URL'}), - onPress: this.handleCopyURL, - }; + const cancelText = formatMessage({id: 'mobile.post.cancel', defaultMessage: 'Cancel'}); + const actionText = formatMessage({id: 'mobile.markdown.link.copy_url', defaultMessage: 'Copy URL'}); + BottomSheet.showBottomSheetWithOptions({ + options: [actionText, cancelText], + cancelButtonIndex: 1, + }, (value) => { + if (value !== 1) { + this.handleLinkCopy(); + } + }); } - - this.props.onLongPress(action); - } + }; handleCopyURL = () => { Clipboard.setString(this.props.href); - } + }; render() { const children = Config.ExperimentalNormalizeMarkdownLinks ? this.parseChildren() : this.props.children; diff --git a/app/components/message_attachments/index.js b/app/components/message_attachments/index.js index 857422ee4..da6e1ddbe 100644 --- a/app/components/message_attachments/index.js +++ b/app/components/message_attachments/index.js @@ -17,7 +17,6 @@ export default class MessageAttachments extends PureComponent { postId: PropTypes.string.isRequired, navigator: PropTypes.object.isRequired, onHashtagPress: PropTypes.func, - onLongPress: PropTypes.func.isRequired, onPermalinkPress: PropTypes.func, theme: PropTypes.object, textStyles: PropTypes.object, @@ -30,7 +29,6 @@ export default class MessageAttachments extends PureComponent { blockStyles, navigator, onHashtagPress, - onLongPress, onPermalinkPress, postId, theme, @@ -47,7 +45,6 @@ export default class MessageAttachments extends PureComponent { key={'att_' + i} navigator={navigator} onHashtagPress={onHashtagPress} - onLongPress={onLongPress} onPermalinkPress={onPermalinkPress} postId={postId} theme={theme} diff --git a/app/components/message_attachments/message_attachment.js b/app/components/message_attachments/message_attachment.js index 7b8557fc5..7e6131dd0 100644 --- a/app/components/message_attachments/message_attachment.js +++ b/app/components/message_attachments/message_attachment.js @@ -40,7 +40,6 @@ export default class MessageAttachment extends PureComponent { blockStyles: PropTypes.object, navigator: PropTypes.object.isRequired, postId: PropTypes.string.isRequired, - onLongPress: PropTypes.func.isRequired, onPermalinkPress: PropTypes.func, theme: PropTypes.object, textStyles: PropTypes.object, @@ -194,7 +193,6 @@ export default class MessageAttachment extends PureComponent { blockStyles={blockStyles} value={(field.value || '')} navigator={navigator} - onLongPress={this.props.onLongPress} onPermalinkPress={onPermalinkPress} /> @@ -317,7 +315,6 @@ export default class MessageAttachment extends PureComponent { blockStyles={blockStyles} value={attachment.pretext} navigator={navigator} - onLongPress={this.props.onLongPress} onPermalinkPress={onPermalinkPress} /> @@ -415,7 +412,6 @@ export default class MessageAttachment extends PureComponent { blockStyles={blockStyles} value={attachment.text} navigator={navigator} - onLongPress={this.props.onLongPress} onPermalinkPress={onPermalinkPress} /> diff --git a/app/components/options_context/index.js b/app/components/options_context/index.js deleted file mode 100644 index 98c033d65..000000000 --- a/app/components/options_context/index.js +++ /dev/null @@ -1,6 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -// Used to leverage the platform specific components -import OptionsContext from './options_context'; -export default OptionsContext; diff --git a/app/components/options_context/options_context.android.js b/app/components/options_context/options_context.android.js deleted file mode 100644 index f0249d87c..000000000 --- a/app/components/options_context/options_context.android.js +++ /dev/null @@ -1,71 +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 {TouchableHighlight, View} from 'react-native'; -import RNBottomSheet from 'react-native-bottom-sheet'; - -export default class OptionsContext extends PureComponent { - static propTypes = { - getPostActions: PropTypes.func, - cancelText: PropTypes.string, - children: PropTypes.node.isRequired, - onPress: PropTypes.func.isRequired, - toggleSelected: PropTypes.func.isRequired, - }; - - static defaultProps = { - getPostActions: () => [], - cancelText: 'Cancel', - }; - - show = (additionalAction) => { - const {getPostActions, cancelText} = this.props; - const nextActions = getPostActions(); - if (additionalAction && !additionalAction.nativeEvent && additionalAction.text) { - const copyPostIndex = nextActions.findIndex((action) => action.copyPost); - nextActions.splice(copyPostIndex + 1, 0, additionalAction); - } - - if (nextActions.length) { - const actionsText = nextActions.map((a) => a.text); - RNBottomSheet.showBottomSheetWithOptions({ - options: [...actionsText, cancelText], - cancelButtonIndex: nextActions.length, - }, (value) => { - if (value !== nextActions.length) { - const selectedOption = nextActions[value]; - if (selectedOption && selectedOption.onPress) { - selectedOption.onPress(); - } - } - }); - } - }; - - handleHideUnderlay = () => { - this.props.toggleSelected(false, this.props.getPostActions().length > 0); - }; - - handleShowUnderlay = () => { - this.props.toggleSelected(true, this.props.getPostActions().length > 0); - }; - - render() { - return ( - - - {this.props.children} - - - ); - } -} diff --git a/app/components/options_context/options_context.ios.js b/app/components/options_context/options_context.ios.js deleted file mode 100644 index 12713d6a6..000000000 --- a/app/components/options_context/options_context.ios.js +++ /dev/null @@ -1,108 +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 ToolTip from 'app/components/tooltip'; - -export default class OptionsContext extends PureComponent { - static propTypes = { - getPostActions: PropTypes.func, - children: PropTypes.node.isRequired, - onPress: PropTypes.func.isRequired, - toggleSelected: PropTypes.func.isRequired, - }; - - static defaultProps = { - getPostActions: () => [], - additionalActions: [], - }; - - constructor(props) { - super(props); - - this.state = { - actions: props.getPostActions(), - }; - } - - beforeShow = (additionalAction) => { - const nextActions = this.props.getPostActions(); - if (additionalAction && additionalAction.text && !additionalAction.nativeEvent) { - const copyPostIndex = nextActions.findIndex((action) => action.copyPost); - nextActions.splice(copyPostIndex + 1, 0, additionalAction); - } - - this.setState({ - actions: nextActions, - }); - }; - - handleHide = () => { - this.isShowing = false; - this.props.toggleSelected(false); - }; - - handleHideUnderlay = () => { - if (!this.isShowing) { - this.props.toggleSelected(false); - } - }; - - handleShow = () => { - this.isShowing = true; - this.props.toggleSelected(true); - } - - handleShowUnderlay = () => { - this.beforeShow(); - this.props.toggleSelected(true); - }; - - hide = () => { - this.setState({ - actions: this.props.getPostActions(), - }); - - if (this.refs.toolTip) { - this.refs.toolTip.hideMenu(); - } - - this.isShowing = false; - this.props.toggleSelected(false); - }; - - handlePress = () => { - this.props.toggleSelected(false); - this.props.onPress(); - }; - - show = (additionalAction) => { - this.props.toggleSelected(true); - this.beforeShow(additionalAction); - - if (this.refs.toolTip) { - this.refs.toolTip.showMenu(); - } - }; - - render() { - return ( - - {this.props.children} - - ); - } -} diff --git a/app/components/post/index.js b/app/components/post/index.js index 97d74b1cf..cda62802d 100644 --- a/app/components/post/index.js +++ b/app/components/post/index.js @@ -4,19 +4,15 @@ import {connect} from 'react-redux'; import {bindActionCreators} from 'redux'; -import {createPost, deletePost, removePost} from 'mattermost-redux/actions/posts'; -import {General, Posts} from 'mattermost-redux/constants'; -import {getCurrentChannelId, isCurrentChannelReadOnly} from 'mattermost-redux/selectors/entities/channels'; +import {createPost, removePost} from 'mattermost-redux/actions/posts'; +import {Posts} from 'mattermost-redux/constants'; +import {isCurrentChannelReadOnly} from 'mattermost-redux/selectors/entities/channels'; import {getPost, makeGetCommentCountForPost} from 'mattermost-redux/selectors/entities/posts'; -import {getCurrentUserId, getCurrentUserRoles} from 'mattermost-redux/selectors/entities/users'; +import {getCurrentUserId} from 'mattermost-redux/selectors/entities/users'; import {getMyPreferences, getTheme} from 'mattermost-redux/selectors/entities/preferences'; -import {getCurrentTeamUrl, getCurrentTeamId} from 'mattermost-redux/selectors/entities/teams'; -import {canDeletePost, canEditPost, isPostFlagged, isSystemMessage} from 'mattermost-redux/utils/post_utils'; -import {isAdmin as checkIsAdmin, isSystemAdmin as checkIsSystemAdmin} from 'mattermost-redux/utils/user_utils'; -import {getConfig, getLicense} from 'mattermost-redux/selectors/entities/general'; +import {isPostFlagged, isSystemMessage} from 'mattermost-redux/utils/post_utils'; import {insertToDraft, setPostTooltipVisible} from 'app/actions/views/channel'; -import {addReaction} from 'app/actions/views/emoji'; import Post from './post'; @@ -45,13 +41,8 @@ function makeMapStateToProps() { const getCommentCountForPost = makeGetCommentCountForPost(); return function mapStateToProps(state, ownProps) { const post = getPost(state, ownProps.postId); - const config = getConfig(state); - const license = getLicense(state); - const roles = getCurrentUserId(state) ? getCurrentUserRoles(state) : ''; const myPreferences = getMyPreferences(state); const currentUserId = getCurrentUserId(state); - const currentTeamId = getCurrentTeamId(state); - const currentChannelId = getCurrentChannelId(state); let isFirstReply = true; let isLastReply = true; @@ -78,28 +69,8 @@ function makeMapStateToProps() { } } - const isAdmin = checkIsAdmin(roles); - const isSystemAdmin = checkIsSystemAdmin(roles); - - let canDelete = false; - let canEdit = false; - let canEditUntil = -1; - if (post) { - canDelete = canDeletePost(state, config, license, currentTeamId, currentChannelId, currentUserId, post, isAdmin, isSystemAdmin); - canEdit = canEditPost(state, config, license, currentTeamId, currentChannelId, currentUserId, post); - if (canEdit && license.IsLicensed === 'true' && - (config.AllowEditPost === General.ALLOW_EDIT_POST_TIME_LIMIT || (config.PostEditTimeLimit !== -1 && config.PostEditTimeLimit !== '-1')) - ) { - canEditUntil = post.create_at + (config.PostEditTimeLimit * 1000); - } - } - return { channelIsReadOnly: isCurrentChannelReadOnly(state), - canDelete, - canEdit, - canEditUntil, - currentTeamUrl: getCurrentTeamUrl(state), currentUserId, post, isFirstReply, @@ -116,9 +87,7 @@ function makeMapStateToProps() { function mapDispatchToProps(dispatch) { return { actions: bindActionCreators({ - addReaction, createPost, - deletePost, removePost, setPostTooltipVisible, insertToDraft, diff --git a/app/components/post/post.js b/app/components/post/post.js index d30ceddf4..60d1a1747 100644 --- a/app/components/post/post.js +++ b/app/components/post/post.js @@ -4,15 +4,12 @@ import React, {PureComponent} from 'react'; import PropTypes from 'prop-types'; import { - Alert, - Clipboard, Platform, TouchableHighlight, View, ViewPropTypes, } from 'react-native'; import {intlShape} from 'react-intl'; -import MaterialIcon from 'react-native-vector-icons/MaterialIcons'; import FlagIcon from 'app/components/flag_icon'; import PostBody from 'app/components/post_body'; @@ -22,7 +19,6 @@ import {NavigationTypes} from 'app/constants'; import {fromAutoResponder} from 'app/utils/general'; import {preventDoubleTap} from 'app/utils/tap'; import {changeOpacity, makeStyleSheetFromTheme} from 'app/utils/theme'; -import {getToolTipVisible} from 'app/utils/tooltip'; import {t} from 'app/utils/i18n'; import {Posts} from 'mattermost-redux/constants'; @@ -34,14 +30,11 @@ import Config from 'assets/config'; export default class Post extends PureComponent { static propTypes = { actions: PropTypes.shape({ - addReaction: PropTypes.func.isRequired, createPost: PropTypes.func.isRequired, - deletePost: PropTypes.func.isRequired, insertToDraft: PropTypes.func.isRequired, removePost: PropTypes.func.isRequired, }).isRequired, channelIsReadOnly: PropTypes.bool, - currentTeamUrl: PropTypes.string.isRequired, currentUserId: PropTypes.string.isRequired, highlight: PropTypes.bool, style: ViewPropTypes.style, @@ -56,9 +49,6 @@ export default class Post extends PureComponent { commentedOnPost: PropTypes.object, managedConfig: PropTypes.object.isRequired, navigator: PropTypes.object, - canEdit: PropTypes.bool.isRequired, - canEditUntil: PropTypes.number.isRequired, - canDelete: PropTypes.bool.isRequired, onHashtagPress: PropTypes.func, onPermalinkPress: PropTypes.func, shouldRenderReplyButton: PropTypes.bool, @@ -112,83 +102,6 @@ export default class Post extends PureComponent { this.props.actions.insertToDraft(`@${username} `); }; - handlePostDelete = () => { - const {formatMessage} = this.context.intl; - const {actions, currentUserId, post} = this.props; - - Alert.alert( - formatMessage({id: 'mobile.post.delete_title', defaultMessage: 'Delete Post'}), - formatMessage({ - id: 'mobile.post.delete_question', - defaultMessage: 'Are you sure you want to delete this post?', - }), - [{ - text: formatMessage({id: 'mobile.post.cancel', defaultMessage: 'Cancel'}), - style: 'cancel', - }, { - text: formatMessage({id: 'post_info.del', defaultMessage: 'Delete'}), - style: 'destructive', - onPress: () => { - actions.deletePost(post); - if (post.user_id === currentUserId) { - actions.removePost(post); - } - }, - }] - ); - }; - - handlePostEdit = () => { - const {intl} = this.context; - const {navigator, post, theme} = this.props; - MaterialIcon.getImageSource('close', 20, theme.sidebarHeaderTextColor).then((source) => { - navigator.showModal({ - screen: 'EditPost', - title: intl.formatMessage({id: 'mobile.edit_post.title', defaultMessage: 'Editing Message'}), - animated: true, - navigatorStyle: { - navBarTextColor: theme.sidebarHeaderTextColor, - navBarBackgroundColor: theme.sidebarHeaderBg, - navBarButtonColor: theme.sidebarHeaderTextColor, - screenBackgroundColor: theme.centerChannelBg, - }, - passProps: { - post, - closeButton: source, - }, - }); - }); - }; - - handleAddReactionToPost = (emoji) => { - const {post} = this.props; - this.props.actions.addReaction(post.id, emoji); - }; - - handleAddReaction = preventDoubleTap(() => { - const {intl} = this.context; - const {navigator, post, theme} = this.props; - - MaterialIcon.getImageSource('close', 20, theme.sidebarHeaderTextColor).then((source) => { - navigator.showModal({ - screen: 'AddReaction', - title: intl.formatMessage({id: 'mobile.post_info.add_reaction', defaultMessage: 'Add Reaction'}), - animated: true, - navigatorStyle: { - navBarTextColor: theme.sidebarHeaderTextColor, - navBarBackgroundColor: theme.sidebarHeaderBg, - navBarButtonColor: theme.sidebarHeaderTextColor, - screenBackgroundColor: theme.centerChannelBg, - }, - passProps: { - post, - closeButton: source, - onEmojiPress: this.handleAddReactionToPost, - }, - }); - }); - }); - handleFailedPostPress = () => { const options = { title: { @@ -246,22 +159,17 @@ export default class Post extends PureComponent { showLongPost, } = this.props; - if (!getToolTipVisible()) { - const isValidSystemMessage = fromAutoResponder(post) || !isSystemMessage(post); - if (onPress && post.state !== Posts.POST_DELETED && isValidSystemMessage && !isPostPendingOrFailed(post)) { - onPress(post); - } else if ((isPostEphemeral(post) || post.state === Posts.POST_DELETED) && !showLongPost) { - this.onRemovePost(post); - } - } else if (this.refs.postBody) { - this.refs.postBody.getWrappedInstance().hideOptionsContext(); - this.handleHideUnderlay(); + const isValidSystemMessage = fromAutoResponder(post) || !isSystemMessage(post); + if (onPress && post.state !== Posts.POST_DELETED && isValidSystemMessage && !isPostPendingOrFailed(post)) { + onPress(post); + } else if ((isPostEphemeral(post) || post.state === Posts.POST_DELETED) && !showLongPost) { + this.onRemovePost(post); } }); handleReply = preventDoubleTap(() => { const {post, onReply} = this.props; - if (!getToolTipVisible() && onReply) { + if (onReply) { return onReply(post); } @@ -305,31 +213,13 @@ export default class Post extends PureComponent { }; viewUserProfile = preventDoubleTap(() => { - if (!getToolTipVisible()) { - this.goToUserProfile(); - } + this.goToUserProfile(); }); toggleSelected = (selected) => { this.setState({selected}); }; - handleCopyText = (text) => { - let textToCopy = this.props.post.message; - if (typeof text === 'string') { - textToCopy = text; - } - - Clipboard.setString(textToCopy); - }; - - handleCopyPermalink = () => { - const {currentTeamUrl, postId} = this.props; - const permalink = `${currentTeamUrl}/pl/${postId}`; - - Clipboard.setString(permalink); - }; - handleHideUnderlay = () => { this.toggleSelected(false); }; @@ -338,9 +228,9 @@ export default class Post extends PureComponent { this.toggleSelected(true); }; - showOptionsContext = () => { + showPostOptions = () => { if (this.refs.postBody) { - this.refs.postBody.getWrappedInstance().showOptionsContext(); + this.refs.postBody.getWrappedInstance().showPostOptions(); } }; @@ -405,7 +295,7 @@ export default class Post extends PureComponent { onPress={this.handlePress} onHideUnderlay={this.handleHideUnderlay} onShowUnderlay={this.handleShowUnderlay} - onLongPress={this.showOptionsContext} + onLongPress={this.showPostOptions} underlayColor='transparent' > @@ -114,7 +112,6 @@ export default class PostAddChannelMember extends React.PureComponent { key={username} mentionStyle={this.props.textStyles.mention} mentionName={username} - onLongPress={this.props.onLongPress} onPostPress={this.props.onPostPress} navigator={this.props.navigator} /> @@ -192,4 +189,4 @@ export default class PostAddChannelMember extends React.PureComponent { ); } -} \ No newline at end of file +} diff --git a/app/components/post_body/index.js b/app/components/post_body/index.js index 82bc3ef58..62854803a 100644 --- a/app/components/post_body/index.js +++ b/app/components/post_body/index.js @@ -2,27 +2,19 @@ // See LICENSE.txt for license information. import {connect} from 'react-redux'; -import {bindActionCreators} from 'redux'; -import {flagPost, unflagPost} from 'mattermost-redux/actions/posts'; -import { - General, - Posts, -} from 'mattermost-redux/constants'; +import {General, Posts} from 'mattermost-redux/constants'; import {getChannel, canManageChannelMembers, getCurrentChannelId} from 'mattermost-redux/selectors/entities/channels'; import {getPost} from 'mattermost-redux/selectors/entities/posts'; import {getTheme} from 'mattermost-redux/selectors/entities/preferences'; -import {hasNewPermissions, getConfig, getLicense} from 'mattermost-redux/selectors/entities/general'; -import {haveIChannelPermission} from 'mattermost-redux/selectors/entities/roles'; +import {getConfig, getLicense} from 'mattermost-redux/selectors/entities/general'; import {getCurrentUserId, getCurrentUserRoles} from 'mattermost-redux/selectors/entities/users'; import {getCurrentTeamId} from 'mattermost-redux/selectors/entities/teams'; -import Permissions from 'mattermost-redux/constants/permissions'; import { isEdited, isPostEphemeral, isSystemMessage, - canEditPost, canDeletePost, } from 'mattermost-redux/utils/post_utils'; import {isAdmin as checkIsAdmin, isSystemAdmin as checkIsSystemAdmin} from 'mattermost-redux/utils/user_utils'; @@ -34,19 +26,6 @@ const POST_TIMEOUT = 20000; function mapStateToProps(state, ownProps) { const post = getPost(state, ownProps.postId) || {}; const channel = getChannel(state, post.channel_id) || {}; - const channelIsArchived = channel ? channel.delete_at !== 0 : false; - const teamId = channel.team_id; - - let canAddReaction = true; - if (channelIsArchived) { - canAddReaction = false; - } else if (hasNewPermissions(state)) { - canAddReaction = haveIChannelPermission(state, { - team: teamId, - channel: post.channel_id, - permission: Permissions.ADD_REACTION, - }); - } let isFailed = post.failed; let isPending = post.id === post.pending_post_id; @@ -69,12 +48,9 @@ function mapStateToProps(state, ownProps) { const isAdmin = checkIsAdmin(roles); const isSystemAdmin = checkIsSystemAdmin(roles); let canDelete = false; - let canEdit = false; - if (post) { - if (!channelIsArchived) { - canDelete = canDeletePost(state, config, license, currentTeamId, currentChannelId, currentUserId, post, isAdmin, isSystemAdmin); - canEdit = canEditPost(state, config, license, currentTeamId, currentChannelId, currentUserId, post); - } + + if (post && !ownProps.channelIsArchived) { + canDelete = canDeletePost(state, config, license, currentTeamId, currentChannelId, currentUserId, post, isAdmin, isSystemAdmin); } let isPostAddChannelMember = false; @@ -103,19 +79,8 @@ function mapStateToProps(state, ownProps) { isSystemMessage: isSystemMessage(post), message: post.message, theme: getTheme(state), - canAddReaction, canDelete, - canEdit, }; } -function mapDispatchToProps(dispatch) { - return { - actions: bindActionCreators({ - flagPost, - unflagPost, - }, dispatch), - }; -} - -export default connect(mapStateToProps, mapDispatchToProps, null, {withRef: true})(PostBody); +export default connect(mapStateToProps, null, null, {withRef: true})(PostBody); diff --git a/app/components/post_body/post_body.js b/app/components/post_body/post_body.js index 0138c6101..4eb82b440 100644 --- a/app/components/post_body/post_body.js +++ b/app/components/post_body/post_body.js @@ -5,7 +5,6 @@ import React, {PureComponent} from 'react'; import PropTypes from 'prop-types'; import { Dimensions, - Platform, TouchableHighlight, TouchableOpacity, View, @@ -18,7 +17,6 @@ import {Posts} from 'mattermost-redux/constants'; import CombinedSystemMessage from 'app/components/combined_system_message'; import FormattedText from 'app/components/formatted_text'; import Markdown from 'app/components/markdown'; -import OptionsContext from 'app/components/options_context'; import ShowMoreButton from 'app/components/show_more_button'; import {emptyFunction} from 'app/utils/general'; @@ -33,14 +31,7 @@ let Reactions; export default class PostBody extends PureComponent { static propTypes = { - actions: PropTypes.shape({ - flagPost: PropTypes.func.isRequired, - unflagPost: PropTypes.func.isRequired, - }).isRequired, - canAddReaction: PropTypes.bool, canDelete: PropTypes.bool, - canEdit: PropTypes.bool, - canEditUntil: PropTypes.number.isRequired, channelIsReadOnly: PropTypes.bool.isRequired, fileIds: PropTypes.array, hasBeenDeleted: PropTypes.bool, @@ -58,14 +49,9 @@ export default class PostBody extends PureComponent { managedConfig: PropTypes.object, message: PropTypes.string, navigator: PropTypes.object.isRequired, - onAddReaction: PropTypes.func, - onCopyPermalink: PropTypes.func, - onCopyText: PropTypes.func, onFailedPostPress: PropTypes.func, onHashtagPress: PropTypes.func, onPermalinkPress: PropTypes.func, - onPostDelete: PropTypes.func, - onPostEdit: PropTypes.func, onPress: PropTypes.func, postId: PropTypes.string.isRequired, postProps: PropTypes.object, @@ -79,12 +65,7 @@ export default class PostBody extends PureComponent { static defaultProps = { fileIds: [], - onAddReaction: emptyFunction, - onCopyPermalink: emptyFunction, - onCopyText: emptyFunction, onFailedPostPress: emptyFunction, - onPostDelete: emptyFunction, - onPostEdit: emptyFunction, onPress: emptyFunction, replyBarStyle: [], toggleSelected: emptyFunction, @@ -98,11 +79,6 @@ export default class PostBody extends PureComponent { isLongPost: false, }; - flagPost = () => { - const {actions, postId} = this.props; - actions.flagPost(postId); - }; - handleHideUnderlay = () => { this.props.toggleSelected(false); }; @@ -111,84 +87,6 @@ export default class PostBody extends PureComponent { this.props.toggleSelected(true); }; - hideOptionsContext = () => { - if (Platform.OS === 'ios' && this.refs.options) { - this.refs.options.hide(); - } - }; - - getPostActions = () => { - const {formatMessage} = this.context.intl; - const { - canEdit, - canEditUntil, - canDelete, - canAddReaction, - channelIsReadOnly, - hasBeenDeleted, - isPending, - isFailed, - isFlagged, - isPostEphemeral, - isSystemMessage, - managedConfig, - message, - onCopyText, - onPostDelete, - onPostEdit, - showAddReaction, - } = this.props; - const actions = []; - const isPendingOrFailedPost = isPending || isFailed; - - // we should check for the user roles and permissions - if (!isPendingOrFailedPost && !isSystemMessage && !isPostEphemeral) { - if (showAddReaction && canAddReaction && !channelIsReadOnly) { - actions.push({ - text: formatMessage({id: 'mobile.post_info.add_reaction', defaultMessage: 'Add Reaction'}), - onPress: this.props.onAddReaction, - }); - } - - if (managedConfig.copyAndPasteProtection !== 'true' && message) { - actions.push({ - text: formatMessage({id: 'mobile.post_info.copy_post', defaultMessage: 'Copy Post'}), - onPress: onCopyText, - copyPost: true, - }); - } - - if (!channelIsReadOnly) { - if (isFlagged) { - actions.push({ - text: formatMessage({id: 'post_info.mobile.unflag', defaultMessage: 'Unflag'}), - onPress: this.unflagPost, - }); - } else { - actions.push({ - text: formatMessage({id: 'post_info.mobile.flag', defaultMessage: 'Flag'}), - onPress: this.flagPost, - }); - } - } - - if (canEdit && (canEditUntil === -1 || canEditUntil > Date.now())) { - actions.push({text: formatMessage({id: 'post_info.edit', defaultMessage: 'Edit'}), onPress: onPostEdit}); - } - - actions.push({ - text: formatMessage({id: 'get_post_link_modal.title', defaultMessage: 'Copy Permalink'}), - onPress: this.props.onCopyPermalink, - }); - } - - if (!isPendingOrFailedPost && !isPostEphemeral && canDelete && !hasBeenDeleted) { - actions.push({text: formatMessage({id: 'post_info.del', defaultMessage: 'Delete'}), onPress: onPostDelete}); - } - - return actions; - }; - measurePost = (event) => { const {height} = event.nativeEvent.layout; const {height: deviceHeight} = Dimensions.get('window'); @@ -206,7 +104,6 @@ export default class PostBody extends PureComponent { const { managedConfig, navigator, - onAddReaction, onHashtagPress, onPermalinkPress, postId, @@ -225,7 +122,6 @@ export default class PostBody extends PureComponent { passProps: { postId, managedConfig, - onAddReaction, onHashtagPress, onPermalinkPress, }, @@ -234,15 +130,51 @@ export default class PostBody extends PureComponent { navigator.showModal(options); }); - unflagPost = () => { - const {actions, postId} = this.props; - actions.unflagPost(postId); - }; + showPostOptions = () => { + const { + canDelete, + channelIsReadOnly, + hasBeenDeleted, + isFailed, + isFlagged, + isPending, + isPostEphemeral, + isSystemMessage, + managedConfig, + navigator, + postId, + showAddReaction, + } = this.props; - showOptionsContext = (additionalAction) => { - if (this.refs.options) { - this.refs.options.show(additionalAction); + if (isSystemMessage && (!canDelete || hasBeenDeleted)) { + return; } + + if (isPending || isFailed || isPostEphemeral) { + return; + } + + const options = { + screen: 'PostOptions', + animationType: 'none', + backButtonTitle: '', + navigatorStyle: { + navBarHidden: true, + screenBackgroundColor: 'transparent', + modalPresentationStyle: 'overCurrentContext', + }, + passProps: { + canDelete, + channelIsReadOnly, + hasBeenDeleted, + isFlagged, + postId, + managedConfig, + showAddReaction, + }, + }; + + navigator.showModal(options); }; renderAddChannelMember = (style, messageStyle, textStyles) => { @@ -258,7 +190,6 @@ export default class PostBody extends PureComponent { ); @@ -334,7 +263,6 @@ export default class PostBody extends PureComponent { hasReactions, isSearchResult, navigator, - onAddReaction, postId, showLongPost, } = this.props; @@ -350,14 +278,12 @@ export default class PostBody extends PureComponent { return ( ); }; render() { - const {formatMessage} = this.context.intl; const { hasBeenDeleted, hasBeenEdited, @@ -378,7 +304,6 @@ export default class PostBody extends PureComponent { postType, replyBarStyle, theme, - toggleSelected, } = this.props; const {isLongPost, maxHeight} = this.state; const style = getStyleSheet(theme); @@ -412,7 +337,7 @@ export default class PostBody extends PureComponent { } else if (postType === Posts.POST_TYPES.COMBINED_USER_ACTIVITY) { const {allUserIds, allUsernames, messageData} = postProps.user_activity; messageComponent = ( - + - + + {messageComponent} {isLongPost && @@ -476,8 +400,8 @@ export default class PostBody extends PureComponent { {this.renderPostAdditionalContent(blockStyles, messageStyle, textStyles)} {this.renderFileAttachments()} {this.renderReactions()} - - + + ); } 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 addbadcbb..7ec33087f 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 @@ -19,7 +19,6 @@ import {intlShape} from 'react-intl'; import ProgressiveImage from 'app/components/progressive_image'; import CustomPropTypes from 'app/constants/custom_prop_types'; -import {emptyFunction} from 'app/utils/general'; import ImageCacheManager from 'app/utils/image_cache_manager'; import {previewImageAtIndex, calculateDimensions} from 'app/utils/images'; import {getYouTubeVideoId, isImageLink, isYoutubeLink} from 'app/utils/url'; @@ -45,7 +44,6 @@ export default class PostBodyAdditionalContent extends PureComponent { message: PropTypes.string.isRequired, navigator: PropTypes.object.isRequired, onHashtagPress: PropTypes.func, - onLongPress: PropTypes.func, onPermalinkPress: PropTypes.func, openGraphData: PropTypes.object, postId: PropTypes.string.isRequired, @@ -55,10 +53,6 @@ export default class PostBodyAdditionalContent extends PureComponent { theme: PropTypes.object.isRequired, }; - static defaultProps = { - onLongPress: emptyFunction, - }; - static contextTypes = { intl: intlShape.isRequired, }; @@ -311,7 +305,6 @@ export default class PostBodyAdditionalContent extends PureComponent { textStyles={textStyles} theme={theme} onHashtagPress={onHashtagPress} - onLongPress={this.props.onLongPress} onPermalinkPress={onPermalinkPress} /> ); diff --git a/app/components/reactions/reactions.js b/app/components/reactions/reactions.js index 602767870..bd6d69439 100644 --- a/app/components/reactions/reactions.js +++ b/app/components/reactions/reactions.js @@ -9,7 +9,10 @@ import { TouchableOpacity, View, } from 'react-native'; +import {intlShape} from 'react-intl'; +import MaterialIcon from 'react-native-vector-icons/MaterialIcons'; +import {preventDoubleTap} from 'app/utils/tap'; import {changeOpacity, makeStyleSheetFromTheme} from 'app/utils/theme'; import addReactionIcon from 'assets/images/icons/reaction.png'; @@ -24,7 +27,6 @@ export default class Reactions extends PureComponent { }).isRequired, highlightedReactions: PropTypes.array.isRequired, navigator: PropTypes.object.isRequired, - onAddReaction: PropTypes.func.isRequired, position: PropTypes.oneOf(['right', 'left']), postId: PropTypes.string.isRequired, reactions: PropTypes.object.isRequired, @@ -37,11 +39,43 @@ export default class Reactions extends PureComponent { position: 'right', }; + static contextTypes = { + intl: intlShape.isRequired, + }; + componentDidMount() { const {actions, postId} = this.props; actions.getReactionsForPost(postId); } + handleAddReaction = preventDoubleTap(() => { + const {formatMessage} = this.context.intl; + const {navigator, theme} = this.props; + + MaterialIcon.getImageSource('close', 20, theme.sidebarHeaderTextColor).then((source) => { + navigator.showModal({ + screen: 'AddReaction', + title: formatMessage({id: 'mobile.post_info.add_reaction', defaultMessage: 'Add Reaction'}), + animated: true, + navigatorStyle: { + navBarTextColor: theme.sidebarHeaderTextColor, + navBarBackgroundColor: theme.sidebarHeaderBg, + navBarButtonColor: theme.sidebarHeaderTextColor, + screenBackgroundColor: theme.centerChannelBg, + }, + passProps: { + closeButton: source, + onEmojiPress: this.handleAddReactionToPost, + }, + }); + }); + }); + + handleAddReactionToPost = (emoji) => { + const {postId} = this.props; + this.props.actions.addReaction(postId, emoji); + }; + handleReactionPress = (emoji, remove) => { const {actions, postId} = this.props; if (remove && this.props.canRemoveReaction) { @@ -104,7 +138,7 @@ export default class Reactions extends PureComponent { addMoreReactions = ( { + onMoveShouldSetPanResponderCapture: (evt, gestureState) => { + if (this.props.alwaysCaptureContainerMove) { + return gestureState.dy !== 0; + } const isGoingDown = gestureState.y0 < gestureState.dy; return this.isAValidMovement(gestureState.dx, gestureState.dy, isGoingDown); }, onPanResponderMove: (evt, gestureState) => { + const isGoingDown = gestureState.dy > 0; + if (this.props.alwaysCaptureContainerMove && + !this.isAValidMovement(gestureState.dx, gestureState.dy, isGoingDown)) { + return; + } + this.moveStart(gestureState); }, onPanResponderRelease: (evt, gestureState) => { diff --git a/app/screens/index.js b/app/screens/index.js index cab6f1f7b..6bee81ef7 100644 --- a/app/screens/index.js +++ b/app/screens/index.js @@ -46,6 +46,7 @@ export function registerScreens(store, Provider) { Navigation.registerComponent('NotificationSettingsMobile', () => wrapWithContextProvider(require('app/screens/settings/notification_settings_mobile').default), store, Provider); Navigation.registerComponent('OptionsModal', () => wrapWithContextProvider(require('app/screens/options_modal').default), store, Provider); Navigation.registerComponent('Permalink', () => wrapWithContextProvider(require('app/screens/permalink').default), store, Provider); + Navigation.registerComponent('PostOptions', () => wrapWithContextProvider(require('app/screens/post_options').default), store, Provider); Navigation.registerComponent('ReactionList', () => wrapWithContextProvider(require('app/screens/reaction_list').default), store, Provider); Navigation.registerComponent('RecentMentions', () => wrapWithContextProvider(require('app/screens/recent_mentions').default), store, Provider); Navigation.registerComponent('Root', () => require('app/screens/root').default, store, Provider); diff --git a/app/screens/long_post/long_post.js b/app/screens/long_post/long_post.js index d90d477d2..56fb0b596 100644 --- a/app/screens/long_post/long_post.js +++ b/app/screens/long_post/long_post.js @@ -51,7 +51,6 @@ export default class LongPost extends PureComponent { inThreadView: PropTypes.bool, managedConfig: PropTypes.object, navigator: PropTypes.object, - onAddReaction: PropTypes.func, onHashtagPress: PropTypes.func, onPermalinkPress: PropTypes.func, postId: PropTypes.string.isRequired, @@ -141,7 +140,6 @@ export default class LongPost extends PureComponent { { - const {hasReactions, postId, onAddReaction} = this.props; + const {hasReactions, navigator, postId} = this.props; if (!hasReactions) { return null; @@ -164,9 +162,9 @@ export default class LongPost extends PureComponent { return ( ); diff --git a/app/screens/post_options/index.js b/app/screens/post_options/index.js new file mode 100644 index 000000000..3771540cf --- /dev/null +++ b/app/screens/post_options/index.js @@ -0,0 +1,81 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +import {bindActionCreators} from 'redux'; +import {connect} from 'react-redux'; + +import {deletePost, flagPost, unflagPost, removePost} from 'mattermost-redux/actions/posts'; +import {General, Permissions} from 'mattermost-redux/constants'; +import {getChannel, getCurrentChannelId} from 'mattermost-redux/selectors/entities/channels'; +import {getCurrentUserId} from 'mattermost-redux/selectors/entities/users'; +import {getConfig, getLicense, hasNewPermissions} from 'mattermost-redux/selectors/entities/general'; +import {getPost} from 'mattermost-redux/selectors/entities/posts'; +import {getTheme} from 'mattermost-redux/selectors/entities/preferences'; +import {haveIChannelPermission} from 'mattermost-redux/selectors/entities/roles'; +import {getCurrentTeamId, getCurrentTeamUrl} from 'mattermost-redux/selectors/entities/teams'; +import {canEditPost} from 'mattermost-redux/utils/post_utils'; + +import {addReaction} from 'app/actions/views/emoji'; +import {getDimensions} from 'app/selectors/device'; + +import PostOptions from './post_options'; + +function mapStateToProps(state, ownProps) { + const post = getPost(state, ownProps.postId); + const channel = getChannel(state, post.channel_id); + const config = getConfig(state); + const license = getLicense(state); + const currentUserId = getCurrentUserId(state); + const currentTeamId = getCurrentTeamId(state); + const currentChannelId = getCurrentChannelId(state); + + const channelIsArchived = channel.delete_at !== 0; + + let canAddReaction = true; + let canEdit = false; + let canEditUntil = -1; + + if (hasNewPermissions(state)) { + canAddReaction = haveIChannelPermission(state, { + team: currentTeamId, + channel: post.channel_id, + permission: Permissions.ADD_REACTION, + }); + } + + if (channelIsArchived) { + canAddReaction = false; + } else { + canEdit = canEditPost(state, config, license, currentTeamId, currentChannelId, currentUserId, post); + if (canEdit && license.IsLicensed === 'true' && + (config.AllowEditPost === General.ALLOW_EDIT_POST_TIME_LIMIT || (config.PostEditTimeLimit !== -1 && config.PostEditTimeLimit !== '-1')) + ) { + canEditUntil = post.create_at + (config.PostEditTimeLimit * 1000); + } + } + + return { + ...getDimensions(state), + canAddReaction, + canEdit, + canEditUntil, + currentTeamUrl: getCurrentTeamUrl(state), + isMyPost: currentUserId === post.user_id, + post, + theme: getTheme(state), + }; +} + +function mapDispatchToProps(dispatch) { + return { + actions: bindActionCreators({ + addReaction, + deletePost, + flagPost, + removePost, + unflagPost, + }, dispatch), + }; +} + +export default connect(mapStateToProps, mapDispatchToProps)(PostOptions); diff --git a/app/screens/post_options/post_option.js b/app/screens/post_options/post_option.js new file mode 100644 index 000000000..38f80c25f --- /dev/null +++ b/app/screens/post_options/post_option.js @@ -0,0 +1,106 @@ +// 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 { + Image, + StyleSheet, + Text, + TouchableHighlight, + View, +} from 'react-native'; + +import copy from 'assets/images/post_menu/copy.png'; +import edit from 'assets/images/post_menu/edit.png'; +import emoji from 'assets/images/post_menu/emoji.png'; +import flag from 'assets/images/post_menu/flag.png'; +import link from 'assets/images/post_menu/link.png'; +import trash from 'assets/images/post_menu/trash.png'; + +const icons = { + copy, + edit, + emoji, + flag, + link, + trash, +}; + +export default class PostOption extends PureComponent { + static propTypes = { + destructive: PropTypes.bool, + icon: PropTypes.string.isRequired, + onPress: PropTypes.func.isRequired, + text: PropTypes.string.isRequired, + }; + + render() { + const {destructive, icon, onPress, text} = this.props; + const image = icons[icon]; + + return ( + + + + + + + + + {text} + + + + + + + ); + } +} + +const style = StyleSheet.create({ + container: { + height: 51, + width: '100%', + }, + flex: { + flex: 1, + }, + destructive: { + color: '#D0021B', + }, + row: { + flex: 1, + flexDirection: 'row', + }, + icon: { + alignItems: 'center', + height: 50, + justifyContent: 'center', + width: 60, + }, + textContainer: { + justifyContent: 'center', + flex: 1, + height: 50, + marginRight: 5, + }, + text: { + color: '#000000', + fontSize: 16, + lineHeight: 19, + opacity: 0.9, + letterSpacing: -0.45, + }, + footer: { + height: 1, + marginLeft: 60, + borderBottomWidth: 1, + borderBottomColor: 'rgba(0, 0, 0 ,0.2)', + }, +}); diff --git a/app/screens/post_options/post_options.js b/app/screens/post_options/post_options.js new file mode 100644 index 000000000..4c6526b89 --- /dev/null +++ b/app/screens/post_options/post_options.js @@ -0,0 +1,358 @@ +// 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 {Alert, Clipboard, StyleSheet, View} from 'react-native'; +import {intlShape} from 'react-intl'; +import MaterialIcon from 'react-native-vector-icons/MaterialIcons'; + +import SlideUpPanel from 'app/components/slide_up_panel'; +import {BOTTOM_MARGIN} from 'app/components/slide_up_panel/slide_up_panel'; + +import PostOption from './post_option'; + +const OPTION_HEIGHT = 50; +const INITIAL_OPTION_COUNT = 6; + +export default class PostOptions extends PureComponent { + static propTypes = { + actions: PropTypes.shape({ + addReaction: PropTypes.func.isRequired, + deletePost: PropTypes.func.isRequired, + flagPost: PropTypes.func.isRequired, + removePost: PropTypes.func.isRequired, + unflagPost: PropTypes.func.isRequired, + }).isRequired, + additionalOption: PropTypes.object, + canAddReaction: PropTypes.bool, + canDelete: PropTypes.bool, + canEdit: PropTypes.bool, + canEditUntil: PropTypes.number.isRequired, + channelIsReadOnly: PropTypes.bool, + currentTeamUrl: PropTypes.string.isRequired, + deviceHeight: PropTypes.number.isRequired, + hasBeenDeleted: PropTypes.bool, + isFlagged: PropTypes.bool, + isMyPost: PropTypes.bool, + managedConfig: PropTypes.object.isRequired, + navigator: PropTypes.object.isRequired, + post: PropTypes.object.isRequired, + showAddReaction: PropTypes.bool, + theme: PropTypes.object.isRequired, + }; + + static contextTypes = { + intl: intlShape.isRequired, + }; + + close = () => { + this.props.navigator.dismissModal({ + animationType: 'none', + }); + }; + + closeWithAnimation = () => { + if (this.slideUpPanel) { + this.slideUpPanel.getWrappedInstance().handleTouchEnd(); + } else { + this.close(); + } + }; + + getAddReactionOption = () => { + const {formatMessage} = this.context.intl; + const {canAddReaction, channelIsReadOnly, showAddReaction} = this.props; + + if (showAddReaction && canAddReaction && !channelIsReadOnly) { + return ( + + ); + } + + return null; + }; + + getCopyPermalink = () => { + const {formatMessage} = this.context.intl; + + return ( + + ); + }; + + getCopyText = () => { + const {formatMessage} = this.context.intl; + const {managedConfig, post} = this.props; + + if (managedConfig.copyAndPasteProtection !== 'true' && post.message) { + return ( + + ); + } + + return null; + }; + + getDeleteOption = () => { + const {formatMessage} = this.context.intl; + const {canDelete, hasBeenDeleted} = this.props; + + if (canDelete && !hasBeenDeleted) { + return ( + + ); + } + + return null; + }; + + getEditOption = () => { + const {formatMessage} = this.context.intl; + const {canEdit, canEditUntil} = this.props; + + if (canEdit && (canEditUntil === -1 || canEditUntil > Date.now())) { + return ( + + ); + } + + return null; + }; + + getFlagOption = () => { + const {formatMessage} = this.context.intl; + const {channelIsReadOnly, isFlagged} = this.props; + + if (channelIsReadOnly) { + return null; + } + + if (isFlagged) { + return ( + + ); + } + + return ( + + ); + }; + + getMyPostOptions = () => { + const actions = [ + this.getEditOption(), + this.getFlagOption(), + this.getAddReactionOption(), + this.getCopyPermalink(), + this.getCopyText(), + this.getDeleteOption(), + ]; + + return actions.filter((a) => a !== null); + }; + + getOthersPostOptions = () => { + const actions = [ + this.getFlagOption(), + this.getAddReactionOption(), + this.getCopyPermalink(), + this.getCopyText(), + this.getEditOption(), + this.getDeleteOption(), + ]; + + return actions.filter((a) => a !== null); + }; + + getPostOptions = () => { + const {isMyPost} = this.props; + + if (isMyPost) { + return this.getMyPostOptions(); + } + + return this.getOthersPostOptions(); + }; + + handleAddReaction = () => { + const {formatMessage} = this.context.intl; + const {navigator, theme} = this.props; + + this.close(); + requestAnimationFrame(() => { + MaterialIcon.getImageSource('close', 20, theme.sidebarHeaderTextColor).then((source) => { + navigator.showModal({ + screen: 'AddReaction', + title: formatMessage({id: 'mobile.post_info.add_reaction', defaultMessage: 'Add Reaction'}), + animated: true, + navigatorStyle: { + navBarTextColor: theme.sidebarHeaderTextColor, + navBarBackgroundColor: theme.sidebarHeaderBg, + navBarButtonColor: theme.sidebarHeaderTextColor, + screenBackgroundColor: theme.centerChannelBg, + }, + passProps: { + closeButton: source, + onEmojiPress: this.handleAddReactionToPost, + }, + }); + }); + }); + }; + + handleAddReactionToPost = (emoji) => { + const {actions, post} = this.props; + + actions.addReaction(post.id, emoji); + }; + + handleCopyPermalink = () => { + const {currentTeamUrl, post} = this.props; + const permalink = `${currentTeamUrl}/pl/${post.id}`; + + Clipboard.setString(permalink); + this.closeWithAnimation(); + }; + + handleCopyText = () => { + const {message} = this.props.post; + + Clipboard.setString(message); + this.closeWithAnimation(); + }; + + handleFlagPost = () => { + const {actions, post} = this.props; + + actions.flagPost(post.id); + this.closeWithAnimation(); + }; + + handlePostDelete = () => { + const {formatMessage} = this.context.intl; + const {actions, isMyPost, post} = this.props; + + Alert.alert( + formatMessage({id: 'mobile.post.delete_title', defaultMessage: 'Delete Post'}), + formatMessage({ + id: 'mobile.post.delete_question', + defaultMessage: 'Are you sure you want to delete this post?', + }), + [{ + text: formatMessage({id: 'mobile.post.cancel', defaultMessage: 'Cancel'}), + style: 'cancel', + }, { + text: formatMessage({id: 'post_info.del', defaultMessage: 'Delete'}), + style: 'destructive', + onPress: () => { + actions.deletePost(post); + if (isMyPost) { + actions.removePost(post); + } + this.closeWithAnimation(); + }, + }] + ); + }; + + handlePostEdit = () => { + const {intl} = this.context; + const {navigator, post, theme} = this.props; + + this.close(); + requestAnimationFrame(() => { + MaterialIcon.getImageSource('close', 20, theme.sidebarHeaderTextColor).then((source) => { + navigator.showModal({ + screen: 'EditPost', + title: intl.formatMessage({id: 'mobile.edit_post.title', defaultMessage: 'Editing Message'}), + animated: true, + navigatorStyle: { + navBarTextColor: theme.sidebarHeaderTextColor, + navBarBackgroundColor: theme.sidebarHeaderBg, + navBarButtonColor: theme.sidebarHeaderTextColor, + screenBackgroundColor: theme.centerChannelBg, + }, + passProps: { + post, + closeButton: source, + }, + }); + }); + }); + }; + + handleUnflagPost = () => { + const {actions, post} = this.props; + + actions.unflagPost(post.id); + this.closeWithAnimation(); + }; + + refSlideUpPanel = (r) => { + this.slideUpPanel = r; + }; + + render() { + const {deviceHeight} = this.props; + const options = this.getPostOptions(); + const initialPosition = (INITIAL_OPTION_COUNT + 1) * OPTION_HEIGHT; + const marginFromTop = deviceHeight - BOTTOM_MARGIN - ((options.length + 1) * OPTION_HEIGHT); + + return ( + + + {options} + + + ); + } +} + +const style = StyleSheet.create({ + flex: { + flex: 1, + }, +}); diff --git a/app/screens/reaction_list/reaction_list.js b/app/screens/reaction_list/reaction_list.js index 64ead7543..af226b5e1 100644 --- a/app/screens/reaction_list/reaction_list.js +++ b/app/screens/reaction_list/reaction_list.js @@ -46,7 +46,6 @@ export default class ReactionList extends PureComponent { this.contentOffsetY = -1; this.state = { - canDrag: true, allUserIds: getUniqueUserIds(reactions), reactions, reactionsByName, diff --git a/app/utils/bottom_sheet/bottom_sheet.android.js b/app/utils/bottom_sheet/bottom_sheet.android.js new file mode 100644 index 000000000..890420ff0 --- /dev/null +++ b/app/utils/bottom_sheet/bottom_sheet.android.js @@ -0,0 +1,5 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +import RNBottomSheet from 'react-native-bottom-sheet'; +export default RNBottomSheet; diff --git a/app/utils/bottom_sheet/bottom_sheet.ios.js b/app/utils/bottom_sheet/bottom_sheet.ios.js new file mode 100644 index 000000000..0ba3abc9e --- /dev/null +++ b/app/utils/bottom_sheet/bottom_sheet.ios.js @@ -0,0 +1,14 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +import {ActionSheetIOS} from 'react-native'; + +export default { + showBottomSheetWithOptions: (options, callback) => { + return ActionSheetIOS.showActionSheetWithOptions(options, callback); + }, + + showShareBottomSheetWithOptions: (options, failureCallback, successCallback) => { + return ActionSheetIOS.showShareActionSheetWithOptions(options, failureCallback, successCallback); + }, +}; diff --git a/app/utils/bottom_sheet/index.js b/app/utils/bottom_sheet/index.js new file mode 100644 index 000000000..6f745c8c3 --- /dev/null +++ b/app/utils/bottom_sheet/index.js @@ -0,0 +1,5 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +import BottomSheet from './bottom_sheet'; +export default BottomSheet; diff --git a/assets/base/i18n/en.json b/assets/base/i18n/en.json index 4e97e6c76..d16c2741f 100644 --- a/assets/base/i18n/en.json +++ b/assets/base/i18n/en.json @@ -330,7 +330,7 @@ "mobile.open_gm.error": "We couldn't open a group message with those users. Please check your connection and try again.", "mobile.open_unknown_channel.error": "Unable to join the channel. Please reset the cache and try again.", "mobile.post_info.add_reaction": "Add Reaction", - "mobile.post_info.copy_post": "Copy Post", + "mobile.post_info.copy_text": "Copy Text", "mobile.post_textbox.empty.message": "You are trying to send an empty message.\nPlease make sure you have a message or at least one attached file.", "mobile.post_textbox.empty.ok": "OK", "mobile.post_textbox.empty.title": "Empty Message", diff --git a/assets/base/images/post_menu/copy.png b/assets/base/images/post_menu/copy.png new file mode 100755 index 000000000..09ce290f9 Binary files /dev/null and b/assets/base/images/post_menu/copy.png differ diff --git a/assets/base/images/post_menu/copy@2x.png b/assets/base/images/post_menu/copy@2x.png new file mode 100755 index 000000000..9cf44d271 Binary files /dev/null and b/assets/base/images/post_menu/copy@2x.png differ diff --git a/assets/base/images/post_menu/copy@3x.png b/assets/base/images/post_menu/copy@3x.png new file mode 100755 index 000000000..e5a2e89f0 Binary files /dev/null and b/assets/base/images/post_menu/copy@3x.png differ diff --git a/assets/base/images/post_menu/edit.png b/assets/base/images/post_menu/edit.png new file mode 100755 index 000000000..597016cd4 Binary files /dev/null and b/assets/base/images/post_menu/edit.png differ diff --git a/assets/base/images/post_menu/edit@2x.png b/assets/base/images/post_menu/edit@2x.png new file mode 100755 index 000000000..8baf8cbd1 Binary files /dev/null and b/assets/base/images/post_menu/edit@2x.png differ diff --git a/assets/base/images/post_menu/edit@3x.png b/assets/base/images/post_menu/edit@3x.png new file mode 100755 index 000000000..268cf72ec Binary files /dev/null and b/assets/base/images/post_menu/edit@3x.png differ diff --git a/assets/base/images/post_menu/emoji.png b/assets/base/images/post_menu/emoji.png new file mode 100755 index 000000000..0d24b407b Binary files /dev/null and b/assets/base/images/post_menu/emoji.png differ diff --git a/assets/base/images/post_menu/emoji@2x.png b/assets/base/images/post_menu/emoji@2x.png new file mode 100755 index 000000000..a7647bb05 Binary files /dev/null and b/assets/base/images/post_menu/emoji@2x.png differ diff --git a/assets/base/images/post_menu/emoji@3x.png b/assets/base/images/post_menu/emoji@3x.png new file mode 100755 index 000000000..230d351aa Binary files /dev/null and b/assets/base/images/post_menu/emoji@3x.png differ diff --git a/assets/base/images/post_menu/flag.png b/assets/base/images/post_menu/flag.png new file mode 100755 index 000000000..a986428c6 Binary files /dev/null and b/assets/base/images/post_menu/flag.png differ diff --git a/assets/base/images/post_menu/flag@2x.png b/assets/base/images/post_menu/flag@2x.png new file mode 100755 index 000000000..dab7db2af Binary files /dev/null and b/assets/base/images/post_menu/flag@2x.png differ diff --git a/assets/base/images/post_menu/flag@3x.png b/assets/base/images/post_menu/flag@3x.png new file mode 100755 index 000000000..c35200d3a Binary files /dev/null and b/assets/base/images/post_menu/flag@3x.png differ diff --git a/assets/base/images/post_menu/link.png b/assets/base/images/post_menu/link.png new file mode 100755 index 000000000..503a31d4c Binary files /dev/null and b/assets/base/images/post_menu/link.png differ diff --git a/assets/base/images/post_menu/link@2x.png b/assets/base/images/post_menu/link@2x.png new file mode 100755 index 000000000..4a3edb494 Binary files /dev/null and b/assets/base/images/post_menu/link@2x.png differ diff --git a/assets/base/images/post_menu/link@3x.png b/assets/base/images/post_menu/link@3x.png new file mode 100755 index 000000000..c59e59e30 Binary files /dev/null and b/assets/base/images/post_menu/link@3x.png differ diff --git a/assets/base/images/post_menu/pin.png b/assets/base/images/post_menu/pin.png new file mode 100755 index 000000000..a07aa27d7 Binary files /dev/null and b/assets/base/images/post_menu/pin.png differ diff --git a/assets/base/images/post_menu/pin@2x.png b/assets/base/images/post_menu/pin@2x.png new file mode 100755 index 000000000..b1c440d97 Binary files /dev/null and b/assets/base/images/post_menu/pin@2x.png differ diff --git a/assets/base/images/post_menu/pin@3x.png b/assets/base/images/post_menu/pin@3x.png new file mode 100755 index 000000000..153af9d41 Binary files /dev/null and b/assets/base/images/post_menu/pin@3x.png differ diff --git a/assets/base/images/post_menu/trash.png b/assets/base/images/post_menu/trash.png new file mode 100755 index 000000000..e8f443bbf Binary files /dev/null and b/assets/base/images/post_menu/trash.png differ diff --git a/assets/base/images/post_menu/trash@2x.png b/assets/base/images/post_menu/trash@2x.png new file mode 100755 index 000000000..532dd292c Binary files /dev/null and b/assets/base/images/post_menu/trash@2x.png differ diff --git a/assets/base/images/post_menu/trash@3x.png b/assets/base/images/post_menu/trash@3x.png new file mode 100755 index 000000000..fb70b2bd9 Binary files /dev/null and b/assets/base/images/post_menu/trash@3x.png differ diff --git a/ios/Mattermost.xcodeproj/project.pbxproj b/ios/Mattermost.xcodeproj/project.pbxproj index 9cab29e75..09958e42d 100644 --- a/ios/Mattermost.xcodeproj/project.pbxproj +++ b/ios/Mattermost.xcodeproj/project.pbxproj @@ -5,6 +5,7 @@ }; objectVersion = 46; objects = { + /* Begin PBXBuildFile section */ 00C302E51ABCBA2D00DB3ED1 /* libRCTActionSheet.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302AC1ABCB8CE00DB3ED1 /* libRCTActionSheet.a */; }; 00C302E71ABCBA2D00DB3ED1 /* libRCTGeolocation.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302BA1ABCB90400DB3ED1 /* libRCTGeolocation.a */; }; @@ -28,9 +29,13 @@ 375218501F4B9EE70035444B /* libRCTCameraRoll.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3752184F1F4B9E980035444B /* libRCTCameraRoll.a */; }; 37ABD3C81F4CE142001FDE6B /* libART.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 37ABD39C1F4CE13B001FDE6B /* libART.a */; }; 382D94CF15EE4FC292C3F341 /* Foundation.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 51F5A483EA9F4A9A87ACFB59 /* Foundation.ttf */; }; + 3C0B333879CE4730843D8584 /* Roboto-MediumItalic.ttf in Resources */ = {isa = PBXBuildFile; fileRef = D08F54E10DF14AE4BBF4E2B4 /* Roboto-MediumItalic.ttf */; }; 3D38ABA732A34A9BB3294F90 /* EvilIcons.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 349FBA7338E74D9BBD709528 /* EvilIcons.ttf */; }; + 3D7B4E6EE6B948AAA6A1E4E6 /* Roboto-BoldItalic.ttf in Resources */ = {isa = PBXBuildFile; fileRef = C46342B0E5FD4D878AF3A129 /* Roboto-BoldItalic.ttf */; }; 3F876A0DC6314E27B16C8A96 /* libRNReactNativeDocViewer.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 6BAF8296411D4657B5A0E8F8 /* libRNReactNativeDocViewer.a */; }; 420A7328E12C4B72AEF420CE /* Octicons.ttf in Resources */ = {isa = PBXBuildFile; fileRef = EDC04CBCF81642219D199CBB /* Octicons.ttf */; }; + 460A48EA5C6C4D8B8D9A2C75 /* Roboto-Italic.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 031EF04FB2D14EEFAACBAA1A /* Roboto-Italic.ttf */; }; + 552835DCC0C24FC691EE6CAB /* Roboto-LightItalic.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 8F0B22D2C9924FAFA7FB681C /* Roboto-LightItalic.ttf */; }; 55C6561DDBBA45929D88B6D1 /* OpenSans-BoldItalic.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 32AC3D4EA79E44738A6E9766 /* OpenSans-BoldItalic.ttf */; }; 5A0920184BD344979BCFCD5C /* libRCTVideo.a in Frameworks */ = {isa = PBXBuildFile; fileRef = B89192186C764B9FA473403A /* libRCTVideo.a */; }; 5CB86E9DFB94485CAA748DF3 /* YTPlayerView-iframe-player.html in Resources */ = {isa = PBXBuildFile; fileRef = 79CB6EBA24FE4ABFB0C155F0 /* YTPlayerView-iframe-player.html */; }; @@ -38,6 +43,7 @@ 5E9157361DD0AC6A00FF2AA8 /* libRCTAnimation.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E9157331DD0AC6500FF2AA8 /* libRCTAnimation.a */; }; 62A8448264674B4D95A5A7C2 /* OpenSans-Semibold.ttf in Resources */ = {isa = PBXBuildFile; fileRef = C78A387124874496AD2C1466 /* OpenSans-Semibold.ttf */; }; 69AC753E496743BABB7A7124 /* OpenSans-SemiboldItalic.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 0E617BF0F36D4E738F51D169 /* OpenSans-SemiboldItalic.ttf */; }; + 71F30A436B5847DF9D319D15 /* Roboto-BlackItalic.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 7F54ABFAE6CE4A6DB11D1ED7 /* Roboto-BlackItalic.ttf */; }; 74D116AD208A8D5600CF8A79 /* libRNKeychain.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 74D116AA208A8D3100CF8A79 /* libRNKeychain.a */; }; 7F2691A11EE1DC6A007574FE /* libRNNotifications.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7F2691A01EE1DC51007574FE /* libRNNotifications.a */; }; 7F292A711E8AB73400A450A3 /* SplashScreenResource in Resources */ = {isa = PBXBuildFile; fileRef = 7F292A701E8AB73400A450A3 /* SplashScreenResource */; }; @@ -62,7 +68,6 @@ 7F5CA9A0208FE3B9004F91CE /* libRNDocumentPicker.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7F5CA991208FE38F004F91CE /* libRNDocumentPicker.a */; }; 7F642DF02093533300F3165E /* libRNDeviceInfo.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7F642DED2093530B00F3165E /* libRNDeviceInfo.a */; }; 7F642DF1209353A400F3165E /* libRNDeviceInfo.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7F642DED2093530B00F3165E /* libRNDeviceInfo.a */; }; - 7F6877B31E7836070094B63F /* libToolTipMenu.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7F6877B01E7835E50094B63F /* libToolTipMenu.a */; }; 7F6C47A51FE87E8C00F5A912 /* PerformRequests.m in Sources */ = {isa = PBXBuildFile; fileRef = 7F6C47A41FE87E8C00F5A912 /* PerformRequests.m */; }; 7F7D7F98201645E100D31155 /* libReactNativePermissions.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7F7D7F87201645D300D31155 /* libReactNativePermissions.a */; }; 7F95132F208646CE00616E3E /* 0155-keys.png in Resources */ = {isa = PBXBuildFile; fileRef = 7F9512EA208646CD00616E3E /* 0155-keys.png */; }; @@ -103,25 +108,20 @@ 9358B95F95184EE0A4DCE629 /* OpenSans-Bold.ttf in Resources */ = {isa = PBXBuildFile; fileRef = D4B1B363C2414DA19C1AC521 /* OpenSans-Bold.ttf */; }; A08D512E7ADC40CCAD055A9E /* OpenSans-Regular.ttf in Resources */ = {isa = PBXBuildFile; fileRef = BC977883E2624E05975CA65B /* OpenSans-Regular.ttf */; }; A9B746D2CFA9CEBFB8AE2B5B /* libPods-Mattermost.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 65FD5EA57EBAE06106094B2F /* libPods-Mattermost.a */; }; + AA9605CFDA8E4E7CB8A041BF /* Roboto-Regular.ttf in Resources */ = {isa = PBXBuildFile; fileRef = C5BD64DE829E455A997DCAD5 /* Roboto-Regular.ttf */; }; + ABF5F93B1D0A47BAACEAC376 /* Roboto-Light.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 34B20A903038487E8D7DEA1E /* Roboto-Light.ttf */; }; C035DB50ED2045F09923FFAE /* MaterialCommunityIcons.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 04AA5E8EF3B54735A11E3B95 /* MaterialCommunityIcons.ttf */; }; C337E8708D2845C6A8DBB47E /* Ionicons.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 2DCFD31D3F4A4154822AB532 /* Ionicons.ttf */; }; + C99BB3F4E4564F01A531FBEA /* Roboto-Medium.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 09FA716C56874BDDA30FE8C4 /* Roboto-Medium.ttf */; }; D719A67137964F08BE47A5FC /* OpenSans-ExtraBold.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 3647DF63D6764CF093375861 /* OpenSans-ExtraBold.ttf */; }; + DDE492F7425D451884DAA088 /* Roboto-Black.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 6EFF13DD24CE4E26953E598A /* Roboto-Black.ttf */; }; + DE863F2E1E194A45A5B58FFA /* Roboto-Thin.ttf in Resources */ = {isa = PBXBuildFile; fileRef = A734E00E7E184582A877F2B3 /* Roboto-Thin.ttf */; }; DEBCF44F1F46413BB407D316 /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 8606EB1EB7E349EF8248933E /* libz.tbd */; }; + E052494CD6104A65840485E7 /* Roboto-Bold.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 71E626D4980A4560B26F0E1C /* Roboto-Bold.ttf */; }; + EC6AF34E03F647389D377064 /* Roboto-ThinItalic.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 12D0B0E475FD46E29907305E /* Roboto-ThinItalic.ttf */; }; F006936FC2884C24A1321FC0 /* MaterialIcons.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 356C9186FA374641A00EB2EA /* MaterialIcons.ttf */; }; F083DB472349411A8E6E7AAD /* OpenSans-LightItalic.ttf in Resources */ = {isa = PBXBuildFile; fileRef = BE17F630DB5D41FD93F32D22 /* OpenSans-LightItalic.ttf */; }; F23C99AA5FA10E457A76803A /* libPods-MattermostTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 4246DC09024BB33A3E491E25 /* libPods-MattermostTests.a */; }; - DDE492F7425D451884DAA088 /* Roboto-Black.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 6EFF13DD24CE4E26953E598A /* Roboto-Black.ttf */; }; - 71F30A436B5847DF9D319D15 /* Roboto-BlackItalic.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 7F54ABFAE6CE4A6DB11D1ED7 /* Roboto-BlackItalic.ttf */; }; - E052494CD6104A65840485E7 /* Roboto-Bold.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 71E626D4980A4560B26F0E1C /* Roboto-Bold.ttf */; }; - 3D7B4E6EE6B948AAA6A1E4E6 /* Roboto-BoldItalic.ttf in Resources */ = {isa = PBXBuildFile; fileRef = C46342B0E5FD4D878AF3A129 /* Roboto-BoldItalic.ttf */; }; - 460A48EA5C6C4D8B8D9A2C75 /* Roboto-Italic.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 031EF04FB2D14EEFAACBAA1A /* Roboto-Italic.ttf */; }; - ABF5F93B1D0A47BAACEAC376 /* Roboto-Light.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 34B20A903038487E8D7DEA1E /* Roboto-Light.ttf */; }; - 552835DCC0C24FC691EE6CAB /* Roboto-LightItalic.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 8F0B22D2C9924FAFA7FB681C /* Roboto-LightItalic.ttf */; }; - C99BB3F4E4564F01A531FBEA /* Roboto-Medium.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 09FA716C56874BDDA30FE8C4 /* Roboto-Medium.ttf */; }; - 3C0B333879CE4730843D8584 /* Roboto-MediumItalic.ttf in Resources */ = {isa = PBXBuildFile; fileRef = D08F54E10DF14AE4BBF4E2B4 /* Roboto-MediumItalic.ttf */; }; - AA9605CFDA8E4E7CB8A041BF /* Roboto-Regular.ttf in Resources */ = {isa = PBXBuildFile; fileRef = C5BD64DE829E455A997DCAD5 /* Roboto-Regular.ttf */; }; - DE863F2E1E194A45A5B58FFA /* Roboto-Thin.ttf in Resources */ = {isa = PBXBuildFile; fileRef = A734E00E7E184582A877F2B3 /* Roboto-Thin.ttf */; }; - EC6AF34E03F647389D377064 /* Roboto-ThinItalic.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 12D0B0E475FD46E29907305E /* Roboto-ThinItalic.ttf */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -468,20 +468,6 @@ remoteGlobalIDString = E72EC1401F7ABB5A0001BC90; remoteInfo = "RNDeviceInfo-tvOS"; }; - 7F6877AF1E7835E50094B63F /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 7F6877AA1E7835E50094B63F /* ToolTipMenu.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 4681C0211B05271A004D67D4; - remoteInfo = ToolTipMenu; - }; - 7F6877B11E7835E50094B63F /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 7F6877AA1E7835E50094B63F /* ToolTipMenu.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 4681C02C1B05271A004D67D4; - remoteInfo = ToolTipMenuTests; - }; 7F6FF6B4203499F400150948 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */; @@ -658,9 +644,12 @@ 00E356EE1AD99517003FC87E /* MattermostTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = MattermostTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 00E356F11AD99517003FC87E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 00E356F21AD99517003FC87E /* MattermostTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MattermostTests.m; sourceTree = ""; }; + 031EF04FB2D14EEFAACBAA1A /* Roboto-Italic.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = "Roboto-Italic.ttf"; path = "../assets/fonts/Roboto-Italic.ttf"; sourceTree = ""; }; 04AA5E8EF3B54735A11E3B95 /* MaterialCommunityIcons.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = MaterialCommunityIcons.ttf; path = "../node_modules/react-native-vector-icons/Fonts/MaterialCommunityIcons.ttf"; sourceTree = ""; }; + 09FA716C56874BDDA30FE8C4 /* Roboto-Medium.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = "Roboto-Medium.ttf"; path = "../assets/fonts/Roboto-Medium.ttf"; sourceTree = ""; }; 0A091BF1A3D04650AD306A0D /* Zocial.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = Zocial.ttf; path = "../node_modules/react-native-vector-icons/Fonts/Zocial.ttf"; sourceTree = ""; }; 0E617BF0F36D4E738F51D169 /* OpenSans-SemiboldItalic.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = "OpenSans-SemiboldItalic.ttf"; path = "../assets/fonts/OpenSans-SemiboldItalic.ttf"; sourceTree = ""; }; + 12D0B0E475FD46E29907305E /* Roboto-ThinItalic.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = "Roboto-ThinItalic.ttf"; path = "../assets/fonts/Roboto-ThinItalic.ttf"; sourceTree = ""; }; 139105B61AF99BAD00B5F7CC /* RCTSettings.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTSettings.xcodeproj; path = "../node_modules/react-native/Libraries/Settings/RCTSettings.xcodeproj"; sourceTree = ""; }; 139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTWebSocket.xcodeproj; path = "../node_modules/react-native/Libraries/WebSocket/RCTWebSocket.xcodeproj"; sourceTree = ""; }; 13B07F961A680F5B00A75B9A /* Mattermost.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Mattermost.app; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -678,6 +667,7 @@ 2DCFD31D3F4A4154822AB532 /* Ionicons.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = Ionicons.ttf; path = "../node_modules/react-native-vector-icons/Fonts/Ionicons.ttf"; sourceTree = ""; }; 32AC3D4EA79E44738A6E9766 /* OpenSans-BoldItalic.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = "OpenSans-BoldItalic.ttf"; path = "../assets/fonts/OpenSans-BoldItalic.ttf"; sourceTree = ""; }; 349FBA7338E74D9BBD709528 /* EvilIcons.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = EvilIcons.ttf; path = "../node_modules/react-native-vector-icons/Fonts/EvilIcons.ttf"; sourceTree = ""; }; + 34B20A903038487E8D7DEA1E /* Roboto-Light.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = "Roboto-Light.ttf"; path = "../assets/fonts/Roboto-Light.ttf"; sourceTree = ""; }; 356C9186FA374641A00EB2EA /* MaterialIcons.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = MaterialIcons.ttf; path = "../node_modules/react-native-vector-icons/Fonts/MaterialIcons.ttf"; sourceTree = ""; }; 3647DF63D6764CF093375861 /* OpenSans-ExtraBold.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = "OpenSans-ExtraBold.ttf"; path = "../assets/fonts/OpenSans-ExtraBold.ttf"; sourceTree = ""; }; 3752184A1F4B9E980035444B /* RCTCameraRoll.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTCameraRoll.xcodeproj; path = "../node_modules/react-native/Libraries/CameraRoll/RCTCameraRoll.xcodeproj"; sourceTree = ""; }; @@ -697,6 +687,8 @@ 6561AEAC21CC40B8A72ABB93 /* OpenSans-Light.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = "OpenSans-Light.ttf"; path = "../assets/fonts/OpenSans-Light.ttf"; sourceTree = ""; }; 65FD5EA57EBAE06106094B2F /* libPods-Mattermost.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Mattermost.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 6BAF8296411D4657B5A0E8F8 /* libRNReactNativeDocViewer.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libRNReactNativeDocViewer.a; sourceTree = ""; }; + 6EFF13DD24CE4E26953E598A /* Roboto-Black.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = "Roboto-Black.ttf"; path = "../assets/fonts/Roboto-Black.ttf"; sourceTree = ""; }; + 71E626D4980A4560B26F0E1C /* Roboto-Bold.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = "Roboto-Bold.ttf"; path = "../assets/fonts/Roboto-Bold.ttf"; sourceTree = ""; }; 74D116A3208A8C8400CF8A79 /* libRNKeychain.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = libRNKeychain.a; sourceTree = BUILT_PRODUCTS_DIR; }; 74D116A4208A8D3000CF8A79 /* RNKeychain.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RNKeychain.xcodeproj; path = "../node_modules/react-native-keychain/RNKeychain.xcodeproj"; sourceTree = ""; }; 7535D128F00C4A47A182627E /* libRNCookieManagerIOS.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libRNCookieManagerIOS.a; sourceTree = ""; }; @@ -713,11 +705,11 @@ 7F43D6051F6BF9EB001FC614 /* libPods-Mattermost.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = "libPods-Mattermost.a"; path = "../../../../../../../Library/Developer/Xcode/DerivedData/Mattermost-czlinsdviifujheezzjvmisotjrm/Build/Products/Debug-iphonesimulator/libPods-Mattermost.a"; sourceTree = ""; }; 7F50C968203C6E80007CA374 /* SessionManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SessionManager.h; sourceTree = ""; }; 7F50C969203C6E80007CA374 /* SessionManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SessionManager.m; sourceTree = ""; }; + 7F54ABFAE6CE4A6DB11D1ED7 /* Roboto-BlackItalic.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = "Roboto-BlackItalic.ttf"; path = "../assets/fonts/Roboto-BlackItalic.ttf"; sourceTree = ""; }; 7F5CA956208FE38F004F91CE /* RNDocumentPicker.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RNDocumentPicker.xcodeproj; path = "../node_modules/react-native-document-picker/ios/RNDocumentPicker.xcodeproj"; sourceTree = ""; }; 7F63D27B1E6C957C001FAE12 /* RCTPushNotification.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTPushNotification.xcodeproj; path = "../node_modules/react-native/Libraries/PushNotificationIOS/RCTPushNotification.xcodeproj"; sourceTree = ""; }; 7F63D2C21E6DD98A001FAE12 /* Mattermost.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; name = Mattermost.entitlements; path = Mattermost/Mattermost.entitlements; sourceTree = ""; }; 7F642DE72093530B00F3165E /* RNDeviceInfo.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RNDeviceInfo.xcodeproj; path = "../node_modules/react-native-device-info/ios/RNDeviceInfo.xcodeproj"; sourceTree = ""; }; - 7F6877AA1E7835E50094B63F /* ToolTipMenu.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = ToolTipMenu.xcodeproj; path = "../node_modules/react-native-tooltip/ToolTipMenu.xcodeproj"; sourceTree = ""; }; 7F6C47A31FE87E8C00F5A912 /* PerformRequests.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PerformRequests.h; sourceTree = ""; }; 7F6C47A41FE87E8C00F5A912 /* PerformRequests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PerformRequests.m; sourceTree = ""; }; 7F7D7F52201645D300D31155 /* ReactNativePermissions.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = ReactNativePermissions.xcodeproj; path = "../node_modules/react-native-permissions/ios/ReactNativePermissions.xcodeproj"; sourceTree = ""; }; @@ -754,17 +746,22 @@ 832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTText.xcodeproj; path = "../node_modules/react-native/Libraries/Text/RCTText.xcodeproj"; sourceTree = ""; }; 849D881A0372465294DE7315 /* RNSafeArea.xcodeproj */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "wrapper.pb-project"; name = RNSafeArea.xcodeproj; path = "../node_modules/react-native-safe-area/ios/RNSafeArea.xcodeproj"; sourceTree = ""; }; 8606EB1EB7E349EF8248933E /* libz.tbd */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = usr/lib/libz.tbd; sourceTree = SDKROOT; }; + 8F0B22D2C9924FAFA7FB681C /* Roboto-LightItalic.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = "Roboto-LightItalic.ttf"; path = "../assets/fonts/Roboto-LightItalic.ttf"; sourceTree = ""; }; 9263CF9B16054263B13EA23B /* libRNSafeArea.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libRNSafeArea.a; sourceTree = ""; }; 9552041247E749308CE7B412 /* RNSentry.xcodeproj */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "wrapper.pb-project"; name = RNSentry.xcodeproj; path = "../node_modules/react-native-sentry/ios/RNSentry.xcodeproj"; sourceTree = ""; }; A2968536BEC74A4ABBB73BD9 /* RCTYouTube.xcodeproj */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "wrapper.pb-project"; name = RCTYouTube.xcodeproj; path = "../node_modules/react-native-youtube/RCTYouTube.xcodeproj"; sourceTree = ""; }; + A734E00E7E184582A877F2B3 /* Roboto-Thin.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = "Roboto-Thin.ttf"; path = "../assets/fonts/Roboto-Thin.ttf"; sourceTree = ""; }; AC6EB561E1F64C17A69D2FAD /* Entypo.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = Entypo.ttf; path = "../node_modules/react-native-vector-icons/Fonts/Entypo.ttf"; sourceTree = ""; }; ACC6B9FDC0AD45A6BFA4FBCD /* libBVLinearGradient.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libBVLinearGradient.a; sourceTree = ""; }; B89192186C764B9FA473403A /* libRCTVideo.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libRCTVideo.a; sourceTree = ""; }; BC977883E2624E05975CA65B /* OpenSans-Regular.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = "OpenSans-Regular.ttf"; path = "../assets/fonts/OpenSans-Regular.ttf"; sourceTree = ""; }; BE17F630DB5D41FD93F32D22 /* OpenSans-LightItalic.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = "OpenSans-LightItalic.ttf"; path = "../assets/fonts/OpenSans-LightItalic.ttf"; sourceTree = ""; }; BFB7025EA936C1B5DC9725C2 /* Pods-Mattermost.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Mattermost.release.xcconfig"; path = "Pods/Target Support Files/Pods-Mattermost/Pods-Mattermost.release.xcconfig"; sourceTree = ""; }; + C46342B0E5FD4D878AF3A129 /* Roboto-BoldItalic.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = "Roboto-BoldItalic.ttf"; path = "../assets/fonts/Roboto-BoldItalic.ttf"; sourceTree = ""; }; + C5BD64DE829E455A997DCAD5 /* Roboto-Regular.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = "Roboto-Regular.ttf"; path = "../assets/fonts/Roboto-Regular.ttf"; sourceTree = ""; }; C78A387124874496AD2C1466 /* OpenSans-Semibold.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = "OpenSans-Semibold.ttf"; path = "../assets/fonts/OpenSans-Semibold.ttf"; sourceTree = ""; }; D0281D64B98143668D6AD42B /* RNLocalAuth.xcodeproj */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "wrapper.pb-project"; name = RNLocalAuth.xcodeproj; path = "../node_modules/react-native-local-auth/RNLocalAuth.xcodeproj"; sourceTree = ""; }; + D08F54E10DF14AE4BBF4E2B4 /* Roboto-MediumItalic.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = "Roboto-MediumItalic.ttf"; path = "../assets/fonts/Roboto-MediumItalic.ttf"; sourceTree = ""; }; D4B1B363C2414DA19C1AC521 /* OpenSans-Bold.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = "OpenSans-Bold.ttf"; path = "../assets/fonts/OpenSans-Bold.ttf"; sourceTree = ""; }; DF9DAAAA482343F3910A1A4C /* RCTVideo.xcodeproj */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "wrapper.pb-project"; name = RCTVideo.xcodeproj; path = "../node_modules/react-native-video/ios/RCTVideo.xcodeproj"; sourceTree = ""; }; EBA6063A99C141098D40C67A /* RNPasscodeStatus.xcodeproj */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "wrapper.pb-project"; name = RNPasscodeStatus.xcodeproj; path = "../node_modules/react-native-passcode-status/ios/RNPasscodeStatus.xcodeproj"; sourceTree = ""; }; @@ -773,18 +770,6 @@ EE671DF7637347CD8C069819 /* libRNDeviceInfo.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libRNDeviceInfo.a; sourceTree = ""; }; F1F071EE85494E269A50AE88 /* SimpleLineIcons.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = SimpleLineIcons.ttf; path = "../node_modules/react-native-vector-icons/Fonts/SimpleLineIcons.ttf"; sourceTree = ""; }; FBBEC29EE2D3418D9AC33BD5 /* OpenSans-ExtraBoldItalic.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = "OpenSans-ExtraBoldItalic.ttf"; path = "../assets/fonts/OpenSans-ExtraBoldItalic.ttf"; sourceTree = ""; }; - 6EFF13DD24CE4E26953E598A /* Roboto-Black.ttf */ = {isa = PBXFileReference; name = "Roboto-Black.ttf"; path = "../assets/fonts/Roboto-Black.ttf"; sourceTree = ""; fileEncoding = undefined; lastKnownFileType = unknown; explicitFileType = undefined; includeInIndex = 0; }; - 7F54ABFAE6CE4A6DB11D1ED7 /* Roboto-BlackItalic.ttf */ = {isa = PBXFileReference; name = "Roboto-BlackItalic.ttf"; path = "../assets/fonts/Roboto-BlackItalic.ttf"; sourceTree = ""; fileEncoding = undefined; lastKnownFileType = unknown; explicitFileType = undefined; includeInIndex = 0; }; - 71E626D4980A4560B26F0E1C /* Roboto-Bold.ttf */ = {isa = PBXFileReference; name = "Roboto-Bold.ttf"; path = "../assets/fonts/Roboto-Bold.ttf"; sourceTree = ""; fileEncoding = undefined; lastKnownFileType = unknown; explicitFileType = undefined; includeInIndex = 0; }; - C46342B0E5FD4D878AF3A129 /* Roboto-BoldItalic.ttf */ = {isa = PBXFileReference; name = "Roboto-BoldItalic.ttf"; path = "../assets/fonts/Roboto-BoldItalic.ttf"; sourceTree = ""; fileEncoding = undefined; lastKnownFileType = unknown; explicitFileType = undefined; includeInIndex = 0; }; - 031EF04FB2D14EEFAACBAA1A /* Roboto-Italic.ttf */ = {isa = PBXFileReference; name = "Roboto-Italic.ttf"; path = "../assets/fonts/Roboto-Italic.ttf"; sourceTree = ""; fileEncoding = undefined; lastKnownFileType = unknown; explicitFileType = undefined; includeInIndex = 0; }; - 34B20A903038487E8D7DEA1E /* Roboto-Light.ttf */ = {isa = PBXFileReference; name = "Roboto-Light.ttf"; path = "../assets/fonts/Roboto-Light.ttf"; sourceTree = ""; fileEncoding = undefined; lastKnownFileType = unknown; explicitFileType = undefined; includeInIndex = 0; }; - 8F0B22D2C9924FAFA7FB681C /* Roboto-LightItalic.ttf */ = {isa = PBXFileReference; name = "Roboto-LightItalic.ttf"; path = "../assets/fonts/Roboto-LightItalic.ttf"; sourceTree = ""; fileEncoding = undefined; lastKnownFileType = unknown; explicitFileType = undefined; includeInIndex = 0; }; - 09FA716C56874BDDA30FE8C4 /* Roboto-Medium.ttf */ = {isa = PBXFileReference; name = "Roboto-Medium.ttf"; path = "../assets/fonts/Roboto-Medium.ttf"; sourceTree = ""; fileEncoding = undefined; lastKnownFileType = unknown; explicitFileType = undefined; includeInIndex = 0; }; - D08F54E10DF14AE4BBF4E2B4 /* Roboto-MediumItalic.ttf */ = {isa = PBXFileReference; name = "Roboto-MediumItalic.ttf"; path = "../assets/fonts/Roboto-MediumItalic.ttf"; sourceTree = ""; fileEncoding = undefined; lastKnownFileType = unknown; explicitFileType = undefined; includeInIndex = 0; }; - C5BD64DE829E455A997DCAD5 /* Roboto-Regular.ttf */ = {isa = PBXFileReference; name = "Roboto-Regular.ttf"; path = "../assets/fonts/Roboto-Regular.ttf"; sourceTree = ""; fileEncoding = undefined; lastKnownFileType = unknown; explicitFileType = undefined; includeInIndex = 0; }; - A734E00E7E184582A877F2B3 /* Roboto-Thin.ttf */ = {isa = PBXFileReference; name = "Roboto-Thin.ttf"; path = "../assets/fonts/Roboto-Thin.ttf"; sourceTree = ""; fileEncoding = undefined; lastKnownFileType = unknown; explicitFileType = undefined; includeInIndex = 0; }; - 12D0B0E475FD46E29907305E /* Roboto-ThinItalic.ttf */ = {isa = PBXFileReference; name = "Roboto-ThinItalic.ttf"; path = "../assets/fonts/Roboto-ThinItalic.ttf"; sourceTree = ""; fileEncoding = undefined; lastKnownFileType = unknown; explicitFileType = undefined; includeInIndex = 0; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -820,7 +805,6 @@ 00C302EA1ABCBA2D00DB3ED1 /* libRCTVibration.a in Frameworks */, 139FDEF61B0652A700C62182 /* libRCTWebSocket.a in Frameworks */, 7F43D63F1F6BFA19001FC614 /* libBVLinearGradient.a in Frameworks */, - 7F6877B31E7836070094B63F /* libToolTipMenu.a in Frameworks */, 7FC200E81EBB65370099331B /* libReactNativeNavigation.a in Frameworks */, 7F2691A11EE1DC6A007574FE /* libRNNotifications.a in Frameworks */, 7F43D5D61F6BF8C2001FC614 /* libRNLocalAuth.a in Frameworks */, @@ -1194,15 +1178,6 @@ name = Products; sourceTree = ""; }; - 7F6877AB1E7835E50094B63F /* Products */ = { - isa = PBXGroup; - children = ( - 7F6877B01E7835E50094B63F /* libToolTipMenu.a */, - 7F6877B21E7835E50094B63F /* ToolTipMenuTests.xctest */, - ); - name = Products; - sourceTree = ""; - }; 7F7D7F53201645D300D31155 /* Products */ = { isa = PBXGroup; children = ( @@ -1355,7 +1330,6 @@ 3752184A1F4B9E980035444B /* RCTCameraRoll.xcodeproj */, 7F26919B1EE1DC51007574FE /* RNNotifications.xcodeproj */, 7FC200BC1EBB65100099331B /* ReactNativeNavigation.xcodeproj */, - 7F6877AA1E7835E50094B63F /* ToolTipMenu.xcodeproj */, 7F63D27B1E6C957C001FAE12 /* RCTPushNotification.xcodeproj */, 5E91572D1DD0AC6500FF2AA8 /* RCTAnimation.xcodeproj */, 146833FF1AC3E56700842450 /* React.xcodeproj */, @@ -1694,10 +1668,6 @@ ProductGroup = 7FDF28EE1E1F4B4E00DBBE56 /* Products */; ProjectRef = 2B25899FDAC149EB96ED3305 /* RNVectorIcons.xcodeproj */; }, - { - ProductGroup = 7F6877AB1E7835E50094B63F /* Products */; - ProjectRef = 7F6877AA1E7835E50094B63F /* ToolTipMenu.xcodeproj */; - }, ); projectRoot = ""; targets = ( @@ -2045,20 +2015,6 @@ remoteRef = 7F642DEE2093530B00F3165E /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; - 7F6877B01E7835E50094B63F /* libToolTipMenu.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libToolTipMenu.a; - remoteRef = 7F6877AF1E7835E50094B63F /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 7F6877B21E7835E50094B63F /* ToolTipMenuTests.xctest */ = { - isa = PBXReferenceProxy; - fileType = wrapper.cfbundle; - path = ToolTipMenuTests.xctest; - remoteRef = 7F6877B11E7835E50094B63F /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; 7F6FF6B5203499F400150948 /* libjsinspector.a */ = { isa = PBXReferenceProxy; fileType = archive.ar; diff --git a/package-lock.json b/package-lock.json index 351de10f6..e8cb9a19e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12891,11 +12891,6 @@ "prop-types": "15.6.2" } }, - "react-native-tooltip": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/react-native-tooltip/-/react-native-tooltip-5.2.0.tgz", - "integrity": "sha512-3mbPGd/VDfb3dUZmdmgg4eE8idJU4OyYM9ItGifnofz+Cz50Aua+sVGo2Ecc7zHV0S+kM0mOyLL758hhTz2gDw==" - }, "react-native-vector-icons": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/react-native-vector-icons/-/react-native-vector-icons-5.0.0.tgz", diff --git a/package.json b/package.json index 7710fc354..2d3123dbb 100644 --- a/package.json +++ b/package.json @@ -52,7 +52,6 @@ "react-native-status-bar-size": "0.3.3", "react-native-svg": "7.0.2", "react-native-tableview": "2.3.1", - "react-native-tooltip": "5.2.0", "react-native-vector-icons": "5.0.0", "react-native-video": "3.2.1", "react-native-youtube": "github:enahum/react-native-youtube#3f395b620ae4e05a3f1c6bdeef3a1158e78daadc",