forked from Ivasoft/mattermost-mobile
Revert "[MM-29225] Define LSApplicationQueriesSchemes so Linking.canO… (#5067)
* Revert "[MM-29225] Define LSApplicationQueriesSchemes so Linking.canOpenURL can work (#5007)"
This reverts commit f3baaa6aa3.
* Create and use tryOpenURL
* Add missing onError functions
* Update app/components/markdown/markdown_link/markdown_link.js
Co-authored-by: Elias Nahum <nahumhbl@gmail.com>
Co-authored-by: Elias Nahum <nahumhbl@gmail.com>
This commit is contained in:
@@ -6,7 +6,6 @@ import PropTypes from 'prop-types';
|
||||
import {
|
||||
Alert,
|
||||
Animated,
|
||||
Linking,
|
||||
TouchableOpacity,
|
||||
View,
|
||||
} from 'react-native';
|
||||
@@ -17,6 +16,7 @@ import FormattedText from '@components/formatted_text';
|
||||
import {DeviceTypes} from '@constants';
|
||||
import {checkUpgradeType, isUpgradeAvailable} from '@utils/client_upgrade';
|
||||
import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
|
||||
import {tryOpenURL} from '@utils/url';
|
||||
import {showModal, dismissModal} from '@actions/navigation';
|
||||
|
||||
const {View: AnimatedView} = Animated;
|
||||
@@ -121,11 +121,7 @@ export default class ClientUpgradeListener extends PureComponent {
|
||||
const {downloadLink} = this.props;
|
||||
const {intl} = this.context;
|
||||
|
||||
Linking.canOpenURL(downloadLink).then((supported) => {
|
||||
if (supported) {
|
||||
return Linking.openURL(downloadLink);
|
||||
}
|
||||
|
||||
const onError = () => {
|
||||
Alert.alert(
|
||||
intl.formatMessage({
|
||||
id: 'mobile.client_upgrade.download_error.title',
|
||||
@@ -136,9 +132,8 @@ export default class ClientUpgradeListener extends PureComponent {
|
||||
defaultMessage: 'An error occurred while trying to open the download link.',
|
||||
}),
|
||||
);
|
||||
|
||||
return false;
|
||||
});
|
||||
};
|
||||
tryOpenURL(downloadLink, onError);
|
||||
|
||||
this.toggleUpgradeMessage(false);
|
||||
};
|
||||
|
||||
@@ -5,7 +5,7 @@ import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import {intlShape} from 'react-intl';
|
||||
import {
|
||||
Linking,
|
||||
Alert,
|
||||
Platform,
|
||||
StyleSheet,
|
||||
Text,
|
||||
@@ -24,7 +24,7 @@ import EphemeralStore from '@store/ephemeral_store';
|
||||
import BottomSheet from '@utils/bottom_sheet';
|
||||
import {generateId} from '@utils/file';
|
||||
import {calculateDimensions, getViewPortWidth, isGifTooLarge, openGalleryAtIndex} from '@utils/images';
|
||||
import {normalizeProtocol} from '@utils/url';
|
||||
import {normalizeProtocol, tryOpenURL} from '@utils/url';
|
||||
|
||||
import mattermostManaged from 'app/mattermost_managed';
|
||||
|
||||
@@ -123,12 +123,22 @@ export default class MarkdownImage extends ImageViewPort {
|
||||
|
||||
handleLinkPress = () => {
|
||||
const url = normalizeProtocol(this.props.linkDestination);
|
||||
const {intl} = this.context;
|
||||
|
||||
Linking.canOpenURL(url).then((supported) => {
|
||||
if (supported) {
|
||||
Linking.openURL(url);
|
||||
}
|
||||
});
|
||||
const onError = () => {
|
||||
Alert.alert(
|
||||
intl.formatMessage({
|
||||
id: 'mobile.link.error.title',
|
||||
defaultMessage: 'Error',
|
||||
}),
|
||||
intl.formatMessage({
|
||||
id: 'mobile.link.error.text',
|
||||
defaultMessage: 'Unable to open the link.',
|
||||
}),
|
||||
);
|
||||
};
|
||||
|
||||
tryOpenURL(url, onError);
|
||||
};
|
||||
|
||||
handleLinkLongPress = async () => {
|
||||
|
||||
@@ -3,10 +3,10 @@
|
||||
|
||||
import React, {Children, PureComponent} from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import {Alert, Linking, Text} from 'react-native';
|
||||
import {Alert, Text} from 'react-native';
|
||||
import Clipboard from '@react-native-community/clipboard';
|
||||
import urlParse from 'url-parse';
|
||||
import {intlShape} from 'react-intl';
|
||||
import urlParse from 'url-parse';
|
||||
|
||||
import Config from '@assets/config';
|
||||
import {DeepLinkTypes} from '@constants';
|
||||
@@ -15,7 +15,7 @@ import {getCurrentServerUrl} from '@init/credentials';
|
||||
import BottomSheet from '@utils/bottom_sheet';
|
||||
import {errorBadChannel} from '@utils/draft';
|
||||
import {preventDoubleTap} from '@utils/tap';
|
||||
import {matchDeepLink, normalizeProtocol} from '@utils/url';
|
||||
import {matchDeepLink, normalizeProtocol, tryOpenURL} from '@utils/url';
|
||||
|
||||
import mattermostManaged from 'app/mattermost_managed';
|
||||
|
||||
@@ -64,23 +64,21 @@ export default class MarkdownLink extends PureComponent {
|
||||
onPermalinkPress(match.postId, match.teamName);
|
||||
}
|
||||
} else {
|
||||
Linking.canOpenURL(url).then((supported) => {
|
||||
if (supported) {
|
||||
Linking.openURL(url);
|
||||
} else {
|
||||
const {formatMessage} = this.context.intl;
|
||||
Alert.alert(
|
||||
formatMessage({
|
||||
id: 'mobile.server_link.error.title',
|
||||
defaultMessage: 'Link Error',
|
||||
}),
|
||||
formatMessage({
|
||||
id: 'mobile.server_link.error.text',
|
||||
defaultMessage: 'The link could not be found on this server.',
|
||||
}),
|
||||
);
|
||||
}
|
||||
});
|
||||
const onError = () => {
|
||||
const {formatMessage} = this.context.intl;
|
||||
Alert.alert(
|
||||
formatMessage({
|
||||
id: 'mobile.link.error.title',
|
||||
defaultMessage: 'Error',
|
||||
}),
|
||||
formatMessage({
|
||||
id: 'mobile.link.error.text',
|
||||
defaultMessage: 'Unable to open the link.',
|
||||
}),
|
||||
);
|
||||
};
|
||||
|
||||
tryOpenURL(url, onError);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -2,11 +2,13 @@
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import React, {PureComponent} from 'react';
|
||||
import {Linking, Text, View} from 'react-native';
|
||||
import {Alert, Text, View} from 'react-native';
|
||||
import FastImage from 'react-native-fast-image';
|
||||
import {intlShape} from 'react-intl';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import {changeOpacity, makeStyleSheetFromTheme} from 'app/utils/theme';
|
||||
import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
|
||||
import {tryOpenURL} from '@utils/url';
|
||||
|
||||
export default class AttachmentAuthor extends PureComponent {
|
||||
static propTypes = {
|
||||
@@ -16,10 +18,29 @@ export default class AttachmentAuthor extends PureComponent {
|
||||
theme: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
static contextTypes = {
|
||||
intl: intlShape.isRequired,
|
||||
};
|
||||
|
||||
openLink = () => {
|
||||
const {link} = this.props;
|
||||
if (link && Linking.canOpenURL(link)) {
|
||||
Linking.openURL(link);
|
||||
const {intl} = this.context;
|
||||
|
||||
if (link) {
|
||||
const onError = () => {
|
||||
Alert.alert(
|
||||
intl.formatMessage({
|
||||
id: 'mobile.link.error.title',
|
||||
defaultMessage: 'Error',
|
||||
}),
|
||||
intl.formatMessage({
|
||||
id: 'mobile.link.error.text',
|
||||
defaultMessage: 'Unable to open the link.',
|
||||
}),
|
||||
);
|
||||
};
|
||||
|
||||
tryOpenURL(link, onError);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -2,11 +2,13 @@
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import React, {PureComponent} from 'react';
|
||||
import {Linking, Text, View} from 'react-native';
|
||||
import {Alert, Text, View} from 'react-native';
|
||||
import {intlShape} from 'react-intl';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import {makeStyleSheetFromTheme} from 'app/utils/theme';
|
||||
import Markdown from 'app/components/markdown';
|
||||
import Markdown from '@components/markdown';
|
||||
import {makeStyleSheetFromTheme} from '@utils/theme';
|
||||
import {tryOpenURL} from '@utils/url';
|
||||
|
||||
export default class AttachmentTitle extends PureComponent {
|
||||
static propTypes = {
|
||||
@@ -15,10 +17,29 @@ export default class AttachmentTitle extends PureComponent {
|
||||
value: PropTypes.string,
|
||||
};
|
||||
|
||||
static contextTypes = {
|
||||
intl: intlShape.isRequired,
|
||||
};
|
||||
|
||||
openLink = () => {
|
||||
const {link} = this.props;
|
||||
if (link && Linking.canOpenURL(link)) {
|
||||
Linking.openURL(link);
|
||||
const {intl} = this.context;
|
||||
|
||||
if (link) {
|
||||
const onError = () => {
|
||||
Alert.alert(
|
||||
intl.formatMessage({
|
||||
id: 'mobile.link.error.title',
|
||||
defaultMessage: 'Error',
|
||||
}),
|
||||
intl.formatMessage({
|
||||
id: 'mobile.link.error.text',
|
||||
defaultMessage: 'Unable to open the link.',
|
||||
}),
|
||||
);
|
||||
};
|
||||
|
||||
tryOpenURL(link, onError);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -3,8 +3,9 @@
|
||||
|
||||
import React, {PureComponent} from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import {Linking, Text, View} from 'react-native';
|
||||
import {Alert, Text, View} from 'react-native';
|
||||
import FastImage from 'react-native-fast-image';
|
||||
import {intlShape} from 'react-intl';
|
||||
import parseUrl from 'url-parse';
|
||||
|
||||
import {TABLET_WIDTH} from '@components/sidebars/drawer_layout';
|
||||
@@ -14,6 +15,7 @@ import {generateId} from '@utils/file';
|
||||
import {openGalleryAtIndex, calculateDimensions} from '@utils/images';
|
||||
import {getNearestPoint} from '@utils/opengraph';
|
||||
import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
|
||||
import {tryOpenURL} from '@utils/url';
|
||||
|
||||
const MAX_IMAGE_HEIGHT = 150;
|
||||
const VIEWPORT_IMAGE_OFFSET = 93;
|
||||
@@ -31,6 +33,10 @@ export default class PostAttachmentOpenGraph extends PureComponent {
|
||||
theme: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
static contextTypes = {
|
||||
intl: intlShape.isRequired,
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
@@ -153,7 +159,21 @@ export default class PostAttachmentOpenGraph extends PureComponent {
|
||||
};
|
||||
|
||||
goToLink = () => {
|
||||
Linking.openURL(this.props.link);
|
||||
const {intl} = this.context;
|
||||
const onError = () => {
|
||||
Alert.alert(
|
||||
intl.formatMessage({
|
||||
id: 'mobile.link.error.title',
|
||||
defaultMessage: 'Error',
|
||||
}),
|
||||
intl.formatMessage({
|
||||
id: 'mobile.link.error.text',
|
||||
defaultMessage: 'Unable to open the link.',
|
||||
}),
|
||||
);
|
||||
};
|
||||
|
||||
tryOpenURL(this.props.link, onError);
|
||||
};
|
||||
|
||||
handlePreviewImage = () => {
|
||||
|
||||
@@ -6,7 +6,6 @@ import PropTypes from 'prop-types';
|
||||
import {
|
||||
Alert,
|
||||
Image,
|
||||
Linking,
|
||||
Platform,
|
||||
StyleSheet,
|
||||
StatusBar,
|
||||
@@ -23,7 +22,7 @@ import CustomPropTypes from '@constants/custom_prop_types';
|
||||
import EventEmitter from '@mm-redux/utils/event_emitter';
|
||||
import {generateId} from '@utils/file';
|
||||
import {calculateDimensions, getViewPortWidth, openGalleryAtIndex} from '@utils/images';
|
||||
import {getYouTubeVideoId, isImageLink, isYoutubeLink} from '@utils/url';
|
||||
import {getYouTubeVideoId, isImageLink, isYoutubeLink, tryOpenURL} from '@utils/url';
|
||||
|
||||
const MAX_YOUTUBE_IMAGE_HEIGHT = 202;
|
||||
const MAX_YOUTUBE_IMAGE_WIDTH = 360;
|
||||
@@ -272,7 +271,21 @@ export default class PostBodyAdditionalContent extends ImageViewPort {
|
||||
startTime,
|
||||
}).catch(this.playYouTubeVideoError);
|
||||
} else {
|
||||
Linking.openURL(videoLink);
|
||||
const {intl} = this.context;
|
||||
const onError = () => {
|
||||
Alert.alert(
|
||||
intl.formatMessage({
|
||||
id: 'mobile.link.error.title',
|
||||
defaultMessage: 'Error',
|
||||
}),
|
||||
intl.formatMessage({
|
||||
id: 'mobile.link.error.text',
|
||||
defaultMessage: 'Unable to open the link.',
|
||||
}),
|
||||
);
|
||||
};
|
||||
|
||||
tryOpenURL(videoLink, onError);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {Alert} from 'react-native';
|
||||
|
||||
import {IntegrationTypes} from '@mm-redux/action_types';
|
||||
import {General} from '../constants';
|
||||
import {Client4} from '@mm-redux/client';
|
||||
@@ -23,7 +26,7 @@ import {getUserByUsername} from '@mm-redux/actions/users';
|
||||
import {getConfig, getCurrentUrl} from '@mm-redux/selectors/entities/general';
|
||||
import * as DraftUtils from '@utils/draft';
|
||||
import {permalinkBadTeam} from '@utils/general';
|
||||
import {getURLAndMatch} from '@utils/url';
|
||||
import {getURLAndMatch, tryOpenURL} from '@utils/url';
|
||||
|
||||
export function createIncomingHook(hook: IncomingWebhook): ActionFunc {
|
||||
return bindClientFunc({
|
||||
@@ -454,7 +457,19 @@ export function handleGotoLocation(href: string, intl: any): ActionFunc {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
DraftUtils.tryOpenURL(url);
|
||||
const {formatMessage} = this.context.intl;
|
||||
const onError = () => Alert.alert(
|
||||
formatMessage({
|
||||
id: 'mobile.server_link.error.title',
|
||||
defaultMessage: 'Link Error',
|
||||
}),
|
||||
formatMessage({
|
||||
id: 'mobile.server_link.error.text',
|
||||
defaultMessage: 'The link could not be found on this server.',
|
||||
}),
|
||||
);
|
||||
|
||||
tryOpenURL(url, onError);
|
||||
}
|
||||
return {data: true};
|
||||
};
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
import React, {PureComponent} from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import {
|
||||
Linking,
|
||||
Alert,
|
||||
ScrollView,
|
||||
Text,
|
||||
TouchableOpacity,
|
||||
@@ -12,6 +12,7 @@ import {
|
||||
} from 'react-native';
|
||||
import DeviceInfo from 'react-native-device-info';
|
||||
import {SafeAreaView} from 'react-native-safe-area-context';
|
||||
import {intlShape} from 'react-intl';
|
||||
|
||||
import Config from '@assets/config';
|
||||
import CompassIcon from '@components/compass_icon';
|
||||
@@ -19,6 +20,7 @@ import FormattedText from '@components/formatted_text';
|
||||
import StatusBar from '@components/status_bar';
|
||||
import AboutLinks from '@constants/about_links';
|
||||
import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
|
||||
import {tryOpenURL} from '@utils/url';
|
||||
|
||||
const MATTERMOST_BUNDLE_IDS = ['com.mattermost.rnbeta', 'com.mattermost.rn'];
|
||||
|
||||
@@ -29,28 +31,50 @@ export default class About extends PureComponent {
|
||||
theme: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
static contextTypes = {
|
||||
intl: intlShape.isRequired,
|
||||
};
|
||||
|
||||
openURL = (url) => {
|
||||
const {intl} = this.context;
|
||||
const onError = () => {
|
||||
Alert.alert(
|
||||
intl.formatMessage({
|
||||
id: 'mobile.link.error.title',
|
||||
defaultMessage: 'Error',
|
||||
}),
|
||||
intl.formatMessage({
|
||||
id: 'mobile.link.error.text',
|
||||
defaultMessage: 'Unable to open the link.',
|
||||
}),
|
||||
);
|
||||
};
|
||||
|
||||
tryOpenURL(url, onError);
|
||||
};
|
||||
|
||||
handleAboutTeam = () => {
|
||||
Linking.openURL(Config.AboutTeamURL);
|
||||
this.openURL(Config.AboutTeamURL);
|
||||
};
|
||||
|
||||
handleAboutEnterprise = () => {
|
||||
Linking.openURL(Config.AboutEnterpriseURL);
|
||||
this.openURL(Config.AboutEnterpriseURL);
|
||||
};
|
||||
|
||||
handlePlatformNotice = () => {
|
||||
Linking.openURL(Config.PlatformNoticeURL);
|
||||
this.openURL(Config.PlatformNoticeURL);
|
||||
};
|
||||
|
||||
handleMobileNotice = () => {
|
||||
Linking.openURL(Config.MobileNoticeURL);
|
||||
this.openURL(Config.MobileNoticeURL);
|
||||
};
|
||||
|
||||
handleTermsOfService = () => {
|
||||
Linking.openURL(AboutLinks.TERMS_OF_SERVICE);
|
||||
this.openURL(AboutLinks.TERMS_OF_SERVICE);
|
||||
};
|
||||
|
||||
handlePrivacyPolicy = () => {
|
||||
Linking.openURL(AboutLinks.PRIVACY_POLICY);
|
||||
this.openURL(AboutLinks.PRIVACY_POLICY);
|
||||
}
|
||||
|
||||
render() {
|
||||
|
||||
@@ -7,7 +7,6 @@ import PropTypes from 'prop-types';
|
||||
import {
|
||||
Alert,
|
||||
Image,
|
||||
Linking,
|
||||
ScrollView,
|
||||
TouchableOpacity,
|
||||
View,
|
||||
@@ -21,6 +20,7 @@ import StatusBar from '@components/status_bar';
|
||||
import {UpgradeTypes} from '@constants';
|
||||
import {checkUpgradeType, isUpgradeAvailable} from '@utils/client_upgrade';
|
||||
import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
|
||||
import {tryOpenURL} from '@utils/url';
|
||||
|
||||
export default class ClientUpgrade extends PureComponent {
|
||||
static propTypes = {
|
||||
@@ -104,11 +104,7 @@ export default class ClientUpgrade extends PureComponent {
|
||||
const {downloadLink} = this.props;
|
||||
const {intl} = this.context;
|
||||
|
||||
Linking.canOpenURL(downloadLink).then((supported) => {
|
||||
if (supported) {
|
||||
return Linking.openURL(downloadLink);
|
||||
}
|
||||
|
||||
const onError = () => {
|
||||
Alert.alert(
|
||||
intl.formatMessage({
|
||||
id: 'mobile.client_upgrade.download_error.title',
|
||||
@@ -119,9 +115,9 @@ export default class ClientUpgrade extends PureComponent {
|
||||
defaultMessage: 'An error occurred while trying to open the download link.',
|
||||
}),
|
||||
);
|
||||
};
|
||||
|
||||
return false;
|
||||
});
|
||||
tryOpenURL(downloadLink, onError);
|
||||
};
|
||||
|
||||
renderMustUpgrade() {
|
||||
|
||||
@@ -5,7 +5,7 @@ import React, {PureComponent} from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import {intlShape, injectIntl} from 'react-intl';
|
||||
import {
|
||||
Linking,
|
||||
Alert,
|
||||
Platform,
|
||||
ScrollView,
|
||||
View,
|
||||
@@ -21,7 +21,7 @@ import SettingsItem from '@screens/settings/settings_item';
|
||||
import {t} from '@utils/i18n';
|
||||
import {preventDoubleTap} from '@utils/tap';
|
||||
import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
|
||||
import {isValidUrl} from '@utils/url';
|
||||
import {isValidUrl, tryOpenURL} from '@utils/url';
|
||||
|
||||
class Settings extends PureComponent {
|
||||
static propTypes = {
|
||||
@@ -135,28 +135,48 @@ class Settings extends PureComponent {
|
||||
});
|
||||
|
||||
openErrorEmail = preventDoubleTap(() => {
|
||||
const {config} = this.props;
|
||||
const {config, intl} = this.props;
|
||||
const recipient = config.SupportEmail;
|
||||
const subject = `Problem with ${config.SiteName} React Native app`;
|
||||
const mailTo = `mailto:${recipient}?subject=${subject}&body=${this.errorEmailBody()}`;
|
||||
|
||||
Linking.canOpenURL(mailTo).then((supported) => {
|
||||
if (supported) {
|
||||
Linking.openURL(mailTo);
|
||||
this.props.actions.clearErrors();
|
||||
}
|
||||
});
|
||||
const onSuccess = () => {
|
||||
this.props.actions.clearErrors();
|
||||
};
|
||||
const onError = () => {
|
||||
Alert.alert(
|
||||
intl.formatMessage({
|
||||
id: 'mobile.mailTo.error.title',
|
||||
defaultMessage: 'Error',
|
||||
}),
|
||||
intl.formatMessage({
|
||||
id: 'mobile.mailTo.error.text',
|
||||
defaultMessage: 'Unable to open an email client.',
|
||||
}),
|
||||
);
|
||||
};
|
||||
|
||||
tryOpenURL(mailTo, onError, onSuccess);
|
||||
});
|
||||
|
||||
openHelp = preventDoubleTap(() => {
|
||||
const {config} = this.props;
|
||||
const {config, intl} = this.props;
|
||||
const link = config.HelpLink ? config.HelpLink.toLowerCase() : '';
|
||||
|
||||
Linking.canOpenURL(link).then((supported) => {
|
||||
if (supported) {
|
||||
Linking.openURL(link);
|
||||
}
|
||||
});
|
||||
const onError = () => {
|
||||
Alert.alert(
|
||||
intl.formatMessage({
|
||||
id: 'mobile.link.error.title',
|
||||
defaultMessage: 'Error',
|
||||
}),
|
||||
intl.formatMessage({
|
||||
id: 'mobile.link.error.text',
|
||||
defaultMessage: 'Unable to open the link.',
|
||||
}),
|
||||
);
|
||||
};
|
||||
|
||||
tryOpenURL(link, onError);
|
||||
});
|
||||
|
||||
render() {
|
||||
|
||||
@@ -4,10 +4,10 @@
|
||||
import React, {PureComponent} from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import {
|
||||
Alert,
|
||||
ScrollView,
|
||||
Text,
|
||||
View,
|
||||
Linking,
|
||||
} from 'react-native';
|
||||
import {intlShape} from 'react-intl';
|
||||
import {Navigation} from 'react-native-navigation';
|
||||
@@ -30,6 +30,7 @@ import {getUserCurrentTimezone} from '@mm-redux/utils/timezone_utils';
|
||||
import {alertErrorWithFallback} from '@utils/general';
|
||||
import {t} from '@utils/i18n';
|
||||
import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
|
||||
import {tryOpenURL} from '@utils/url';
|
||||
import {isGuest} from '@utils/users';
|
||||
|
||||
import UserProfileRow from './user_profile_row';
|
||||
@@ -229,11 +230,25 @@ export default class UserProfile extends PureComponent {
|
||||
handleLinkPress = (link) => {
|
||||
const username = this.props.user.username;
|
||||
const email = this.props.user.email;
|
||||
const {intl} = this.context;
|
||||
|
||||
return () => {
|
||||
let hydrated = link.replace(/{email}/, email);
|
||||
hydrated = hydrated.replace(/{username}/, username);
|
||||
Linking.openURL(hydrated);
|
||||
|
||||
const onError = () => {
|
||||
Alert.alert(
|
||||
intl.formatMessage({
|
||||
id: 'mobile.link.error.title',
|
||||
defaultMessage: 'Error',
|
||||
}),
|
||||
intl.formatMessage({
|
||||
id: 'mobile.link.error.text',
|
||||
defaultMessage: 'Unable to open the link.',
|
||||
}),
|
||||
);
|
||||
};
|
||||
tryOpenURL(hydrated, onError);
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {Alert, Linking} from 'react-native';
|
||||
import {Alert} from 'react-native';
|
||||
|
||||
import {AT_MENTION_REGEX_GLOBAL, CODE_REGEX} from '@constants/autocomplete';
|
||||
import {NOTIFY_ALL_MEMBERS} from '@constants/view';
|
||||
@@ -81,26 +81,6 @@ export function alertSendToGroups(formatMessage, notifyAllMessage, accept, cance
|
||||
);
|
||||
}
|
||||
|
||||
export function tryOpenURL(url) {
|
||||
Linking.canOpenURL(url).then((supported) => {
|
||||
if (supported) {
|
||||
Linking.openURL(url);
|
||||
} else {
|
||||
const {formatMessage} = this.context.intl;
|
||||
Alert.alert(
|
||||
formatMessage({
|
||||
id: 'mobile.server_link.error.title',
|
||||
defaultMessage: 'Link Error',
|
||||
}),
|
||||
formatMessage({
|
||||
id: 'mobile.server_link.error.text',
|
||||
defaultMessage: 'The link could not be found on this server.',
|
||||
}),
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export function errorBadChannel(intl) {
|
||||
const message = {
|
||||
id: t('mobile.server_link.unreachable_channel.error'),
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {Alert, Linking, AlertButton} from 'react-native';
|
||||
import {Alert, AlertButton} from 'react-native';
|
||||
import {ViewTypes} from '@constants';
|
||||
import {tryOpenURL} from '@utils/url';
|
||||
|
||||
interface FormatObjectType {
|
||||
id: string;
|
||||
@@ -36,9 +37,20 @@ function unsupportedServerAdminAlert(formatMessage: FormatMessageType) {
|
||||
style: 'cancel',
|
||||
onPress: () => {
|
||||
const url = 'https://mattermost.com/blog/support-for-esr-5-9-has-ended/';
|
||||
if (Linking.canOpenURL(url)) {
|
||||
Linking.openURL(url);
|
||||
}
|
||||
const onError = () => {
|
||||
Alert.alert(
|
||||
formatMessage({
|
||||
id: 'mobile.link.error.title',
|
||||
defaultMessage: 'Error',
|
||||
}),
|
||||
formatMessage({
|
||||
id: 'mobile.link.error.text',
|
||||
defaultMessage: 'Unable to open the link.',
|
||||
}),
|
||||
);
|
||||
};
|
||||
|
||||
tryOpenURL(url, onError);
|
||||
},
|
||||
};
|
||||
const buttons: AlertButton[] = [cancel, learnMore];
|
||||
|
||||
@@ -1,13 +1,16 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {Linking} from 'react-native';
|
||||
|
||||
import {latinise} from './latinise.js';
|
||||
import {escapeRegex} from './markdown';
|
||||
|
||||
import {Files} from '@mm-redux/constants';
|
||||
import {getCurrentServerUrl} from '@init/credentials';
|
||||
|
||||
import {DeepLinkTypes} from 'app/constants';
|
||||
import {DeepLinkTypes} from '@constants';
|
||||
import {emptyFunction} from '@utils/general';
|
||||
|
||||
const ytRegex = /(?:http|https):\/\/(?:www\.|m\.)?(?:(?:youtube\.com\/(?:(?:v\/)|(?:(?:watch|embed\/watch)(?:\/|.*v=))|(?:embed\/)|(?:user\/[^/]+\/u\/[0-9]\/)))|(?:youtu\.be\/))([^#&?]*)/;
|
||||
|
||||
@@ -180,3 +183,9 @@ export async function getURLAndMatch(href, serverURL, siteURL) {
|
||||
|
||||
return {url, match};
|
||||
}
|
||||
|
||||
export function tryOpenURL(url, onError = emptyFunction, onSuccess = emptyFunction) {
|
||||
Linking.openURL(url).
|
||||
then(onSuccess).
|
||||
catch(onError);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import * as UrlUtils from 'app/utils/url';
|
||||
import {Linking} from 'react-native';
|
||||
|
||||
import * as UrlUtils from '@utils/url';
|
||||
|
||||
/* eslint-disable max-nested-callbacks */
|
||||
|
||||
@@ -131,4 +133,28 @@ describe('UrlUtils', () => {
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
describe('tryOpenUrl', () => {
|
||||
const url = 'https://some.url.com';
|
||||
|
||||
it('should call onSuccess when Linking.openURL succeeds', async () => {
|
||||
Linking.openURL.mockResolvedValueOnce();
|
||||
const onError = jest.fn();
|
||||
const onSuccess = jest.fn();
|
||||
|
||||
await UrlUtils.tryOpenURL(url, onError, onSuccess);
|
||||
expect(onError).not.toHaveBeenCalled();
|
||||
expect(onSuccess).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('should call onError when Linking.openURL fails', async () => {
|
||||
Linking.openURL.mockRejectedValueOnce();
|
||||
const onError = jest.fn();
|
||||
const onSuccess = jest.fn();
|
||||
|
||||
await UrlUtils.tryOpenURL(url, onError, onSuccess);
|
||||
expect(onError).toHaveBeenCalledTimes(1);
|
||||
expect(onSuccess).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -291,12 +291,16 @@
|
||||
"mobile.ios.photos_permission_denied_description": "Upload photos and videos to your Mattermost instance or save them to your device. Open Settings to grant Mattermost Read and Write access to your photo and video library.",
|
||||
"mobile.ios.photos_permission_denied_title": "{applicationName} would like to access your photos",
|
||||
"mobile.join_channel.error": "We couldn't join the channel {displayName}. Please check your connection and try again.",
|
||||
"mobile.link.error.text": "Unable to open the link.",
|
||||
"mobile.link.error.title": "Error",
|
||||
"mobile.loading_channels": "Loading Channels...",
|
||||
"mobile.loading_members": "Loading Members...",
|
||||
"mobile.loading_options": "Loading Options...",
|
||||
"mobile.loading_posts": "Loading messages...",
|
||||
"mobile.login_options.choose_title": "Choose your login method",
|
||||
"mobile.long_post_title": "{channelName} - Post",
|
||||
"mobile.mailTo.error.text": "Unable to open an email client.",
|
||||
"mobile.mailTo.error.title": "Error",
|
||||
"mobile.managed.blocked_by": "Blocked by {vendor}",
|
||||
"mobile.managed.exit": "Exit",
|
||||
"mobile.managed.jailbreak": "Jailbroken devices are not trusted by {vendor}, please exit the app.",
|
||||
|
||||
@@ -129,10 +129,5 @@
|
||||
</array>
|
||||
<key>UIViewControllerBasedStatusBarAppearance</key>
|
||||
<false/>
|
||||
<key>LSApplicationQueriesSchemes</key>
|
||||
<array>
|
||||
<string>https</string>
|
||||
<string>http</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
|
||||
@@ -30,6 +30,7 @@ jest.doMock('react-native', () => {
|
||||
Alert: RNAlert,
|
||||
InteractionManager: RNInteractionManager,
|
||||
NativeModules: RNNativeModules,
|
||||
Linking: RNLinking,
|
||||
} = ReactNative;
|
||||
|
||||
const Alert = {
|
||||
@@ -96,6 +97,11 @@ jest.doMock('react-native', () => {
|
||||
},
|
||||
};
|
||||
|
||||
const Linking = {
|
||||
...RNLinking,
|
||||
openURL: jest.fn(),
|
||||
};
|
||||
|
||||
return Object.setPrototypeOf({
|
||||
Platform: {
|
||||
...Platform,
|
||||
@@ -110,6 +116,7 @@ jest.doMock('react-native', () => {
|
||||
Alert,
|
||||
InteractionManager,
|
||||
NativeModules,
|
||||
Linking,
|
||||
}, ReactNative);
|
||||
});
|
||||
|
||||
@@ -187,7 +194,6 @@ jest.mock('react-native-cookies', () => ({
|
||||
addEventListener: jest.fn(),
|
||||
removeEventListener: jest.fn(),
|
||||
openURL: jest.fn(),
|
||||
canOpenURL: jest.fn(),
|
||||
getInitialURL: jest.fn(),
|
||||
clearAll: jest.fn(),
|
||||
get: () => Promise.resolve(({
|
||||
|
||||
Reference in New Issue
Block a user