// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved. // See License.txt for license information. import React, {Component} from 'react'; import PropTypes from 'prop-types'; import { ActivityIndicator, Animated, Platform, StyleSheet, View } from 'react-native'; import IonIcon from 'react-native-vector-icons/Ionicons'; import FormattedText from 'app/components/formatted_text'; import {RequestStatus} from 'mattermost-redux/constants'; const HEIGHT = 38; const NAVBAR = Platform.OS === 'ios' ? 64 : 46; const INITIAL_TOP = NAVBAR - HEIGHT; const OFFLINE = 'offline'; const CONNECTING = 'connecting'; const CONNECTED = 'connected'; export default class OfflineIndicator extends Component { static propTypes = { isConnecting: PropTypes.bool, isOnline: PropTypes.bool, webSocketStatus: PropTypes.string }; static defaultProps: { isOnline: true }; constructor(props) { super(props); this.state = { network: null, top: new Animated.Value(INITIAL_TOP) }; this.backgroundColor = new Animated.Value(0); } componentWillReceiveProps(nextProps) { const {webSocketStatus} = this.props; if (nextProps.isOnline) { if (this.state.network && webSocketStatus === RequestStatus.STARTED && nextProps.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(); } } else { this.offline(); } } shouldComponentUpdate(nextProps, nextState) { return nextState.network !== this.state.network && nextState.network; } offline = () => { this.setState({network: OFFLINE}, () => { this.show(); }); }; connecting = () => { const prevState = this.state.network; this.setState({network: CONNECTING}, () => { if (prevState !== OFFLINE) { this.show(); } }); }; connected = () => { this.setState({network: CONNECTED}); Animated.sequence([ Animated.timing( this.backgroundColor, { toValue: 1, duration: 100 } ), Animated.timing( this.state.top, { toValue: INITIAL_TOP, duration: 300, delay: 500 } ) ]).start(() => { this.backgroundColor.setValue(0); this.setState({network: null}); }); }; show = () => { Animated.timing( this.state.top, { toValue: NAVBAR, duration: 300 } ).start(); }; render() { if (!this.state.network) { return null; } const background = this.backgroundColor.interpolate({ inputRange: [0, 1], outputRange: ['#939393', '#629a41'] }); let i18nId; let defaultMessage; let action; switch (this.state.network) { case OFFLINE: i18nId = 'mobile.offlineIndicator.offline'; defaultMessage = 'No internet connection'; break; case CONNECTING: i18nId = 'mobile.offlineIndicator.connecting'; defaultMessage = 'Connecting...'; action = ( ); break; case CONNECTED: i18nId = 'mobile.offlineIndicator.connected'; defaultMessage = 'Connected'; action = ( ); break; } return ( {action} ); } } const styles = StyleSheet.create({ container: { height: HEIGHT, width: '100%', zIndex: 9, position: 'absolute' }, wrapper: { alignItems: 'center', flex: 1, height: HEIGHT, flexDirection: 'row', paddingLeft: 12, paddingRight: 5 }, message: { color: '#FFFFFF', fontSize: 14, fontWeight: '600', flex: 1 }, actionButton: { alignItems: 'center', borderWidth: 1, borderColor: '#FFFFFF' }, actionContainer: { alignItems: 'flex-end', height: 24, justifyContent: 'center', paddingRight: 10, width: 60 } });