Add copy post/url/mention/code to tooltip menu (#1069)
* Add copy post/url/mention/code to tooltip menu * Check for managedConfig.copyAndPasteProtection * Reorder copy options
This commit is contained in:
parent
3fdfe92800
commit
2f5201bac9
15 changed files with 246 additions and 35 deletions
|
|
@ -3,24 +3,29 @@
|
|||
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import {Text} from 'react-native';
|
||||
import {injectIntl, intlShape} from 'react-intl';
|
||||
import {Clipboard, Text} from 'react-native';
|
||||
import {intlShape} from 'react-intl';
|
||||
|
||||
import CustomPropTypes from 'app/constants/custom_prop_types';
|
||||
import mattermostManaged from 'app/mattermost_managed';
|
||||
|
||||
class AtMention extends React.PureComponent {
|
||||
export default class AtMention extends React.PureComponent {
|
||||
static propTypes = {
|
||||
intl: intlShape,
|
||||
isSearchResult: PropTypes.bool,
|
||||
mentionName: PropTypes.string.isRequired,
|
||||
mentionStyle: CustomPropTypes.Style,
|
||||
navigator: PropTypes.object.isRequired,
|
||||
onLongPress: PropTypes.func.isRequired,
|
||||
onPostPress: PropTypes.func,
|
||||
textStyle: CustomPropTypes.Style,
|
||||
theme: PropTypes.object.isRequired,
|
||||
usersByUsername: PropTypes.object.isRequired
|
||||
};
|
||||
|
||||
static contextTypes = {
|
||||
intl: intlShape
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
|
|
@ -42,7 +47,8 @@ class AtMention extends React.PureComponent {
|
|||
}
|
||||
|
||||
goToUserProfile = () => {
|
||||
const {intl, navigator, theme} = this.props;
|
||||
const {navigator, theme} = this.props;
|
||||
const {intl} = this.context;
|
||||
|
||||
navigator.push({
|
||||
screen: 'UserProfile',
|
||||
|
|
@ -86,6 +92,30 @@ class AtMention extends React.PureComponent {
|
|||
};
|
||||
}
|
||||
|
||||
handleLongPress = async () => {
|
||||
const {intl} = this.context;
|
||||
|
||||
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
|
||||
};
|
||||
}
|
||||
|
||||
this.props.onLongPress(action);
|
||||
}
|
||||
|
||||
handleCopyMention = () => {
|
||||
const {username} = this.state;
|
||||
Clipboard.setString(`@${username}`);
|
||||
}
|
||||
|
||||
render() {
|
||||
const {isSearchResult, mentionName, mentionStyle, onPostPress, textStyle} = this.props;
|
||||
const username = this.state.username;
|
||||
|
|
@ -100,6 +130,7 @@ class AtMention extends React.PureComponent {
|
|||
<Text
|
||||
style={textStyle}
|
||||
onPress={isSearchResult ? onPostPress : this.goToUserProfile}
|
||||
onLongPress={this.handleLongPress}
|
||||
>
|
||||
<Text style={mentionStyle}>
|
||||
{'@' + username}
|
||||
|
|
@ -109,5 +140,3 @@ class AtMention extends React.PureComponent {
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default injectIntl(AtMention);
|
||||
|
|
|
|||
|
|
@ -149,6 +149,7 @@ 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}
|
||||
/>
|
||||
|
|
@ -223,6 +224,7 @@ export default class Markdown extends PureComponent {
|
|||
content={content}
|
||||
language={props.language}
|
||||
textStyle={this.props.textStyles.codeBlock}
|
||||
onLongPress={this.props.onLongPress}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import {PropTypes} from 'prop-types';
|
|||
import React from 'react';
|
||||
import {injectIntl, intlShape} from 'react-intl';
|
||||
import {
|
||||
Clipboard,
|
||||
StyleSheet,
|
||||
Text,
|
||||
TouchableOpacity,
|
||||
|
|
@ -16,6 +17,7 @@ import FormattedText from 'app/components/formatted_text';
|
|||
import {getDisplayNameForLanguage} from 'app/utils/markdown';
|
||||
import {wrapWithPreventDoubleTap} from 'app/utils/tap';
|
||||
import {changeOpacity, makeStyleSheetFromTheme} from 'app/utils/theme';
|
||||
import mattermostManaged from 'app/mattermost_managed';
|
||||
|
||||
const MAX_LINES = 4;
|
||||
|
||||
|
|
@ -26,7 +28,8 @@ class MarkdownCodeBlock extends React.PureComponent {
|
|||
theme: PropTypes.object.isRequired,
|
||||
language: PropTypes.string,
|
||||
content: PropTypes.string.isRequired,
|
||||
textStyle: CustomPropTypes.Style
|
||||
textStyle: CustomPropTypes.Style,
|
||||
onLongPress: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
|
|
@ -72,6 +75,26 @@ class MarkdownCodeBlock extends React.PureComponent {
|
|||
});
|
||||
});
|
||||
|
||||
handleLongPress = async () => {
|
||||
const {formatMessage} = this.props.intl;
|
||||
|
||||
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
|
||||
};
|
||||
}
|
||||
|
||||
this.props.onLongPress(action);
|
||||
}
|
||||
|
||||
handleCopyCode = () => {
|
||||
Clipboard.setString(this.props.content);
|
||||
}
|
||||
|
||||
trimContent = (content) => {
|
||||
const lines = content.split('\n');
|
||||
const numberOfLines = lines.length;
|
||||
|
|
@ -131,7 +154,10 @@ class MarkdownCodeBlock extends React.PureComponent {
|
|||
}
|
||||
|
||||
return (
|
||||
<TouchableOpacity onPress={this.handlePress}>
|
||||
<TouchableOpacity
|
||||
onPress={this.handlePress}
|
||||
onLongPress={this.handleLongPress}
|
||||
>
|
||||
<View style={style.container}>
|
||||
<View style={style.lineNumbers}>
|
||||
<Text style={style.lineNumbersText}>
|
||||
|
|
|
|||
|
|
@ -3,16 +3,19 @@
|
|||
|
||||
import React, {Children, PureComponent} from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import {Linking, Text} from 'react-native';
|
||||
import {Clipboard, Linking, Text} from 'react-native';
|
||||
import urlParse from 'url-parse';
|
||||
import {injectIntl, intlShape} from 'react-intl';
|
||||
|
||||
import CustomPropTypes from 'app/constants/custom_prop_types';
|
||||
import Config from 'assets/config';
|
||||
import mattermostManaged from 'app/mattermost_managed';
|
||||
|
||||
export default class MarkdownLink extends PureComponent {
|
||||
class MarkdownLink extends PureComponent {
|
||||
static propTypes = {
|
||||
children: CustomPropTypes.Children.isRequired,
|
||||
href: PropTypes.string.isRequired,
|
||||
intl: intlShape.isRequired,
|
||||
onLongPress: PropTypes.func
|
||||
};
|
||||
|
||||
|
|
@ -65,16 +68,38 @@ export default class MarkdownLink extends PureComponent {
|
|||
});
|
||||
}
|
||||
|
||||
handleLongPress = async () => {
|
||||
const {formatMessage} = this.props.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
|
||||
};
|
||||
}
|
||||
|
||||
this.props.onLongPress(action);
|
||||
}
|
||||
|
||||
handleCopyURL = () => {
|
||||
Clipboard.setString(this.props.href);
|
||||
}
|
||||
|
||||
render() {
|
||||
const children = Config.ExperimentalNormalizeMarkdownLinks ? this.parseChildren() : this.props.children;
|
||||
|
||||
return (
|
||||
<Text
|
||||
onPress={this.handlePress}
|
||||
onLongPress={this.props.onLongPress}
|
||||
onLongPress={this.handleLongPress}
|
||||
>
|
||||
{children}
|
||||
</Text>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default injectIntl(MarkdownLink);
|
||||
|
|
@ -20,16 +20,22 @@ export default class OptionsContext extends PureComponent {
|
|||
cancelText: 'Cancel'
|
||||
};
|
||||
|
||||
show = () => {
|
||||
show = (additionalAction) => {
|
||||
const {actions, cancelText} = this.props;
|
||||
if (actions.length) {
|
||||
const actionsText = actions.map((a) => a.text);
|
||||
const nextActions = [...actions];
|
||||
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: actions.length
|
||||
cancelButtonIndex: nextActions.length
|
||||
}, (value) => {
|
||||
if (value !== actions.length) {
|
||||
const selectedOption = actions[value];
|
||||
if (value !== nextActions.length) {
|
||||
const selectedOption = nextActions[value];
|
||||
if (selectedOption && selectedOption.onPress) {
|
||||
selectedOption.onPress();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,9 +14,18 @@ export default class OptionsContext extends PureComponent {
|
|||
};
|
||||
|
||||
static defaultProps = {
|
||||
actions: []
|
||||
actions: [],
|
||||
additionalActions: []
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
actions: props.actions
|
||||
};
|
||||
}
|
||||
|
||||
handleHideUnderlay = () => {
|
||||
if (!this.isShowing) {
|
||||
this.props.toggleSelected(false, false);
|
||||
|
|
@ -39,9 +48,22 @@ export default class OptionsContext extends PureComponent {
|
|||
|
||||
hide = () => {
|
||||
this.refs.toolTip.hideMenu();
|
||||
this.setState({
|
||||
actions: this.props.actions
|
||||
});
|
||||
};
|
||||
|
||||
show = () => {
|
||||
show = (additionalAction) => {
|
||||
const nextActions = [...this.props.actions];
|
||||
if (additionalAction && additionalAction.text && !additionalAction.nativeEvent) {
|
||||
const copyPostIndex = nextActions.findIndex((action) => action.copyPost);
|
||||
nextActions.splice(copyPostIndex + 1, 0, additionalAction);
|
||||
}
|
||||
|
||||
this.setState({
|
||||
actions: nextActions
|
||||
});
|
||||
|
||||
this.refs.toolTip.showMenu();
|
||||
};
|
||||
|
||||
|
|
@ -56,7 +78,7 @@ export default class OptionsContext extends PureComponent {
|
|||
onHideUnderlay={this.handleHideUnderlay}
|
||||
onShowUnderlay={this.handleShowUnderlay}
|
||||
ref='toolTip'
|
||||
actions={this.props.actions}
|
||||
actions={this.state.actions}
|
||||
arrowDirection='down'
|
||||
longPress={true}
|
||||
onPress={this.handlePress}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import React, {PureComponent} from 'react';
|
|||
import PropTypes from 'prop-types';
|
||||
import {
|
||||
Alert,
|
||||
Clipboard,
|
||||
View,
|
||||
ViewPropTypes
|
||||
} from 'react-native';
|
||||
|
|
@ -50,6 +51,7 @@ class Post extends PureComponent {
|
|||
isSearchResult: PropTypes.bool,
|
||||
commentedOnPost: PropTypes.object,
|
||||
license: PropTypes.object.isRequired,
|
||||
managedConfig: PropTypes.object.isRequired,
|
||||
navigator: PropTypes.object,
|
||||
roles: PropTypes.string,
|
||||
shouldRenderReplyButton: PropTypes.bool,
|
||||
|
|
@ -317,6 +319,15 @@ class Post extends PureComponent {
|
|||
}
|
||||
};
|
||||
|
||||
handleCopyText = (text) => {
|
||||
let textToCopy = this.props.post.message;
|
||||
if (typeof text === 'string') {
|
||||
textToCopy = text;
|
||||
}
|
||||
|
||||
Clipboard.setString(textToCopy);
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
commentedOnPost,
|
||||
|
|
@ -327,7 +338,8 @@ class Post extends PureComponent {
|
|||
renderReplies,
|
||||
shouldRenderReplyButton,
|
||||
showFullDate,
|
||||
theme
|
||||
theme,
|
||||
managedConfig
|
||||
} = this.props;
|
||||
|
||||
if (!post) {
|
||||
|
|
@ -369,6 +381,7 @@ class Post extends PureComponent {
|
|||
isSearchResult={isSearchResult}
|
||||
navigator={this.props.navigator}
|
||||
onAddReaction={this.handleAddReaction}
|
||||
onCopyText={this.handleCopyText}
|
||||
onFailedPostPress={this.handleFailedPostPress}
|
||||
onPostDelete={this.handlePostDelete}
|
||||
onPostEdit={this.handlePostEdit}
|
||||
|
|
@ -376,6 +389,7 @@ class Post extends PureComponent {
|
|||
postId={post.id}
|
||||
renderReplyBar={commentedOnPost ? this.renderReplyBar : emptyFunction}
|
||||
toggleSelected={this.toggleSelected}
|
||||
managedConfig={managedConfig}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
|
|
|
|||
|
|
@ -42,9 +42,11 @@ class PostBody extends PureComponent {
|
|||
isPostEphemeral: PropTypes.bool,
|
||||
isSearchResult: PropTypes.bool,
|
||||
isSystemMessage: PropTypes.bool,
|
||||
managedConfig: PropTypes.object,
|
||||
message: PropTypes.string,
|
||||
navigator: PropTypes.object.isRequired,
|
||||
onAddReaction: PropTypes.func,
|
||||
onCopyText: PropTypes.func,
|
||||
onFailedPostPress: PropTypes.func,
|
||||
onPostDelete: PropTypes.func,
|
||||
onPostEdit: PropTypes.func,
|
||||
|
|
@ -59,6 +61,7 @@ class PostBody extends PureComponent {
|
|||
static defaultProps = {
|
||||
fileIds: [],
|
||||
onAddReaction: emptyFunction,
|
||||
onCopyText: emptyFunction,
|
||||
onFailedPostPress: emptyFunction,
|
||||
onPostDelete: emptyFunction,
|
||||
onPostEdit: emptyFunction,
|
||||
|
|
@ -91,9 +94,9 @@ class PostBody extends PureComponent {
|
|||
actions.unflagPost(postId);
|
||||
};
|
||||
|
||||
showOptionsContext = () => {
|
||||
showOptionsContext = (additionalAction) => {
|
||||
if (this.refs.options) {
|
||||
this.refs.options.show();
|
||||
this.refs.options.show(additionalAction);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -125,7 +128,7 @@ class PostBody extends PureComponent {
|
|||
return attachments;
|
||||
}
|
||||
|
||||
render() {
|
||||
render() { // eslint-disable-line complexity
|
||||
const {
|
||||
canDelete,
|
||||
canEdit,
|
||||
|
|
@ -138,6 +141,7 @@ class PostBody extends PureComponent {
|
|||
isSearchResult,
|
||||
isSystemMessage,
|
||||
intl,
|
||||
managedConfig,
|
||||
message,
|
||||
navigator,
|
||||
onFailedPostPress,
|
||||
|
|
@ -160,6 +164,19 @@ class PostBody extends PureComponent {
|
|||
|
||||
// we should check for the user roles and permissions
|
||||
if (!isPendingOrFailedPost && !isSearchResult && !isSystemMessage && !isPostEphemeral) {
|
||||
actions.push({
|
||||
text: formatMessage({id: 'mobile.post_info.add_reaction', defaultMessage: 'Add Reaction'}),
|
||||
onPress: this.props.onAddReaction
|
||||
});
|
||||
|
||||
if (managedConfig.copyAndPasteProtection !== 'true') {
|
||||
actions.push({
|
||||
text: formatMessage({id: 'mobile.post_info.copy_post', defaultMessage: 'Copy Post'}),
|
||||
onPress: this.props.onCopyText,
|
||||
copyPost: true
|
||||
});
|
||||
}
|
||||
|
||||
if (isFlagged) {
|
||||
actions.push({
|
||||
text: formatMessage({id: 'post_info.mobile.unflag', defaultMessage: 'Unflag'}),
|
||||
|
|
@ -179,11 +196,6 @@ class PostBody extends PureComponent {
|
|||
if (canDelete && !hasBeenDeleted) {
|
||||
actions.push({text: formatMessage({id: 'post_info.del', defaultMessage: 'Delete'}), onPress: onPostDelete});
|
||||
}
|
||||
|
||||
actions.push({
|
||||
text: formatMessage({id: 'mobile.post_info.add_reaction', defaultMessage: 'Add Reaction'}),
|
||||
onPress: this.props.onAddReaction
|
||||
});
|
||||
}
|
||||
|
||||
let body;
|
||||
|
|
@ -265,6 +277,7 @@ class PostBody extends PureComponent {
|
|||
message={message}
|
||||
postProps={postProps}
|
||||
textStyles={textStyles}
|
||||
onLongPress={this.showOptionsContext}
|
||||
/>
|
||||
{this.renderFileAttachments()}
|
||||
{hasReactions && <Reactions postId={postId}/>}
|
||||
|
|
|
|||
|
|
@ -11,14 +11,15 @@ import {
|
|||
TouchableWithoutFeedback,
|
||||
View
|
||||
} from 'react-native';
|
||||
|
||||
import {YouTubeStandaloneAndroid, YouTubeStandaloneIOS} from 'react-native-youtube';
|
||||
import youTubeVideoId from 'youtube-video-id';
|
||||
|
||||
import youtubePlayIcon from 'assets/images/icons/youtube-play-icon.png';
|
||||
|
||||
import PostAttachmentOpenGraph from 'app/components/post_attachment_opengraph';
|
||||
import SlackAttachments from 'app/components/slack_attachments';
|
||||
import CustomPropTypes from 'app/constants/custom_prop_types';
|
||||
import {emptyFunction} from 'app/utils/general';
|
||||
import {isImageLink, isYoutubeLink} from 'app/utils/url';
|
||||
|
||||
const MAX_IMAGE_HEIGHT = 150;
|
||||
|
|
@ -33,6 +34,7 @@ export default class PostBodyAdditionalContent extends PureComponent {
|
|||
link: PropTypes.string,
|
||||
message: PropTypes.string.isRequired,
|
||||
navigator: PropTypes.object.isRequired,
|
||||
onLongPress: PropTypes.func,
|
||||
openGraphData: PropTypes.object,
|
||||
postProps: PropTypes.object.isRequired,
|
||||
showLinkPreviews: PropTypes.bool.isRequired,
|
||||
|
|
@ -40,6 +42,10 @@ export default class PostBodyAdditionalContent extends PureComponent {
|
|||
theme: PropTypes.object.isRequired
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
onLongPress: emptyFunction
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
|
|
@ -163,6 +169,7 @@ export default class PostBodyAdditionalContent extends PureComponent {
|
|||
navigator={navigator}
|
||||
textStyles={textStyles}
|
||||
theme={theme}
|
||||
onLongPress={this.props.onLongPress}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import ChannelIntro from 'app/components/channel_intro';
|
|||
import FlatList from 'app/components/inverted_flat_list';
|
||||
import Post from 'app/components/post';
|
||||
import {DATE_LINE, START_OF_NEW_MESSAGES} from 'app/selectors/post_list';
|
||||
import mattermostManaged from 'app/mattermost_managed';
|
||||
|
||||
import DateHeader from './date_header';
|
||||
import LoadMorePosts from './load_more_posts';
|
||||
|
|
@ -43,6 +44,22 @@ export default class PostList extends PureComponent {
|
|||
loadMore: () => true
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
managedConfig: {}
|
||||
};
|
||||
}
|
||||
|
||||
componentWillMount() {
|
||||
mattermostManaged.addEventListener('change', this.setManagedConfig);
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.setManagedConfig();
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
if (prevProps.channelId !== this.props.channelId && this.refs.list) {
|
||||
// When switching channels make sure we start from the bottom
|
||||
|
|
@ -50,6 +67,17 @@ export default class PostList extends PureComponent {
|
|||
}
|
||||
}
|
||||
|
||||
setManagedConfig = async (config) => {
|
||||
let nextConfig = config;
|
||||
if (!nextConfig) {
|
||||
nextConfig = await mattermostManaged.getLocalConfig();
|
||||
}
|
||||
|
||||
this.setState({
|
||||
managedConfig: nextConfig
|
||||
});
|
||||
}
|
||||
|
||||
getItem = (data, index) => data[index];
|
||||
|
||||
getItemCount = (data) => data.length;
|
||||
|
|
@ -115,6 +143,7 @@ export default class PostList extends PureComponent {
|
|||
renderReplies,
|
||||
shouldRenderReplyButton
|
||||
} = this.props;
|
||||
const {managedConfig} = this.state;
|
||||
|
||||
return (
|
||||
<Post
|
||||
|
|
@ -127,6 +156,7 @@ export default class PostList extends PureComponent {
|
|||
shouldRenderReplyButton={shouldRenderReplyButton}
|
||||
onPress={onPostPress}
|
||||
navigator={navigator}
|
||||
managedConfig={managedConfig}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -16,11 +16,12 @@ export default class SlackAttachments extends PureComponent {
|
|||
blockStyles: PropTypes.object,
|
||||
textStyles: PropTypes.object,
|
||||
navigator: PropTypes.object.isRequired,
|
||||
theme: PropTypes.object
|
||||
theme: PropTypes.object,
|
||||
onLongPress: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
render() {
|
||||
const {attachments, baseTextStyle, blockStyles, navigator, textStyles, theme} = this.props;
|
||||
const {attachments, baseTextStyle, blockStyles, navigator, textStyles, theme, onLongPress} = this.props;
|
||||
const content = [];
|
||||
|
||||
attachments.forEach((attachment, i) => {
|
||||
|
|
@ -33,6 +34,7 @@ export default class SlackAttachments extends PureComponent {
|
|||
textStyles={textStyles}
|
||||
navigator={navigator}
|
||||
theme={theme}
|
||||
onLongPress={onLongPress}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -22,7 +22,8 @@ export default class SlackAttachment extends PureComponent {
|
|||
blockStyles: PropTypes.object,
|
||||
navigator: PropTypes.object.isRequired,
|
||||
textStyles: PropTypes.object,
|
||||
theme: PropTypes.object
|
||||
theme: PropTypes.object,
|
||||
onLongPress: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
|
|
@ -117,6 +118,7 @@ export default class SlackAttachment extends PureComponent {
|
|||
blockStyles={blockStyles}
|
||||
value={(field.value || '')}
|
||||
navigator={navigator}
|
||||
onLongPress={this.props.onLongPress}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
|
|
@ -163,7 +165,7 @@ export default class SlackAttachment extends PureComponent {
|
|||
this.setState({collapsed, text});
|
||||
};
|
||||
|
||||
render() {
|
||||
render() { // eslint-disable-line complexity
|
||||
const {
|
||||
attachment,
|
||||
baseTextStyle,
|
||||
|
|
@ -185,6 +187,7 @@ export default class SlackAttachment extends PureComponent {
|
|||
blockStyles={blockStyles}
|
||||
value={attachment.pretext}
|
||||
navigator={navigator}
|
||||
onLongPress={this.props.onLongPress}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
|
|
@ -293,6 +296,7 @@ export default class SlackAttachment extends PureComponent {
|
|||
blockStyles={blockStyles}
|
||||
value={this.state.text}
|
||||
navigator={navigator}
|
||||
onLongPress={this.props.onLongPress}
|
||||
/>
|
||||
{moreLess}
|
||||
</View>
|
||||
|
|
|
|||
|
|
@ -7,9 +7,12 @@ import JailMonkey from 'jail-monkey';
|
|||
|
||||
const {MattermostManaged} = NativeModules;
|
||||
|
||||
let localConfig;
|
||||
|
||||
export default {
|
||||
addEventListener: (name, callback) => {
|
||||
DeviceEventEmitter.addListener(name, (config) => {
|
||||
localConfig = config;
|
||||
if (callback && typeof callback === 'function') {
|
||||
callback(config);
|
||||
}
|
||||
|
|
@ -19,6 +22,17 @@ export default {
|
|||
authenticate: LocalAuth.authenticate,
|
||||
blurAppScreen: MattermostManaged.blurAppScreen,
|
||||
getConfig: MattermostManaged.getConfig,
|
||||
getLocalConfig: async () => {
|
||||
if (!localConfig) {
|
||||
try {
|
||||
localConfig = await MattermostManaged.getConfig();
|
||||
} catch (error) {
|
||||
// do nothing...
|
||||
}
|
||||
}
|
||||
|
||||
return localConfig || {};
|
||||
},
|
||||
isDeviceSecure: async () => {
|
||||
try {
|
||||
return await LocalAuth.isDeviceSecure();
|
||||
|
|
|
|||
|
|
@ -7,10 +7,12 @@ import JailMonkey from 'jail-monkey';
|
|||
const {BlurAppScreen, MattermostManaged} = NativeModules;
|
||||
|
||||
const listeners = [];
|
||||
let localConfig;
|
||||
|
||||
export default {
|
||||
addEventListener: (name, callback) => {
|
||||
const listener = DeviceEventEmitter.addListener(name, (config) => {
|
||||
localConfig = config;
|
||||
if (callback && typeof callback === 'function') {
|
||||
callback(config);
|
||||
}
|
||||
|
|
@ -26,6 +28,17 @@ export default {
|
|||
authenticate: LocalAuth.authenticate,
|
||||
blurAppScreen: BlurAppScreen.enabled,
|
||||
getConfig: MattermostManaged.getConfig,
|
||||
getLocalConfig: async () => {
|
||||
if (!localConfig) {
|
||||
try {
|
||||
localConfig = await MattermostManaged.getConfig();
|
||||
} catch (error) {
|
||||
// do nothing...
|
||||
}
|
||||
}
|
||||
|
||||
return localConfig || {};
|
||||
},
|
||||
isDeviceSecure: async () => {
|
||||
try {
|
||||
return await LocalAuth.isDeviceSecure();
|
||||
|
|
|
|||
|
|
@ -1970,7 +1970,10 @@
|
|||
"mobile.managed.exit": "Exit",
|
||||
"mobile.managed.jailbreak": "Jailbroken devices are not trusted by {vendor}, please exit the app.",
|
||||
"mobile.managed.secured_by": "Secured by {vendor}",
|
||||
"mobile.markdown.code.copy_code": "Copy Code",
|
||||
"mobile.markdown.link.copy_url": "Copy URL",
|
||||
"mobile.markdown.code.plusMoreLines": "+{count, number} more lines",
|
||||
"mobile.mention.copy_mention": "Copy Mention",
|
||||
"mobile.more_dms.start": "Start",
|
||||
"mobile.more_dms.title": "New Conversation",
|
||||
"mobile.notice_mobile_link": "mobile apps",
|
||||
|
|
@ -2019,6 +2022,7 @@
|
|||
"mobile.post.failed_title": "Unable to send your message",
|
||||
"mobile.post.retry": "Refresh",
|
||||
"mobile.post_info.add_reaction": "Add Reaction",
|
||||
"mobile.post_info.copy_post": "Copy Post",
|
||||
"mobile.request.invalid_response": "Received invalid response from the server.",
|
||||
"mobile.retry_message": "Refreshing messages failed. Pull up to try again.",
|
||||
"mobile.routes.channelInfo": "Info",
|
||||
|
|
|
|||
Loading…
Reference in a new issue