From db0cd5abd139dbb240ede27cc6518ff950afaeed Mon Sep 17 00:00:00 2001
From: Diego Mello <diegolmello@gmail.com>
Date: Thu, 7 Feb 2019 14:13:21 -0200
Subject: [PATCH] Updating room indicator (#609)

Shows "Updating..." when requesting rooms from Rest API.
---
 app/i18n/locales/en.js                        |   1 +
 app/i18n/locales/pt-BR.js                     |   1 +
 app/lib/methods/getRooms.js                   |  33 +---
 app/lib/methods/subscriptions/rooms.js        |  18 +-
 app/lib/rocketchat.js                         |   3 +-
 app/reducers/rooms.js                         |   7 +-
 app/sagas/index.js                            |   2 +
 app/sagas/room.js                             | 156 ++++++++++++++++++
 app/sagas/rooms.js                            | 151 ++---------------
 .../RoomsListView/Header/Header.android.js    |  20 ++-
 app/views/RoomsListView/Header/Header.ios.js  |  22 ++-
 app/views/RoomsListView/Header/index.js       |  15 +-
 app/views/RoomsListView/index.js              |  17 +-
 13 files changed, 252 insertions(+), 194 deletions(-)
 create mode 100644 app/sagas/room.js

diff --git a/app/i18n/locales/en.js b/app/i18n/locales/en.js
index fb7fdbd81..abd9dcfca 100644
--- a/app/i18n/locales/en.js
+++ b/app/i18n/locales/en.js
@@ -330,6 +330,7 @@ export default {
 	Unread: 'Unread',
 	Unread_on_top: 'Unread on top',
 	Unstar: 'Unstar',
+	Updating: 'Updating...',
 	Uploading: 'Uploading',
 	Upload_file_question_mark: 'Upload file?',
 	User_added_by: 'User {{userAdded}} added by {{userBy}}',
diff --git a/app/i18n/locales/pt-BR.js b/app/i18n/locales/pt-BR.js
index 9f0b91c9c..b67439e27 100644
--- a/app/i18n/locales/pt-BR.js
+++ b/app/i18n/locales/pt-BR.js
@@ -328,6 +328,7 @@ export default {
 	Unread: 'Não lidas',
 	Unread_on_top: 'Não lidas no topo',
 	Unstar: 'Remover favorito',
+	Updating: 'Atualizando...',
 	Uploading: 'Subindo arquivo',
 	Upload_file_question_mark: 'Enviar arquivo?',
 	User_added_by: 'Usuário {{userAdded}} adicionado por {{userBy}}',
diff --git a/app/lib/methods/getRooms.js b/app/lib/methods/getRooms.js
index 417b38893..8e4fb7e3e 100644
--- a/app/lib/methods/getRooms.js
+++ b/app/lib/methods/getRooms.js
@@ -1,8 +1,4 @@
-import { InteractionManager } from 'react-native';
-
-import mergeSubscriptionsRooms from './helpers/mergeSubscriptionsRooms';
 import database from '../realm';
-import log from '../../utils/log';
 
 const lastMessage = () => {
 	const message = database
@@ -12,26 +8,11 @@ const lastMessage = () => {
 };
 
 export default function() {
-	return new Promise(async(resolve, reject) => {
-		try {
-			const updatedSince = lastMessage();
-			// subscriptions.get: Since RC 0.60.0
-			// rooms.get: Since RC 0.62.0
-			const [subscriptionsResult, roomsResult] = await (updatedSince
-				? Promise.all([this.sdk.get('subscriptions.get', { updatedSince }), this.sdk.get('rooms.get', { updatedSince })])
-				: Promise.all([this.sdk.get('subscriptions.get'), this.sdk.get('rooms.get')])
-			);
-			const { subscriptions } = mergeSubscriptionsRooms(subscriptionsResult, roomsResult);
-
-			InteractionManager.runAfterInteractions(() => {
-				database.write(() => {
-					subscriptions.forEach(subscription => database.create('subscriptions', subscription, true));
-				});
-				resolve(subscriptions);
-			});
-		} catch (e) {
-			log('getRooms', e);
-			reject(e);
-		}
-	});
+	const updatedSince = lastMessage();
+	// subscriptions.get: Since RC 0.60.0
+	// rooms.get: Since RC 0.62.0
+	if (updatedSince) {
+		return Promise.all([this.sdk.get('subscriptions.get', { updatedSince }), this.sdk.get('rooms.get', { updatedSince })]);
+	}
+	return Promise.all([this.sdk.get('subscriptions.get'), this.sdk.get('rooms.get')]);
 }
diff --git a/app/lib/methods/subscriptions/rooms.js b/app/lib/methods/subscriptions/rooms.js
index 7f6339248..494d50e71 100644
--- a/app/lib/methods/subscriptions/rooms.js
+++ b/app/lib/methods/subscriptions/rooms.js
@@ -4,6 +4,8 @@ import protectedFunction from '../helpers/protectedFunction';
 import messagesStatus from '../../../constants/messagesStatus';
 import log from '../../../utils/log';
 import random from '../../../utils/random';
+import store from '../../createStore';
+import { roomsRequest } from '../../../actions/rooms';
 
 export default async function subscribeRooms() {
 	let timer = null;
@@ -11,15 +13,11 @@ export default async function subscribeRooms() {
 		if (timer) {
 			return;
 		}
-		timer = setTimeout(async() => {
-			try {
-				clearTimeout(timer);
-				timer = false;
-				if (this.sdk.userId) {
-					await this.getRooms();
-					loop();
-				}
-			} catch (e) {
+		timer = setTimeout(() => {
+			clearTimeout(timer);
+			timer = false;
+			if (this.sdk.userId) {
+				store.dispatch(roomsRequest());
 				loop();
 			}
 		}, 5000);
@@ -27,7 +25,7 @@ export default async function subscribeRooms() {
 
 	this.sdk.onStreamData('connected', () => {
 		if (this.sdk.userId) {
-			this.getRooms();
+			store.dispatch(roomsRequest());
 		}
 		clearTimeout(timer);
 		timer = false;
diff --git a/app/lib/rocketchat.js b/app/lib/rocketchat.js
index 6f4c4a72f..bb9db20d0 100644
--- a/app/lib/rocketchat.js
+++ b/app/lib/rocketchat.js
@@ -39,6 +39,7 @@ import sendMessage, { getMessage, sendMessageCall } from './methods/sendMessage'
 import { sendFileMessage, cancelUpload, isUploadActive } from './methods/sendFileMessage';
 
 import { getDeviceToken } from '../push';
+import { roomsRequest } from '../actions/rooms';
 
 const TOKEN_KEY = 'reactnativemeteor_usertoken';
 const SORT_PREFS_KEY = 'RC_SORT_PREFS_KEY';
@@ -134,7 +135,7 @@ const RocketChat = {
 	},
 	loginSuccess({ user }) {
 		reduxStore.dispatch(setUser(user));
-		this.getRooms().catch(e => console.log(e));
+		reduxStore.dispatch(roomsRequest());
 		this.subscribeRooms();
 		this.sdk.subscribe('activeUsers');
 		this.sdk.subscribe('roles');
diff --git a/app/reducers/rooms.js b/app/reducers/rooms.js
index 0e16f13e6..f9931babc 100644
--- a/app/reducers/rooms.js
+++ b/app/reducers/rooms.js
@@ -1,8 +1,9 @@
 import * as types from '../actions/actionsTypes';
 
 const initialState = {
-	isFetching: false,
+	isFetching: true,
 	failure: false,
+	errorMessage: {},
 	searchText: '',
 	showServerDropdown: false,
 	closeServerDropdown: false,
@@ -15,7 +16,9 @@ export default function login(state = initialState, action) {
 		case types.ROOMS.REQUEST:
 			return {
 				...state,
-				isFetching: true
+				isFetching: true,
+				failure: false,
+				errorMessage: {}
 			};
 		case types.ROOMS.SUCCESS:
 			return {
diff --git a/app/sagas/index.js b/app/sagas/index.js
index b85e72291..d6de1d21f 100644
--- a/app/sagas/index.js
+++ b/app/sagas/index.js
@@ -1,6 +1,7 @@
 import { all } from 'redux-saga/effects';
 import login from './login';
 import rooms from './rooms';
+import room from './room';
 import messages from './messages';
 import selectServer from './selectServer';
 import createChannel from './createChannel';
@@ -14,6 +15,7 @@ const root = function* root() {
 		init(),
 		createChannel(),
 		rooms(),
+		room(),
 		login(),
 		messages(),
 		selectServer(),
diff --git a/app/sagas/room.js b/app/sagas/room.js
new file mode 100644
index 000000000..448499957
--- /dev/null
+++ b/app/sagas/room.js
@@ -0,0 +1,156 @@
+import { Alert } from 'react-native';
+import {
+	put, call, takeLatest, take, select, race, fork, cancel, takeEvery
+} from 'redux-saga/effects';
+import { delay } from 'redux-saga';
+import EJSON from 'ejson';
+
+import Navigation from '../lib/Navigation';
+import * as types from '../actions/actionsTypes';
+import { addUserTyping, removeUserTyping } from '../actions/room';
+import { messagesRequest, editCancel, replyCancel } from '../actions/messages';
+import RocketChat from '../lib/rocketchat';
+import database from '../lib/realm';
+import log from '../utils/log';
+import I18n from '../i18n';
+
+
+let sub;
+let thread;
+
+const cancelTyping = function* cancelTyping(username) {
+	while (true) {
+		const { typing, timeout } = yield race({
+			typing: take(types.ROOM.SOMEONE_TYPING),
+			timeout: call(delay, 5000)
+		});
+		if (timeout || (typing.username === username && !typing.typing)) {
+			return yield put(removeUserTyping(username));
+		}
+	}
+};
+
+const usersTyping = function* usersTyping({ rid }) {
+	while (true) {
+		const { _rid, username, typing } = yield take(types.ROOM.SOMEONE_TYPING);
+		if (_rid === rid) {
+			yield (typing ? put(addUserTyping(username)) : put(removeUserTyping(username)));
+			if (typing) {
+				yield fork(cancelTyping, username);
+			}
+		}
+	}
+};
+const handleMessageReceived = function* handleMessageReceived({ message }) {
+	try {
+		const room = yield select(state => state.room);
+
+		if (message.rid === room.rid) {
+			database.write(() => {
+				database.create('messages', EJSON.fromJSONValue(message), true);
+			});
+
+			if (room._id) {
+				RocketChat.readMessages(room.rid);
+			}
+		}
+	} catch (e) {
+		console.warn('handleMessageReceived', e);
+	}
+};
+
+let opened = false;
+
+const watchRoomOpen = function* watchRoomOpen({ room }) {
+	try {
+		if (opened) {
+			return;
+		}
+		opened = true;
+
+		const auth = yield select(state => state.login.isAuthenticated);
+		if (!auth) {
+			yield take(types.LOGIN.SUCCESS);
+		}
+
+		yield put(messagesRequest({ ...room }));
+
+		if (room._id) {
+			RocketChat.readMessages(room.rid);
+		}
+
+		sub = yield RocketChat.subscribeRoom(room);
+
+		thread = yield fork(usersTyping, { rid: room.rid });
+		yield race({
+			open: take(types.ROOM.OPEN),
+			close: take(types.ROOM.CLOSE)
+		});
+		opened = false;
+		cancel(thread);
+		sub.stop();
+		yield put(editCancel());
+		yield put(replyCancel());
+	} catch (e) {
+		log('watchRoomOpen', e);
+	}
+};
+
+const watchuserTyping = function* watchuserTyping({ status }) {
+	const auth = yield select(state => state.login.isAuthenticated);
+	if (!auth) {
+		yield take(types.LOGIN.SUCCESS);
+	}
+
+	const room = yield select(state => state.room);
+
+	if (!room) {
+		return;
+	}
+
+	try {
+		yield RocketChat.emitTyping(room.rid, status);
+
+		if (status) {
+			yield call(delay, 5000);
+			yield RocketChat.emitTyping(room.rid, false);
+		}
+	} catch (e) {
+		log('watchuserTyping', e);
+	}
+};
+
+const handleLeaveRoom = function* handleLeaveRoom({ rid, t }) {
+	try {
+		const result = yield RocketChat.leaveRoom(rid, t);
+		if (result.success) {
+			yield Navigation.popToRoot('RoomsListView');
+		}
+	} catch (e) {
+		if (e.data && e.data.errorType === 'error-you-are-last-owner') {
+			Alert.alert(I18n.t('Oops'), I18n.t(e.data.errorType));
+		} else {
+			Alert.alert(I18n.t('Oops'), I18n.t('There_was_an_error_while_action', { action: I18n.t('leaving_room') }));
+		}
+	}
+};
+
+const handleEraseRoom = function* handleEraseRoom({ rid, t }) {
+	try {
+		const result = yield RocketChat.eraseRoom(rid, t);
+		if (result.success) {
+			yield Navigation.popToRoot('RoomsListView');
+		}
+	} catch (e) {
+		Alert.alert(I18n.t('Oops'), I18n.t('There_was_an_error_while_action', { action: I18n.t('erasing_room') }));
+	}
+};
+
+const root = function* root() {
+	yield takeLatest(types.ROOM.USER_TYPING, watchuserTyping);
+	yield takeEvery(types.ROOM.OPEN, watchRoomOpen);
+	yield takeEvery(types.ROOM.MESSAGE_RECEIVED, handleMessageReceived);
+	yield takeLatest(types.ROOM.LEAVE, handleLeaveRoom);
+	yield takeLatest(types.ROOM.ERASE, handleEraseRoom);
+};
+export default root;
diff --git a/app/sagas/rooms.js b/app/sagas/rooms.js
index 6bf6347ae..e8d5cb529 100644
--- a/app/sagas/rooms.js
+++ b/app/sagas/rooms.js
@@ -1,155 +1,28 @@
-import { Alert } from 'react-native';
-import {
-	put, call, takeLatest, take, select, race, fork, cancel, takeEvery
-} from 'redux-saga/effects';
-import { delay } from 'redux-saga';
-import EJSON from 'ejson';
+import { put, takeLatest } from 'redux-saga/effects';
 
-import Navigation from '../lib/Navigation';
 import * as types from '../actions/actionsTypes';
-import { addUserTyping, removeUserTyping } from '../actions/room';
-import { messagesRequest, editCancel, replyCancel } from '../actions/messages';
+import { roomsSuccess, roomsFailure } from '../actions/rooms';
 import RocketChat from '../lib/rocketchat';
 import database from '../lib/realm';
 import log from '../utils/log';
-import I18n from '../i18n';
+import mergeSubscriptionsRooms from '../lib/methods/helpers/mergeSubscriptionsRooms';
 
-let sub;
-let thread;
-
-const cancelTyping = function* cancelTyping(username) {
-	while (true) {
-		const { typing, timeout } = yield race({
-			typing: take(types.ROOM.SOMEONE_TYPING),
-			timeout: call(delay, 5000)
-		});
-		if (timeout || (typing.username === username && !typing.typing)) {
-			return yield put(removeUserTyping(username));
-		}
-	}
-};
-
-const usersTyping = function* usersTyping({ rid }) {
-	while (true) {
-		const { _rid, username, typing } = yield take(types.ROOM.SOMEONE_TYPING);
-		if (_rid === rid) {
-			yield (typing ? put(addUserTyping(username)) : put(removeUserTyping(username)));
-			if (typing) {
-				yield fork(cancelTyping, username);
-			}
-		}
-	}
-};
-const handleMessageReceived = function* handleMessageReceived({ message }) {
-	try {
-		const room = yield select(state => state.room);
-
-		if (message.rid === room.rid) {
-			database.write(() => {
-				database.create('messages', EJSON.fromJSONValue(message), true);
-			});
-
-			if (room._id) {
-				RocketChat.readMessages(room.rid);
-			}
-		}
-	} catch (e) {
-		console.warn('handleMessageReceived', e);
-	}
-};
-
-let opened = false;
-
-const watchRoomOpen = function* watchRoomOpen({ room }) {
+const handleRoomsRequest = function* handleRoomsRequest() {
 	try {
-		if (opened) {
-			return;
-		}
-		opened = true;
+		const [subscriptionsResult, roomsResult] = yield RocketChat.getRooms();
+		const { subscriptions } = mergeSubscriptionsRooms(subscriptionsResult, roomsResult);
 
-		const auth = yield select(state => state.login.isAuthenticated);
-		if (!auth) {
-			yield take(types.LOGIN.SUCCESS);
-		}
-
-		yield put(messagesRequest({ ...room }));
-
-		if (room._id) {
-			RocketChat.readMessages(room.rid);
-		}
-
-		sub = yield RocketChat.subscribeRoom(room);
-
-		thread = yield fork(usersTyping, { rid: room.rid });
-		yield race({
-			open: take(types.ROOM.OPEN),
-			close: take(types.ROOM.CLOSE)
+		database.write(() => {
+			subscriptions.forEach(subscription => database.create('subscriptions', subscription, true));
 		});
-		opened = false;
-		cancel(thread);
-		sub.stop();
-		yield put(editCancel());
-		yield put(replyCancel());
-	} catch (e) {
-		log('watchRoomOpen', e);
-	}
-};
-
-const watchuserTyping = function* watchuserTyping({ status }) {
-	const auth = yield select(state => state.login.isAuthenticated);
-	if (!auth) {
-		yield take(types.LOGIN.SUCCESS);
-	}
-
-	const room = yield select(state => state.room);
-
-	if (!room) {
-		return;
-	}
-
-	try {
-		yield RocketChat.emitTyping(room.rid, status);
-
-		if (status) {
-			yield call(delay, 5000);
-			yield RocketChat.emitTyping(room.rid, false);
-		}
-	} catch (e) {
-		log('watchuserTyping', e);
-	}
-};
-
-const handleLeaveRoom = function* handleLeaveRoom({ rid, t }) {
-	try {
-		const result = yield RocketChat.leaveRoom(rid, t);
-		if (result.success) {
-			yield Navigation.popToRoot('RoomsListView');
-		}
-	} catch (e) {
-		if (e.data && e.data.errorType === 'error-you-are-last-owner') {
-			Alert.alert(I18n.t('Oops'), I18n.t(e.data.errorType));
-		} else {
-			Alert.alert(I18n.t('Oops'), I18n.t('There_was_an_error_while_action', { action: I18n.t('leaving_room') }));
-		}
-	}
-};
-
-const handleEraseRoom = function* handleEraseRoom({ rid, t }) {
-	try {
-		const result = yield RocketChat.eraseRoom(rid, t);
-		if (result.success) {
-			yield Navigation.popToRoot('RoomsListView');
-		}
+		yield put(roomsSuccess());
 	} catch (e) {
-		Alert.alert(I18n.t('Oops'), I18n.t('There_was_an_error_while_action', { action: I18n.t('erasing_room') }));
+		yield put(roomsFailure(e));
+		log('handleRoomsRequest', e);
 	}
 };
 
 const root = function* root() {
-	yield takeLatest(types.ROOM.USER_TYPING, watchuserTyping);
-	yield takeEvery(types.ROOM.OPEN, watchRoomOpen);
-	yield takeEvery(types.ROOM.MESSAGE_RECEIVED, handleMessageReceived);
-	yield takeLatest(types.ROOM.LEAVE, handleLeaveRoom);
-	yield takeLatest(types.ROOM.ERASE, handleEraseRoom);
+	yield takeLatest(types.ROOMS.REQUEST, handleRoomsRequest);
 };
 export default root;
diff --git a/app/views/RoomsListView/Header/Header.android.js b/app/views/RoomsListView/Header/Header.android.js
index 851b993ec..c75d5c500 100644
--- a/app/views/RoomsListView/Header/Header.android.js
+++ b/app/views/RoomsListView/Header/Header.android.js
@@ -5,6 +5,8 @@ import {
 import PropTypes from 'prop-types';
 import { TextInput } from 'react-native-gesture-handler';
 
+import I18n from '../../../i18n';
+
 const styles = StyleSheet.create({
 	container: {
 		flex: 1,
@@ -18,6 +20,13 @@ const styles = StyleSheet.create({
 		fontSize: 20,
 		color: '#FFF'
 	},
+	serverSmall: {
+		fontSize: 16
+	},
+	updating: {
+		fontSize: 14,
+		color: '#FFF'
+	},
 	disclosure: {
 		marginLeft: 9,
 		marginTop: 1,
@@ -30,7 +39,7 @@ const styles = StyleSheet.create({
 });
 
 const Header = ({
-	onPress, serverName, showServerDropdown, setSearchInputRef, showSearchHeader, onSearchChangeText
+	isFetching, serverName, showServerDropdown, width, setSearchInputRef, showSearchHeader, onSearchChangeText, onPress
 }) => {
 	if (showSearchHeader) {
 		return (
@@ -46,10 +55,11 @@ const Header = ({
 		);
 	}
 	return (
-		<View style={styles.container}>
+		<View style={[styles.container, { width: width - 150 }]}>
 			<TouchableOpacity onPress={onPress} testID='rooms-list-header-server-dropdown-button'>
+				{isFetching ? <Text style={styles.updating}>{I18n.t('Updating')}</Text> : null}
 				<View style={styles.button}>
-					<Text style={styles.server}>{serverName}</Text>
+					<Text style={[styles.server, isFetching && styles.serverSmall]}>{serverName}</Text>
 					<Image style={[styles.disclosure, showServerDropdown && styles.upsideDown]} source={{ uri: 'disclosure_indicator_server' }} />
 				</View>
 			</TouchableOpacity>
@@ -63,7 +73,9 @@ Header.propTypes = {
 	onPress: PropTypes.func.isRequired,
 	onSearchChangeText: PropTypes.func.isRequired,
 	setSearchInputRef: PropTypes.func.isRequired,
-	serverName: PropTypes.string
+	isFetching: PropTypes.bool,
+	serverName: PropTypes.string,
+	width: PropTypes.number
 };
 
 Header.defaultProps = {
diff --git a/app/views/RoomsListView/Header/Header.ios.js b/app/views/RoomsListView/Header/Header.ios.js
index e6d52b045..5ea0dd7d7 100644
--- a/app/views/RoomsListView/Header/Header.ios.js
+++ b/app/views/RoomsListView/Header/Header.ios.js
@@ -35,14 +35,23 @@ const styles = StyleSheet.create({
 	}
 });
 
-const Header = ({ onPress, serverName, showServerDropdown }) => (
+const HeaderTitle = ({ isFetching }) => {
+	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
+}) => (
 	<View style={styles.container}>
 		<TouchableOpacity
 			onPress={onPress}
 			testID='rooms-list-header-server-dropdown-button'
 			style={styles.container}
 		>
-			<Text style={styles.title}>{I18n.t('Messages')}</Text>
+			<HeaderTitle isFetching={isFetching} />
 			<View style={styles.button}>
 				<Text style={styles.server}>{serverName}</Text>
 				<Image style={[styles.disclosure, showServerDropdown && styles.upsideDown]} source={{ uri: 'disclosure_indicator_server' }} />
@@ -52,13 +61,18 @@ const Header = ({ onPress, serverName, showServerDropdown }) => (
 );
 
 Header.propTypes = {
-	onPress: PropTypes.func.isRequired,
+	isFetching: PropTypes.bool,
 	serverName: PropTypes.string,
-	showServerDropdown: PropTypes.bool.isRequired
+	showServerDropdown: PropTypes.bool.isRequired,
+	onPress: PropTypes.func.isRequired
 };
 
 Header.defaultProps = {
 	serverName: 'Rocket.Chat'
 };
 
+HeaderTitle.propTypes = {
+	isFetching: PropTypes.bool
+};
+
 export default Header;
diff --git a/app/views/RoomsListView/Header/index.js b/app/views/RoomsListView/Header/index.js
index 88a452572..d69c95d70 100644
--- a/app/views/RoomsListView/Header/index.js
+++ b/app/views/RoomsListView/Header/index.js
@@ -1,16 +1,19 @@
 import React, { PureComponent } from 'react';
 import PropTypes from 'prop-types';
 import { connect } from 'react-redux';
+import { responsive } from 'react-native-responsive-ui';
 
 import {
 	toggleServerDropdown, closeServerDropdown, closeSortDropdown, setSearch as setSearchAction
 } from '../../../actions/rooms';
 import Header from './Header';
 
+@responsive
 @connect(state => ({
 	showServerDropdown: state.rooms.showServerDropdown,
 	showSortDropdown: state.rooms.showSortDropdown,
 	showSearchHeader: state.rooms.showSearchHeader,
+	isFetching: state.rooms.isFetching,
 	serverName: state.settings.Site_Name
 }), dispatch => ({
 	close: () => dispatch(closeServerDropdown()),
@@ -24,10 +27,12 @@ export default class RoomsListHeaderView extends PureComponent {
 		showSortDropdown: PropTypes.bool,
 		showSearchHeader: PropTypes.bool,
 		serverName: PropTypes.string,
+		isFetching: PropTypes.bool,
 		open: PropTypes.func,
 		close: PropTypes.func,
 		closeSort: PropTypes.func,
-		setSearch: PropTypes.func
+		setSearch: PropTypes.func,
+		window: PropTypes.object
 	}
 
 	componentDidUpdate(prevProps) {
@@ -66,14 +71,18 @@ export default class RoomsListHeaderView extends PureComponent {
 
 
 	render() {
-		const { serverName, showServerDropdown, showSearchHeader } = this.props;
+		const {
+			serverName, showServerDropdown, showSearchHeader, isFetching, window: { width }
+		} = this.props;
 		return (
 			<Header
-				onPress={this.onPress}
 				serverName={serverName}
 				showServerDropdown={showServerDropdown}
 				showSearchHeader={showSearchHeader}
+				isFetching={isFetching}
+				width={width}
 				setSearchInputRef={this.setSearchInputRef}
+				onPress={this.onPress}
 				onSearchChangeText={text => this.onSearchChangeText(text)}
 			/>
 		);
diff --git a/app/views/RoomsListView/index.js b/app/views/RoomsListView/index.js
index 143a24d47..8d78aa8b4 100644
--- a/app/views/RoomsListView/index.js
+++ b/app/views/RoomsListView/index.js
@@ -20,7 +20,12 @@ import I18n from '../../i18n';
 import SortDropdown from './SortDropdown';
 import ServerDropdown from './ServerDropdown';
 import Touch from '../../utils/touch';
-import { toggleSortDropdown as toggleSortDropdownAction, openSearchHeader as openSearchHeaderAction, closeSearchHeader as closeSearchHeaderAction } from '../../actions/rooms';
+import {
+	toggleSortDropdown as toggleSortDropdownAction,
+	openSearchHeader as openSearchHeaderAction,
+	closeSearchHeader as closeSearchHeaderAction,
+	roomsRequest as roomsRequestAction
+} from '../../actions/rooms';
 import { appStart as appStartAction } from '../../actions';
 import debounce from '../../utils/debounce';
 import { isIOS, isAndroid } from '../../utils/deviceInfo';
@@ -69,7 +74,8 @@ if (isAndroid) {
 	toggleSortDropdown: () => dispatch(toggleSortDropdownAction()),
 	openSearchHeader: () => dispatch(openSearchHeaderAction()),
 	closeSearchHeader: () => dispatch(closeSearchHeaderAction()),
-	appStart: () => dispatch(appStartAction())
+	appStart: () => dispatch(appStartAction()),
+	roomsRequest: () => dispatch(roomsRequestAction())
 }))
 /** @extends React.Component */
 export default class RoomsListView extends LoggedView {
@@ -114,7 +120,8 @@ export default class RoomsListView extends LoggedView {
 		toggleSortDropdown: PropTypes.func,
 		openSearchHeader: PropTypes.func,
 		closeSearchHeader: PropTypes.func,
-		appStart: PropTypes.func
+		appStart: PropTypes.func,
+		roomsRequest: PropTypes.func
 	}
 
 	constructor(props) {
@@ -215,7 +222,7 @@ export default class RoomsListView extends LoggedView {
 
 	componentDidUpdate(prevProps) {
 		const {
-			sortBy, groupByType, showFavorites, showUnread, appState
+			sortBy, groupByType, showFavorites, showUnread, appState, roomsRequest
 		} = this.props;
 
 		if (!(
@@ -226,7 +233,7 @@ export default class RoomsListView extends LoggedView {
 		)) {
 			this.getSubscriptions();
 		} else if (appState === 'foreground' && appState !== prevProps.appState) {
-			RocketChat.getRooms().catch(e => console.log(e));
+			roomsRequest();
 		}
 	}
 
-- 
GitLab