Network consolidation (#2324)
* Create network listener component * Remove unnecessary network/websocket logic * Remove offline indicator. Fix linting issue * Fix websocketStatus prop issue * Refactor and remove animation from state * Fix AppState listener. Add connection retry.
This commit is contained in:
parent
ae629a455c
commit
4d5b49f104
4 changed files with 162 additions and 181 deletions
|
|
@ -4,33 +4,37 @@
|
|||
import {bindActionCreators} from 'redux';
|
||||
import {connect} from 'react-redux';
|
||||
|
||||
import {init as initWebSocket} from 'mattermost-redux/actions/websocket';
|
||||
import {startPeriodicStatusUpdates, stopPeriodicStatusUpdates, logout} from 'mattermost-redux/actions/users';
|
||||
import {init as initWebSocket, close as closeWebSocket} from 'mattermost-redux/actions/websocket';
|
||||
|
||||
import {connection} from 'app/actions/device';
|
||||
import {getConnection, isLandscape} from 'app/selectors/device';
|
||||
|
||||
import OfflineIndicator from './offline_indicator';
|
||||
import NetworkIndicator from './network_indicator';
|
||||
|
||||
function mapStateToProps(state) {
|
||||
const {websocket} = state.requests.general;
|
||||
const webSocketStatus = websocket.status;
|
||||
const isConnecting = websocket.error > 1;
|
||||
const websocketStatus = websocket.status;
|
||||
|
||||
return {
|
||||
isConnecting,
|
||||
isLandscape: isLandscape(state),
|
||||
isOnline: getConnection(state),
|
||||
webSocketStatus,
|
||||
websocketErrorCount: websocket.error,
|
||||
websocketStatus,
|
||||
};
|
||||
}
|
||||
|
||||
function mapDispatchToProps(dispatch) {
|
||||
return {
|
||||
actions: bindActionCreators({
|
||||
closeWebSocket,
|
||||
connection,
|
||||
initWebSocket,
|
||||
logout,
|
||||
startPeriodicStatusUpdates,
|
||||
stopPeriodicStatusUpdates,
|
||||
}, dispatch),
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(OfflineIndicator);
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(NetworkIndicator);
|
||||
|
|
@ -1,11 +1,14 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import React, {Component} from 'react';
|
||||
import React, {PureComponent} from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import {intlShape} from 'react-intl';
|
||||
import {
|
||||
ActivityIndicator,
|
||||
Alert,
|
||||
Animated,
|
||||
AppState,
|
||||
Platform,
|
||||
StyleSheet,
|
||||
TouchableOpacity,
|
||||
|
|
@ -16,16 +19,16 @@ import IonIcon from 'react-native-vector-icons/Ionicons';
|
|||
import FormattedText from 'app/components/formatted_text';
|
||||
import {DeviceTypes, ViewTypes} from 'app/constants';
|
||||
import mattermostBucket from 'app/mattermost_bucket';
|
||||
import checkNetwork from 'app/utils/network';
|
||||
import networkConnectionListener, {checkConnection} from 'app/utils/network';
|
||||
import {t} from 'app/utils/i18n';
|
||||
import LocalConfig from 'assets/config';
|
||||
|
||||
import {RequestStatus} from 'mattermost-redux/constants';
|
||||
|
||||
const HEIGHT = 38;
|
||||
const OFFLINE = 'offline';
|
||||
const CONNECTING = 'connecting';
|
||||
const CONNECTED = 'connected';
|
||||
const MAX_WEBSOCKET_RETRIES = 3;
|
||||
const CONNECTION_RETRY_SECONDS = 30;
|
||||
const CONNECTION_RETRY_TIMEOUT = 1000 * CONNECTION_RETRY_SECONDS; // 30 seconds
|
||||
const {
|
||||
ANDROID_TOP_LANDSCAPE,
|
||||
ANDROID_TOP_PORTRAIT,
|
||||
|
|
@ -35,85 +38,96 @@ const {
|
|||
STATUS_BAR_HEIGHT,
|
||||
} = ViewTypes;
|
||||
|
||||
export default class OfflineIndicator extends Component {
|
||||
export default class NetworkIndicator extends PureComponent {
|
||||
static propTypes = {
|
||||
actions: PropTypes.shape({
|
||||
closeWebSocket: PropTypes.func.isRequired,
|
||||
connection: PropTypes.func.isRequired,
|
||||
initWebSocket: PropTypes.func.isRequired,
|
||||
logout: PropTypes.func.isRequired,
|
||||
startPeriodicStatusUpdates: PropTypes.func.isRequired,
|
||||
stopPeriodicStatusUpdates: PropTypes.func.isRequired,
|
||||
}).isRequired,
|
||||
isConnecting: PropTypes.bool,
|
||||
isLandscape: PropTypes.bool,
|
||||
isOnline: PropTypes.bool,
|
||||
webSocketStatus: PropTypes.string,
|
||||
websocketErrorCount: PropTypes.number,
|
||||
websocketStatus: PropTypes.string,
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
isOnline: true,
|
||||
};
|
||||
|
||||
static contextTypes = {
|
||||
intl: intlShape.isRequired,
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
const navBar = this.getNavBarHeight(props.isLandscape);
|
||||
|
||||
this.state = {
|
||||
network: null,
|
||||
navBar,
|
||||
top: new Animated.Value(navBar - HEIGHT),
|
||||
};
|
||||
this.top = new Animated.Value(navBar - HEIGHT);
|
||||
|
||||
this.backgroundColor = new Animated.Value(0);
|
||||
|
||||
this.networkListener = networkConnectionListener(this.handleConnectionChange);
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.mounted = true;
|
||||
|
||||
AppState.addEventListener('change', this.handleAppStateChange);
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
const {isLandscape, webSocketStatus} = this.props;
|
||||
componentDidUpdate(prevProps) {
|
||||
const {websocketStatus: previousWebsocketStatus} = prevProps;
|
||||
const {websocketErrorCount, websocketStatus} = this.props;
|
||||
|
||||
if (nextProps.isLandscape !== isLandscape && this.state.network) {
|
||||
const navBar = this.getNavBarHeight(nextProps.isLandscape);
|
||||
const top = new Animated.Value(navBar - HEIGHT);
|
||||
this.setLocalState({navBar, top});
|
||||
}
|
||||
|
||||
if (nextProps.isOnline) {
|
||||
if (this.state.network && webSocketStatus === RequestStatus.STARTED && nextProps.webSocketStatus === RequestStatus.SUCCESS) {
|
||||
if (this.props.isOnline) {
|
||||
if (previousWebsocketStatus === RequestStatus.STARTED && websocketStatus === RequestStatus.SUCCESS) {
|
||||
// Show the connected animation only if we had a previous network status
|
||||
this.connected();
|
||||
} else if (webSocketStatus === RequestStatus.STARTED && nextProps.webSocketStatus === RequestStatus.FAILURE && nextProps.isConnecting) {
|
||||
// Show the connecting bar if it failed to connect at least twice
|
||||
this.connecting();
|
||||
clearTimeout(this.connectionRetryTimeout);
|
||||
} else if (previousWebsocketStatus === RequestStatus.STARTED && websocketStatus === RequestStatus.FAILURE && websocketErrorCount > MAX_WEBSOCKET_RETRIES) {
|
||||
this.handleWebSocket(false);
|
||||
this.handleReconnect();
|
||||
} else if (websocketStatus === RequestStatus.FAILURE && websocketErrorCount > 1) {
|
||||
this.show();
|
||||
}
|
||||
} else {
|
||||
} else if (prevProps.isOnline && !this.props.isOnline) {
|
||||
this.offline();
|
||||
}
|
||||
}
|
||||
|
||||
shouldComponentUpdate(nextProps, nextState) {
|
||||
return (nextState.network !== this.state.network || nextProps.isLandscape !== this.props.isLandscape);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.mounted = false;
|
||||
|
||||
const {closeWebSocket, stopPeriodicStatusUpdates} = this.props.actions;
|
||||
|
||||
this.networkListener.removeEventListener();
|
||||
|
||||
AppState.removeEventListener('change', this.handleAppStateChange);
|
||||
|
||||
closeWebSocket();
|
||||
stopPeriodicStatusUpdates();
|
||||
|
||||
clearTimeout(this.connectionRetryTimeout);
|
||||
}
|
||||
|
||||
connect = () => {
|
||||
checkNetwork((result) => {
|
||||
this.setLocalState({network: CONNECTING}, () => {
|
||||
if (result) {
|
||||
this.props.actions.connection(true);
|
||||
this.initializeWebSocket();
|
||||
} else {
|
||||
this.setLocalState({network: OFFLINE});
|
||||
}
|
||||
});
|
||||
});
|
||||
connect = async () => {
|
||||
clearTimeout(this.connectionRetryTimeout);
|
||||
|
||||
const result = await checkConnection(this.props.isOnline);
|
||||
|
||||
if (result) {
|
||||
this.props.actions.connection(true);
|
||||
this.initializeWebSocket();
|
||||
} else {
|
||||
this.handleWebSocket(false);
|
||||
}
|
||||
};
|
||||
|
||||
connected = () => {
|
||||
this.setState({network: CONNECTED});
|
||||
Animated.sequence([
|
||||
Animated.timing(
|
||||
this.backgroundColor, {
|
||||
|
|
@ -122,28 +136,18 @@ export default class OfflineIndicator extends Component {
|
|||
}
|
||||
),
|
||||
Animated.timing(
|
||||
this.state.top, {
|
||||
toValue: (this.state.navBar - HEIGHT),
|
||||
this.top, {
|
||||
toValue: (this.getNavBarHeight() - HEIGHT),
|
||||
duration: 300,
|
||||
delay: 500,
|
||||
}
|
||||
),
|
||||
]).start(() => {
|
||||
this.backgroundColor.setValue(0);
|
||||
this.setLocalState({network: null});
|
||||
});
|
||||
};
|
||||
|
||||
connecting = () => {
|
||||
const prevState = this.state.network;
|
||||
this.setLocalState({network: CONNECTING}, () => {
|
||||
if (prevState !== OFFLINE) {
|
||||
this.show();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
getNavBarHeight = (isLandscape) => {
|
||||
getNavBarHeight = (isLandscape = this.props.isLandscape) => {
|
||||
if (Platform.OS === 'android') {
|
||||
if (isLandscape) {
|
||||
return ANDROID_TOP_LANDSCAPE;
|
||||
|
|
@ -152,9 +156,11 @@ export default class OfflineIndicator extends Component {
|
|||
return ANDROID_TOP_PORTRAIT;
|
||||
}
|
||||
|
||||
if (DeviceTypes.IS_IPHONE_X && isLandscape) {
|
||||
const isX = DeviceTypes.IS_IPHONE_X;
|
||||
|
||||
if (isX && isLandscape) {
|
||||
return IOS_TOP_LANDSCAPE;
|
||||
} else if (DeviceTypes.IS_IPHONE_X) {
|
||||
} else if (isX) {
|
||||
return IOSX_TOP_PORTRAIT;
|
||||
} else if (isLandscape) {
|
||||
return IOS_TOP_LANDSCAPE + STATUS_BAR_HEIGHT;
|
||||
|
|
@ -163,46 +169,94 @@ export default class OfflineIndicator extends Component {
|
|||
return IOS_TOP_PORTRAIT;
|
||||
};
|
||||
|
||||
initializeWebSocket = async () => {
|
||||
handleWebSocket = (open) => {
|
||||
const {actions} = this.props;
|
||||
const {initWebSocket} = actions;
|
||||
const {
|
||||
closeWebSocket,
|
||||
startPeriodicStatusUpdates,
|
||||
stopPeriodicStatusUpdates,
|
||||
} = actions;
|
||||
|
||||
if (open) {
|
||||
this.initializeWebSocket();
|
||||
startPeriodicStatusUpdates();
|
||||
} else {
|
||||
closeWebSocket(true);
|
||||
stopPeriodicStatusUpdates();
|
||||
}
|
||||
};
|
||||
|
||||
handleAppStateChange = async (appState) => {
|
||||
this.handleWebSocket(appState === 'active');
|
||||
};
|
||||
|
||||
handleConnectionChange = (isConnected) => {
|
||||
const {connection} = this.props.actions;
|
||||
|
||||
// Prevent for being called more than once.
|
||||
if (this.isConnected !== isConnected) {
|
||||
this.isConnected = isConnected;
|
||||
this.handleWebSocket(isConnected);
|
||||
connection(isConnected);
|
||||
}
|
||||
};
|
||||
|
||||
handleReconnect = () => {
|
||||
clearTimeout(this.connectionRetryTimeout);
|
||||
this.connectionRetryTimeout = setTimeout(() => {
|
||||
const {websocketStatus} = this.props;
|
||||
if (websocketStatus !== RequestStatus.STARTED || websocketStatus !== RequestStatus.SUCCESS) {
|
||||
this.connect();
|
||||
}
|
||||
}, CONNECTION_RETRY_TIMEOUT);
|
||||
}
|
||||
|
||||
initializeWebSocket = async () => {
|
||||
const {formatMessage} = this.context.intl;
|
||||
const {actions} = this.props;
|
||||
const {closeWebSocket, initWebSocket} = actions;
|
||||
const platform = Platform.OS;
|
||||
let certificate = null;
|
||||
if (platform === 'ios') {
|
||||
certificate = await mattermostBucket.getPreference('cert', LocalConfig.AppGroupId);
|
||||
}
|
||||
|
||||
initWebSocket(platform, null, null, null, {certificate});
|
||||
};
|
||||
|
||||
offline = () => {
|
||||
this.setLocalState({network: OFFLINE}, () => {
|
||||
this.show();
|
||||
initWebSocket(platform, null, null, null, {certificate}).catch(() => {
|
||||
// we should dispatch a failure and show the app as disconnected
|
||||
Alert.alert(
|
||||
formatMessage({id: 'mobile.authentication_error.title', defaultMessage: 'Authentication Error'}),
|
||||
formatMessage({
|
||||
id: 'mobile.authentication_error.message',
|
||||
defaultMessage: 'Mattermost has encountered an error. Please re-authenticate to start a new session.',
|
||||
}),
|
||||
[{
|
||||
text: formatMessage({
|
||||
id: 'navbar_dropdown.logout',
|
||||
defaultMessage: 'Logout',
|
||||
}),
|
||||
onPress: actions.logout,
|
||||
}],
|
||||
{cancelable: false}
|
||||
);
|
||||
closeWebSocket(true);
|
||||
});
|
||||
};
|
||||
|
||||
setLocalState = (state, callback) => {
|
||||
if (!this.mounted) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.setState(state, callback);
|
||||
offline = () => {
|
||||
this.show();
|
||||
};
|
||||
|
||||
show = () => {
|
||||
Animated.timing(
|
||||
this.state.top, {
|
||||
toValue: this.state.navBar,
|
||||
this.top, {
|
||||
toValue: this.getNavBarHeight(),
|
||||
duration: 300,
|
||||
}
|
||||
).start();
|
||||
};
|
||||
|
||||
render() {
|
||||
if (!this.state.network) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const {websocketErrorCount, websocketStatus} = this.props;
|
||||
const background = this.backgroundColor.interpolate({
|
||||
inputRange: [0, 1],
|
||||
outputRange: ['#939393', '#629a41'],
|
||||
|
|
@ -210,11 +264,17 @@ export default class OfflineIndicator extends Component {
|
|||
|
||||
let i18nId;
|
||||
let defaultMessage;
|
||||
let values;
|
||||
let action;
|
||||
switch (this.state.network) {
|
||||
case OFFLINE:
|
||||
|
||||
const currentWebsocketStatus = (websocketStatus === RequestStatus.FAILURE && websocketErrorCount <= MAX_WEBSOCKET_RETRIES) ? RequestStatus.STARTED : websocketStatus;
|
||||
|
||||
switch (currentWebsocketStatus) {
|
||||
case (RequestStatus.NOT_STARTED):
|
||||
case (RequestStatus.FAILURE):
|
||||
i18nId = t('mobile.offlineIndicator.offline');
|
||||
defaultMessage = 'Cannot connect to the server';
|
||||
defaultMessage = 'Cannot connect to the server. Retrying in {seconds} seconds';
|
||||
values = {seconds: CONNECTION_RETRY_SECONDS};
|
||||
action = (
|
||||
<TouchableOpacity
|
||||
onPress={this.connect}
|
||||
|
|
@ -228,7 +288,7 @@ export default class OfflineIndicator extends Component {
|
|||
</TouchableOpacity>
|
||||
);
|
||||
break;
|
||||
case CONNECTING:
|
||||
case RequestStatus.STARTED:
|
||||
i18nId = t('mobile.offlineIndicator.connecting');
|
||||
defaultMessage = 'Connecting...';
|
||||
action = (
|
||||
|
|
@ -240,7 +300,7 @@ export default class OfflineIndicator extends Component {
|
|||
</View>
|
||||
);
|
||||
break;
|
||||
case CONNECTED:
|
||||
case RequestStatus.SUCCESS:
|
||||
default:
|
||||
i18nId = t('mobile.offlineIndicator.connected');
|
||||
defaultMessage = 'Connected';
|
||||
|
|
@ -257,11 +317,12 @@ export default class OfflineIndicator extends Component {
|
|||
}
|
||||
|
||||
return (
|
||||
<Animated.View style={[styles.container, {top: this.state.top, backgroundColor: background}]}>
|
||||
<Animated.View style={[styles.container, {top: this.top, backgroundColor: background}]}>
|
||||
<Animated.View style={styles.wrapper}>
|
||||
<FormattedText
|
||||
defaultMessage={defaultMessage}
|
||||
id={i18nId}
|
||||
values={values}
|
||||
style={styles.message}
|
||||
/>
|
||||
{action}
|
||||
|
|
@ -288,7 +349,7 @@ const styles = StyleSheet.create({
|
|||
},
|
||||
message: {
|
||||
color: '#FFFFFF',
|
||||
fontSize: 14,
|
||||
fontSize: 12,
|
||||
fontWeight: '600',
|
||||
flex: 1,
|
||||
},
|
||||
|
|
@ -296,6 +357,7 @@ const styles = StyleSheet.create({
|
|||
alignItems: 'center',
|
||||
borderWidth: 1,
|
||||
borderColor: '#FFFFFF',
|
||||
paddingRight: 0,
|
||||
},
|
||||
actionContainer: {
|
||||
alignItems: 'flex-end',
|
||||
|
|
@ -5,8 +5,6 @@ import React, {PureComponent} from 'react';
|
|||
import PropTypes from 'prop-types';
|
||||
import {intlShape} from 'react-intl';
|
||||
import {
|
||||
Alert,
|
||||
AppState,
|
||||
Dimensions,
|
||||
Platform,
|
||||
StyleSheet,
|
||||
|
|
@ -21,14 +19,12 @@ import ChannelLoader from 'app/components/channel_loader';
|
|||
import MainSidebar from 'app/components/sidebars/main';
|
||||
import SettingsSidebar from 'app/components/sidebars/settings';
|
||||
import KeyboardLayout from 'app/components/layout/keyboard_layout';
|
||||
import OfflineIndicator from 'app/components/offline_indicator';
|
||||
import NetworkIndicator from 'app/components/network_indicator';
|
||||
import SafeAreaView from 'app/components/safe_area_view';
|
||||
import StatusBar from 'app/components/status_bar';
|
||||
import {DeviceTypes, ViewTypes} from 'app/constants';
|
||||
import mattermostBucket from 'app/mattermost_bucket';
|
||||
import {preventDoubleTap} from 'app/utils/tap';
|
||||
import PostTextbox from 'app/components/post_textbox';
|
||||
import networkConnectionListener from 'app/utils/network';
|
||||
import tracker from 'app/utils/time_tracker';
|
||||
import LocalConfig from 'assets/config';
|
||||
|
||||
|
|
@ -48,17 +44,11 @@ let ClientUpgradeListener;
|
|||
export default class Channel extends PureComponent {
|
||||
static propTypes = {
|
||||
actions: PropTypes.shape({
|
||||
connection: PropTypes.func.isRequired,
|
||||
loadChannelsIfNecessary: PropTypes.func.isRequired,
|
||||
loadProfilesAndTeamMembersForDMSidebar: PropTypes.func.isRequired,
|
||||
logout: PropTypes.func.isRequired,
|
||||
selectDefaultTeam: PropTypes.func.isRequired,
|
||||
selectInitialChannel: PropTypes.func.isRequired,
|
||||
initWebSocket: PropTypes.func.isRequired,
|
||||
closeWebSocket: PropTypes.func.isRequired,
|
||||
recordLoadTime: PropTypes.func.isRequired,
|
||||
startPeriodicStatusUpdates: PropTypes.func.isRequired,
|
||||
stopPeriodicStatusUpdates: PropTypes.func.isRequired,
|
||||
}).isRequired,
|
||||
currentChannelId: PropTypes.string,
|
||||
channelsRequestFailed: PropTypes.bool,
|
||||
|
|
@ -89,8 +79,6 @@ export default class Channel extends PureComponent {
|
|||
componentWillMount() {
|
||||
EventEmitter.on('leave_team', this.handleLeaveTeam);
|
||||
|
||||
this.networkListener = networkConnectionListener(this.handleConnectionChange);
|
||||
|
||||
if (this.props.currentTeamId) {
|
||||
this.loadChannels(this.props.currentTeamId);
|
||||
} else {
|
||||
|
|
@ -99,8 +87,6 @@ export default class Channel extends PureComponent {
|
|||
}
|
||||
|
||||
componentDidMount() {
|
||||
AppState.addEventListener('change', this.handleAppStateChange);
|
||||
|
||||
if (tracker.initialLoad) {
|
||||
this.props.actions.recordLoadTime('Start time', 'initialLoad');
|
||||
}
|
||||
|
|
@ -140,15 +126,7 @@ export default class Channel extends PureComponent {
|
|||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
const {closeWebSocket, stopPeriodicStatusUpdates} = this.props.actions;
|
||||
|
||||
EventEmitter.off('leave_team', this.handleLeaveTeam);
|
||||
this.networkListener.removeEventListener();
|
||||
|
||||
AppState.removeEventListener('change', this.handleAppStateChange);
|
||||
|
||||
closeWebSocket();
|
||||
stopPeriodicStatusUpdates();
|
||||
}
|
||||
|
||||
attachPostTextBox = (ref) => {
|
||||
|
|
@ -245,73 +223,10 @@ export default class Channel extends PureComponent {
|
|||
}
|
||||
});
|
||||
|
||||
handleWebSocket = (open) => {
|
||||
const {actions} = this.props;
|
||||
const {
|
||||
closeWebSocket,
|
||||
startPeriodicStatusUpdates,
|
||||
stopPeriodicStatusUpdates,
|
||||
} = actions;
|
||||
|
||||
if (open) {
|
||||
this.initializeWebSocket();
|
||||
startPeriodicStatusUpdates();
|
||||
} else {
|
||||
closeWebSocket(true);
|
||||
stopPeriodicStatusUpdates();
|
||||
}
|
||||
};
|
||||
|
||||
handleAppStateChange = async (appState) => {
|
||||
this.handleWebSocket(appState === 'active');
|
||||
};
|
||||
|
||||
handleConnectionChange = (isConnected) => {
|
||||
const {connection} = this.props.actions;
|
||||
|
||||
// Prevent for being called more than once.
|
||||
if (this.isConnected !== isConnected) {
|
||||
this.isConnected = isConnected;
|
||||
this.handleWebSocket(isConnected);
|
||||
connection(isConnected);
|
||||
}
|
||||
};
|
||||
|
||||
handleLeaveTeam = () => {
|
||||
this.props.actions.selectDefaultTeam();
|
||||
};
|
||||
|
||||
initializeWebSocket = async () => {
|
||||
const {formatMessage} = this.context.intl;
|
||||
const {actions} = this.props;
|
||||
const {initWebSocket} = actions;
|
||||
const platform = Platform.OS;
|
||||
let certificate = null;
|
||||
if (platform === 'ios') {
|
||||
certificate = await mattermostBucket.getPreference('cert', LocalConfig.AppGroupId);
|
||||
}
|
||||
|
||||
initWebSocket(platform, null, null, null, {certificate}).catch(() => {
|
||||
// we should dispatch a failure and show the app as disconnected
|
||||
Alert.alert(
|
||||
formatMessage({id: 'mobile.authentication_error.title', defaultMessage: 'Authentication Error'}),
|
||||
formatMessage({
|
||||
id: 'mobile.authentication_error.message',
|
||||
defaultMessage: 'Mattermost has encountered an error. Please re-authenticate to start a new session.',
|
||||
}),
|
||||
[{
|
||||
text: formatMessage({
|
||||
id: 'navbar_dropdown.logout',
|
||||
defaultMessage: 'Logout',
|
||||
}),
|
||||
onPress: actions.logout,
|
||||
}],
|
||||
{cancelable: false}
|
||||
);
|
||||
this.props.actions.closeWebSocket(true);
|
||||
});
|
||||
};
|
||||
|
||||
loadChannels = (teamId) => {
|
||||
const {
|
||||
loadChannelsIfNecessary,
|
||||
|
|
@ -393,7 +308,7 @@ export default class Channel extends PureComponent {
|
|||
>
|
||||
<SafeAreaView navigator={navigator}>
|
||||
<StatusBar/>
|
||||
<OfflineIndicator/>
|
||||
<NetworkIndicator/>
|
||||
<ChannelNavBar
|
||||
navigator={navigator}
|
||||
openChannelDrawer={this.openChannelSidebar}
|
||||
|
|
|
|||
|
|
@ -325,7 +325,7 @@
|
|||
"mobile.notification.in": " in ",
|
||||
"mobile.offlineIndicator.connected": "Connected",
|
||||
"mobile.offlineIndicator.connecting": "Connecting...",
|
||||
"mobile.offlineIndicator.offline": "Cannot connect to the server",
|
||||
"mobile.offlineIndicator.offline": "Cannot connect to the server. Retrying in {seconds} seconds",
|
||||
"mobile.open_dm.error": "We couldn't open a direct message with {displayName}. Please check your connection and try again.",
|
||||
"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.",
|
||||
|
|
|
|||
Loading…
Reference in a new issue