From 94e32368ddc873753f61d5a3812b58b16418536c Mon Sep 17 00:00:00 2001 From: Diego Mello <diegolmello@gmail.com> Date: Tue, 30 Apr 2019 16:31:51 -0300 Subject: [PATCH] Remove connection badge (#862) * Connecting indicator on RoomsListView header * Connecting indicator on RoomView header * Remove ConnectionBadge * Show updating on RoomView load messages --- app/containers/ConnectionBadge.js | 140 ------------------ app/views/RoomView/Header/Header.js | 42 +++++- app/views/RoomView/Header/index.js | 15 +- app/views/RoomView/index.js | 23 ++- .../RoomsListView/Header/Header.android.js | 8 +- app/views/RoomsListView/Header/Header.ios.js | 17 ++- app/views/RoomsListView/Header/index.js | 6 +- app/views/RoomsListView/index.js | 2 - 8 files changed, 90 insertions(+), 163 deletions(-) delete mode 100644 app/containers/ConnectionBadge.js diff --git a/app/containers/ConnectionBadge.js b/app/containers/ConnectionBadge.js deleted file mode 100644 index 4d935c885..000000000 --- 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 2a6b9b5a0..31a2725c4 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 54d0d4cde..b3b354bdc 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 4354ca1fd..94e3ffce7 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 136563ea5..a2393caf0 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 64836a114..20d6f9b13 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 3d156f2f3..853602b5a 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 0f9c8762f..453bdef38 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)} -- GitLab