diff --git a/app/containers/ConnectionBadge.js b/app/containers/ConnectionBadge.js deleted file mode 100644 index 4d935c885e2855e4cd412e9812326cc2ff312841..0000000000000000000000000000000000000000 --- a/app/containers/ConnectionBadge.js +++ /dev/null @@ -1,140 +0,0 @@ -import React, { Component } from 'react'; -import { - Text, StyleSheet, ActivityIndicator, Animated, Easing -} from 'react-native'; -import { connect } from 'react-redux'; -import PropTypes from 'prop-types'; - -import I18n from '../i18n'; -import debounce from '../utils/debounce'; -import sharedStyles from '../views/Styles'; -import { - COLOR_BACKGROUND_CONTAINER, COLOR_DANGER, COLOR_SUCCESS, COLOR_WHITE, COLOR_TEXT_DESCRIPTION -} from '../constants/colors'; - -const styles = StyleSheet.create({ - container: { - width: '100%', - position: 'absolute', - top: 0, - height: 41, - backgroundColor: COLOR_BACKGROUND_CONTAINER, - flexDirection: 'row', - alignItems: 'center', - justifyContent: 'center', - elevation: 4 - }, - text: { - color: COLOR_WHITE, - fontSize: 15, - ...sharedStyles.textRegular - }, - textConnecting: { - ...sharedStyles.textColorDescription - }, - containerConnected: { - backgroundColor: COLOR_SUCCESS - }, - containerOffline: { - backgroundColor: COLOR_DANGER - }, - activityIndicator: { - marginRight: 15 - } -}); - -const ANIMATION_DURATION = 300; - -@connect(state => ({ - connecting: state.meteor.connecting, - connected: state.meteor.connected, - disconnected: !state.meteor.connecting && !state.meteor.connected -})) -class ConnectionBadge extends Component { - static propTypes = { - connecting: PropTypes.bool, - connected: PropTypes.bool, - disconnected: PropTypes.bool - } - - constructor(props) { - super(props); - this.animatedValue = new Animated.Value(0); - if (props.connecting) { - this.show(); - } - } - - componentDidUpdate() { - const { connected, disconnected } = this.props; - this.show(connected || disconnected); - } - - componentWillUnmount() { - if (this.timeout) { - clearTimeout(this.timeout); - } - } - - // eslint-disable-next-line react/sort-comp - animate = debounce((toValue, autoHide) => { - Animated.timing( - this.animatedValue, - { - toValue, - duration: ANIMATION_DURATION, - easing: Easing.ease, - useNativeDriver: true - }, - ).start(() => { - if (toValue === 1 && autoHide) { - if (this.timeout) { - clearTimeout(this.timeout); - } - this.timeout = setTimeout(() => { - this.hide(); - }, 1000); - } - }); - }, 300); - - show = (autoHide) => { - this.animate(1, autoHide); - } - - hide = () => { - this.animate(0); - } - - render() { - const { connecting, connected } = this.props; - - const translateY = this.animatedValue.interpolate({ - inputRange: [0, 1], - outputRange: [-42, 0] - }); - - if (connecting) { - return ( - <Animated.View style={[styles.container, { transform: [{ translateY }] }]}> - <ActivityIndicator color={COLOR_TEXT_DESCRIPTION} style={styles.activityIndicator} /> - <Text style={[styles.text, styles.textConnecting]}>{I18n.t('Connecting')}</Text> - </Animated.View> - ); - } else if (connected) { - return ( - <Animated.View style={[styles.container, styles.containerConnected, { transform: [{ translateY }] }]}> - <Text style={styles.text}>{I18n.t('Connected')}</Text> - </Animated.View> - ); - } - - return ( - <Animated.View style={[styles.container, styles.containerOffline, { transform: [{ translateY }] }]}> - <Text style={styles.text}>{I18n.t('Offline')}</Text> - </Animated.View> - ); - } -} - -export default ConnectionBadge; diff --git a/app/views/RoomView/Header/Header.js b/app/views/RoomView/Header/Header.js index 2a6b9b5a0a444948a60b7b17b0b274f19808585c..31a2725c4f5daece3d272897f4759a604a9d8fc4 100644 --- a/app/views/RoomView/Header/Header.js +++ b/app/views/RoomView/Header/Header.js @@ -65,8 +65,34 @@ Typing.propTypes = { usersTyping: PropTypes.array }; +const HeaderTitle = React.memo(({ + title, scale, connecting, isFetching +}) => { + if (connecting) { + title = I18n.t('Connecting'); + } + if (isFetching) { + title = I18n.t('Updating'); + } + return ( + <Text + style={[styles.title, { fontSize: TITLE_SIZE * scale }]} + numberOfLines={1} + testID={`room-view-title-${ title }`} + >{title} + </Text> + ); +}); + +HeaderTitle.propTypes = { + title: PropTypes.string, + scale: PropTypes.number, + connecting: PropTypes.bool, + isFetching: PropTypes.bool +}; + const Header = React.memo(({ - title, type, status, usersTyping, width, height, prid, tmid, widthOffset + title, type, status, usersTyping, width, height, prid, tmid, widthOffset, connecting, isFetching }) => { const portrait = height > width; let scale = 1; @@ -93,7 +119,15 @@ const Header = React.memo(({ contentContainerStyle={styles.scroll} > <Icon type={prid ? 'discussion' : type} status={status} /> - <Text style={[styles.title, { fontSize: TITLE_SIZE * scale }]} numberOfLines={1} testID={`room-view-title-${ title }`}>{title}</Text> + <HeaderTitle + prid={prid} + type={type} + status={status} + title={title} + scale={scale} + connecting={connecting} + isFetching={isFetching} + /> </ScrollView> </View> {type === 'thread' ? null : <Typing usersTyping={usersTyping} />} @@ -110,7 +144,9 @@ Header.propTypes = { tmid: PropTypes.string, status: PropTypes.string, usersTyping: PropTypes.array, - widthOffset: PropTypes.number + widthOffset: PropTypes.number, + connecting: PropTypes.bool, + isFetching: PropTypes.bool }; Header.defaultProps = { diff --git a/app/views/RoomView/Header/index.js b/app/views/RoomView/Header/index.js index 54d0d4cde83b5a08f784b3d2c5acd1cfcd91afea..b3b354bdc0deb7261086197719a821b01d5a0876 100644 --- a/app/views/RoomView/Header/index.js +++ b/app/views/RoomView/Header/index.js @@ -26,6 +26,7 @@ import RightButtons from './RightButtons'; } return { + connecting: state.meteor.connecting, userId, isLoggedUser, status @@ -40,6 +41,8 @@ export default class RoomHeaderView extends Component { rid: PropTypes.string, window: PropTypes.object, status: PropTypes.string, + connecting: PropTypes.bool, + isFetching: PropTypes.bool, widthOffset: PropTypes.number, isLoggedUser: PropTypes.bool, userId: PropTypes.string @@ -63,7 +66,7 @@ export default class RoomHeaderView extends Component { shouldComponentUpdate(nextProps, nextState) { const { usersTyping, user } = this.state; const { - type, title, status, window + type, title, status, window, connecting, isFetching } = this.props; if (nextProps.type !== type) { return true; @@ -74,6 +77,12 @@ export default class RoomHeaderView extends Component { if (nextProps.status !== status) { return true; } + if (nextProps.connecting !== connecting) { + return true; + } + if (nextProps.isFetching !== isFetching) { + return true; + } if (nextProps.window.width !== window.width) { return true; } @@ -102,7 +111,7 @@ export default class RoomHeaderView extends Component { render() { const { usersTyping, user } = this.state; const { - window, title, type, prid, tmid, widthOffset, isLoggedUser, status: userStatus + window, title, type, prid, tmid, widthOffset, isLoggedUser, status: userStatus, connecting, isFetching } = this.props; let status = 'offline'; @@ -125,6 +134,8 @@ export default class RoomHeaderView extends Component { height={window.height} usersTyping={usersTyping} widthOffset={widthOffset} + connecting={connecting} + isFetching={isFetching} /> ); } diff --git a/app/views/RoomView/index.js b/app/views/RoomView/index.js index 4354ca1fdc623cc7dbbf9b558ffb920d34f47d6e..94e3ffce7202a3a3b9d2a374eef3dc2017350b94 100644 --- a/app/views/RoomView/index.js +++ b/app/views/RoomView/index.js @@ -31,7 +31,6 @@ import log from '../../utils/log'; import { isIOS } from '../../utils/deviceInfo'; import EventEmitter from '../../utils/events'; import I18n from '../../i18n'; -import ConnectionBadge from '../../containers/ConnectionBadge'; import RoomHeaderView, { RightButtons } from './Header'; import StatusBar from '../../containers/StatusBar'; import Separator from './Separator'; @@ -67,10 +66,19 @@ export default class RoomView extends LoggedView { const title = navigation.getParam('name'); const t = navigation.getParam('t'); const tmid = navigation.getParam('tmid'); + const isFetching = navigation.getParam('isFetching', false); return { headerTitleContainerStyle: styles.headerTitleContainerStyle, headerTitle: ( - <RoomHeaderView rid={rid} prid={prid} tmid={tmid} title={title} type={t} widthOffset={tmid ? 95 : 130} /> + <RoomHeaderView + rid={rid} + prid={prid} + tmid={tmid} + title={title} + type={t} + widthOffset={tmid ? 95 : 130} + isFetching={isFetching} + /> ), headerRight: <RightButtons rid={rid} tmid={tmid} t={t} navigation={navigation} /> }; @@ -312,14 +320,18 @@ export default class RoomView extends LoggedView { return ((room.prid || useRealName) && room.fname) || room.name; } - getMessages = () => { + getMessages = async() => { const { room } = this.state; + const { navigation } = this.props; try { + navigation.setParams({ isFetching: true }); if (room.lastOpen) { - return RocketChat.loadMissedMessages(room); + await RocketChat.loadMissedMessages(room); } else { - return RocketChat.loadMessagesForRoom(room); + await RocketChat.loadMessagesForRoom(room); } + navigation.setParams({ isFetching: false }); + return Promise.resolve(); } catch (e) { console.log('TCL: getMessages -> e', e); log('getMessages', e); @@ -519,7 +531,6 @@ export default class RoomView extends LoggedView { {this.renderActions()} <ReactionPicker onEmojiSelected={this.onReactionPress} /> <UploadProgress rid={this.rid} /> - <ConnectionBadge /> </SafeAreaView> ); } diff --git a/app/views/RoomsListView/Header/Header.android.js b/app/views/RoomsListView/Header/Header.android.js index 136563ea5cd3a4141d0ac0fb28135dd239e6260f..a2393caf0c86cf9649b55b02c542e26f5239b81f 100644 --- a/app/views/RoomsListView/Header/Header.android.js +++ b/app/views/RoomsListView/Header/Header.android.js @@ -42,8 +42,8 @@ const styles = StyleSheet.create({ } }); -const Header = ({ - isFetching, serverName, showServerDropdown, setSearchInputRef, showSearchHeader, onSearchChangeText, onPress +const Header = React.memo(({ + connecting, isFetching, serverName, showServerDropdown, setSearchInputRef, showSearchHeader, onSearchChangeText, onPress }) => { if (showSearchHeader) { return ( @@ -61,6 +61,7 @@ const Header = ({ return ( <View style={styles.container}> <TouchableOpacity onPress={onPress} testID='rooms-list-header-server-dropdown-button'> + {connecting ? <Text style={styles.updating}>{I18n.t('Connecting')}</Text> : null} {isFetching ? <Text style={styles.updating}>{I18n.t('Updating')}</Text> : null} <View style={styles.button}> <Text style={[styles.server, isFetching && styles.serverSmall]}>{serverName}</Text> @@ -69,7 +70,7 @@ const Header = ({ </TouchableOpacity> </View> ); -}; +}); Header.propTypes = { showServerDropdown: PropTypes.bool.isRequired, @@ -77,6 +78,7 @@ Header.propTypes = { onPress: PropTypes.func.isRequired, onSearchChangeText: PropTypes.func.isRequired, setSearchInputRef: PropTypes.func.isRequired, + connecting: PropTypes.bool, isFetching: PropTypes.bool, serverName: PropTypes.string }; diff --git a/app/views/RoomsListView/Header/Header.ios.js b/app/views/RoomsListView/Header/Header.ios.js index 64836a1140d200c0e5d793183057374f48fe1830..20d6f9b1308d26ec2eddd39853646ba64d25ec75 100644 --- a/app/views/RoomsListView/Header/Header.ios.js +++ b/app/views/RoomsListView/Header/Header.ios.js @@ -39,15 +39,18 @@ const styles = StyleSheet.create({ } }); -const HeaderTitle = ({ isFetching }) => { +const HeaderTitle = React.memo(({ connecting, isFetching }) => { + if (connecting) { + return <Text style={styles.title}>{I18n.t('Connecting')}</Text>; + } if (isFetching) { return <Text style={styles.title}>{I18n.t('Updating')}</Text>; } return <Text style={styles.title}>{I18n.t('Messages')}</Text>; -}; +}); -const Header = ({ - isFetching, serverName, showServerDropdown, onPress +const Header = React.memo(({ + connecting, isFetching, serverName, showServerDropdown, onPress }) => ( <View style={styles.container}> <TouchableOpacity @@ -55,16 +58,17 @@ const Header = ({ testID='rooms-list-header-server-dropdown-button' style={styles.container} > - <HeaderTitle isFetching={isFetching} /> + <HeaderTitle connecting={connecting} isFetching={isFetching} /> <View style={styles.button}> <Text style={styles.server}>{serverName}</Text> <Image style={[styles.disclosure, showServerDropdown && styles.upsideDown]} source={{ uri: 'disclosure_indicator_server' }} /> </View> </TouchableOpacity> </View> -); +)); Header.propTypes = { + connecting: PropTypes.bool, isFetching: PropTypes.bool, serverName: PropTypes.string, showServerDropdown: PropTypes.bool.isRequired, @@ -76,6 +80,7 @@ Header.defaultProps = { }; HeaderTitle.propTypes = { + connecting: PropTypes.bool, isFetching: PropTypes.bool }; diff --git a/app/views/RoomsListView/Header/index.js b/app/views/RoomsListView/Header/index.js index 3d156f2f3241f9d44ae806ff842112c471473c66..853602b5a6e7bb8c869793a7f71eaea4168aa988 100644 --- a/app/views/RoomsListView/Header/index.js +++ b/app/views/RoomsListView/Header/index.js @@ -11,6 +11,7 @@ import Header from './Header'; showServerDropdown: state.rooms.showServerDropdown, showSortDropdown: state.rooms.showSortDropdown, showSearchHeader: state.rooms.showSearchHeader, + connecting: state.meteor.connecting, isFetching: state.rooms.isFetching, serverName: state.settings.Site_Name }), dispatch => ({ @@ -25,6 +26,7 @@ export default class RoomsListHeaderView extends PureComponent { showSortDropdown: PropTypes.bool, showSearchHeader: PropTypes.bool, serverName: PropTypes.string, + connecting: PropTypes.bool, isFetching: PropTypes.bool, open: PropTypes.func, close: PropTypes.func, @@ -68,13 +70,15 @@ export default class RoomsListHeaderView extends PureComponent { render() { const { - serverName, showServerDropdown, showSearchHeader, isFetching + serverName, showServerDropdown, showSearchHeader, connecting, isFetching } = this.props; + return ( <Header serverName={serverName} showServerDropdown={showServerDropdown} showSearchHeader={showSearchHeader} + connecting={connecting} isFetching={isFetching} setSearchInputRef={this.setSearchInputRef} onPress={this.onPress} diff --git a/app/views/RoomsListView/index.js b/app/views/RoomsListView/index.js index 0f9c8762ff7ceb6fccfbb6b75183bb6d833000b7..453bdef3832ced633a10064587002ef76d1af39b 100644 --- a/app/views/RoomsListView/index.js +++ b/app/views/RoomsListView/index.js @@ -8,7 +8,6 @@ import { isEqual } from 'lodash'; import { SafeAreaView, NavigationEvents } from 'react-navigation'; import Orientation from 'react-native-orientation-locker'; -import ConnectionBadge from '../../containers/ConnectionBadge'; import database, { safeAddListener } from '../../lib/realm'; import RocketChat from '../../lib/rocketchat'; import RoomItem, { ROW_HEIGHT } from '../../presentation/RoomItem'; @@ -559,7 +558,6 @@ export default class RoomsListView extends LoggedView { : null } {showServerDropdown ? <ServerDropdown /> : null} - <ConnectionBadge /> <NavigationEvents onDidFocus={() => BackHandler.addEventListener('hardwareBackPress', this.handleBackPress)} onWillBlur={() => BackHandler.removeEventListener('hardwareBackPress', this.handleBackPress)}