diff --git a/app/containers/ConnectionBadge.js b/app/containers/ConnectionBadge.js new file mode 100644 index 000000000..99a186dc6 --- /dev/null +++ b/app/containers/ConnectionBadge.js @@ -0,0 +1,144 @@ +import React, { Component } from 'react'; +import { + Text, StyleSheet, ActivityIndicator, Animated, TouchableWithoutFeedback, Easing +} from 'react-native'; +import { connect } from 'react-redux'; +import PropTypes from 'prop-types'; + +import I18n from '../i18n'; + +const styles = StyleSheet.create({ + container: { + width: '100%', + position: 'absolute', + top: 0, + height: 41, + backgroundColor: '#F7F8FA', + flexDirection: 'row', + alignItems: 'center', + justifyContent: 'center', + elevation: 4 + }, + text: { + color: '#fff', + fontSize: 15, + fontWeight: 'normal' + }, + textConnecting: { + color: '#9EA2A8' + }, + containerConnected: { + backgroundColor: '#2de0a5' + }, + containerOffline: { + backgroundColor: '#f5455c' + }, + 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.state = { + visible: false + }; + this.animatedValue = new Animated.Value(0); + } + + componentDidMount() { + const { connecting, disconnected } = this.props; + if (connecting || disconnected) { + this.animate(1); + } + } + + componentDidUpdate(prevProps) { + const { visible } = this.state; + const { connecting, connected, disconnected } = this.props; + + if ((connecting && connecting !== prevProps.connecting) || (disconnected && disconnected !== prevProps.disconnected)) { + if (!visible) { + this.animate(1); + } + } else if (connected && connected !== prevProps.connected) { + if (visible) { + setTimeout(() => { + this.animate(0); + }, 1000); + } + } + } + + animate = (toValue) => { + Animated.timing( + this.animatedValue, + { + toValue, + duration: ANIMATION_DURATION, + easing: Easing.ease, + useNativeDriver: true + }, + ).start(() => this.setState({ visible: toValue === 1 })); + } + + show = () => { + this.animate(1); + } + + hide = () => { + this.animate(0); + } + + render() { + const { connecting, connected } = this.props; + + const translateY = this.animatedValue.interpolate({ + inputRange: [0, 1], + outputRange: [-41, 0] + }); + + if (connecting) { + return ( + + + + {I18n.t('Connecting')} + + + ); + } else if (connected) { + return ( + + + {I18n.t('Connected')} + + + ); + } + + return ( + + + {I18n.t('Offline')} + + + ); + } +} + +export default ConnectionBadge; diff --git a/app/i18n/locales/en.js b/app/i18n/locales/en.js index 910b071ef..7ca32afe0 100644 --- a/app/i18n/locales/en.js +++ b/app/i18n/locales/en.js @@ -123,8 +123,8 @@ export default { Colaborative: 'Colaborative', Connect: 'Connect', Connect_to_a_server: 'Connect to a server', - Connected_to: 'Connected to', - Connecting: 'Connecting', + Connected: 'Connected', + Connecting: 'Connecting...', Copied_to_clipboard: 'Copied to clipboard!', Copy_Message: 'Copy Message', Copy_Permalink: 'Copy Permalink', diff --git a/app/i18n/locales/pt-BR.js b/app/i18n/locales/pt-BR.js index f0e4ef42b..5929f227b 100644 --- a/app/i18n/locales/pt-BR.js +++ b/app/i18n/locales/pt-BR.js @@ -130,8 +130,8 @@ export default { Colaborative: 'Colaborativo', Connect: 'Conectar', Connect_to_a_server: 'Conectar a um servidor', - Connected_to: 'Conectado a', - Connecting: 'Conectando', + Connected: 'Conectado', + Connecting: 'Conectando...', Copied_to_clipboard: 'Copiado para a área de transferência!', Copy_Message: 'Copiar Mensagem', Copy_Permalink: 'Copiar Link-Permanente', diff --git a/app/views/RoomView/index.js b/app/views/RoomView/index.js index 2d8a42e51..3de09327a 100644 --- a/app/views/RoomView/index.js +++ b/app/views/RoomView/index.js @@ -25,6 +25,7 @@ import I18n from '../../i18n'; import debounce from '../../utils/debounce'; import { iconsMap } from '../../Icons'; import store from '../../lib/createStore'; +import ConnectionBadge from '../../containers/ConnectionBadge'; let RoomActionsView = null; @@ -388,6 +389,7 @@ export default class RoomView extends LoggedView { {showErrorActions ? : null} + ); } diff --git a/app/views/RoomsListView/index.js b/app/views/RoomsListView/index.js index 6d2bca73e..f31d6c5fe 100644 --- a/app/views/RoomsListView/index.js +++ b/app/views/RoomsListView/index.js @@ -8,6 +8,7 @@ import { isEqual } from 'lodash'; import { Navigation } from 'react-native-navigation'; import SearchBox from '../../containers/SearchBox'; +import ConnectionBadge from '../../containers/ConnectionBadge'; import database from '../../lib/realm'; import RocketChat from '../../lib/rocketchat'; import RoomItem from '../../presentation/RoomItem'; @@ -91,8 +92,8 @@ export default class RoomsListView extends LoggedView { groupByType: PropTypes.bool, showFavorites: PropTypes.bool, showUnread: PropTypes.bool, - toggleSortDropdown: PropTypes.func, - useRealName: PropTypes.bool + useRealName: PropTypes.bool, + toggleSortDropdown: PropTypes.func } constructor(props) { @@ -565,6 +566,7 @@ export default class RoomsListView extends LoggedView { : null } {showServerDropdown ? : null} + ); } diff --git a/app/views/index.js b/app/views/index.js index c48953fdf..318171c0f 100644 --- a/app/views/index.js +++ b/app/views/index.js @@ -1,3 +1,4 @@ +import { Platform } from 'react-native'; import { Navigation } from 'react-native-navigation'; import { Provider } from 'react-redux'; import { gestureHandlerRootHOC } from 'react-native-gesture-handler'; @@ -5,7 +6,6 @@ import { gestureHandlerRootHOC } from 'react-native-gesture-handler'; import OnboardingView from './OnboardingView'; import ProfileView from './ProfileView'; import RoomsListHeaderView from './RoomsListView/Header'; -import RoomsListSearchView from './RoomsListView/Search'; import RoomsListView from './RoomsListView'; import RoomView from './RoomView'; import SettingsView from './SettingsView'; @@ -15,7 +15,12 @@ export const registerScreens = (store) => { Navigation.registerComponent('OnboardingView', () => OnboardingView, store, Provider); Navigation.registerComponent('ProfileView', () => ProfileView, store, Provider); Navigation.registerComponent('RoomsListHeaderView', () => RoomsListHeaderView, store, Provider); - Navigation.registerComponent('RoomsListSearchView', () => RoomsListSearchView, store, Provider); + + if (Platform.OS === 'android') { + const RoomsListSearchView = require('./RoomsListView/Search'); + Navigation.registerComponent('RoomsListSearchView', () => RoomsListSearchView, store, Provider); + } + Navigation.registerComponent('RoomsListView', () => gestureHandlerRootHOC(RoomsListView), store, Provider); Navigation.registerComponent('RoomView', () => gestureHandlerRootHOC(RoomView), store, Provider); Navigation.registerComponent('SettingsView', () => SettingsView, store, Provider);