From a2821af95b43d75404d4fb59d7ac32483ec2e40e Mon Sep 17 00:00:00 2001
From: Diego Mello <diegolmello@gmail.com>
Date: Wed, 5 Dec 2018 18:52:08 -0200
Subject: [PATCH] Use Rest API calls (#558)

---
 .../__snapshots__/Storyshots.test.js.snap     |   8 +-
 app/ReactotronConfig.js                       |   1 +
 app/actions/actionsTypes.js                   |  14 +-
 app/actions/connect.js                        |  12 -
 app/actions/login.js                          |  91 +--
 app/actions/room.js                           |  10 +-
 app/constants/settings.js                     |   4 +-
 app/containers/Avatar.js                      |   9 +-
 app/containers/MessageActions.js              |   5 +-
 app/containers/MessageBox/Recording.js        |   1 -
 app/containers/Sidebar.js                     |   4 +-
 app/containers/message/Image.js               |   2 +-
 app/i18n/locales/en.js                        |   4 +-
 app/i18n/locales/pt-BR.js                     |   5 +-
 app/i18n/locales/ru.js                        |   2 -
 app/i18n/locales/zh-CN.js                     |   2 -
 app/index.js                                  |   2 -
 app/lib/methods/canOpenRoom.js                |  36 +-
 app/lib/methods/getCustomEmojis.js            |   3 +-
 app/lib/methods/getPermissions.js             |  16 +-
 app/lib/methods/getRooms.js                   |  26 +-
 app/lib/methods/getSettings.js                |  26 +-
 app/lib/methods/loadMessagesForRoom.js        |  31 +-
 app/lib/methods/loadMissedMessages.js         |  15 +-
 app/lib/methods/readMessages.js               |  19 +-
 app/lib/methods/sendMessage.js                |  23 +-
 app/lib/methods/subscriptions/room.js         |  38 +-
 app/lib/methods/subscriptions/rooms.js        | 140 ++--
 app/lib/rocketchat.js                         | 623 +++++++++---------
 app/reducers/app.js                           |   7 +-
 app/reducers/connect.js                       |  24 +-
 app/reducers/login.js                         |  77 +--
 app/reducers/sortPreferences.js               |   6 +-
 app/sagas/connect.js                          |  50 --
 app/sagas/index.js                            |   2 -
 app/sagas/init.js                             |  41 +-
 app/sagas/login.js                            | 123 ++--
 app/sagas/messages.js                         |   3 +-
 app/sagas/rooms.js                            |  59 +-
 app/sagas/selectServer.js                     |  20 +-
 app/sagas/state.js                            |  15 +-
 app/utils/isValidEmail.js                     |   5 +
 app/utils/log.js                              |   2 +-
 app/views/ForgotPasswordView.js               |  52 +-
 app/views/LoginSignupView.js                  |  14 +-
 app/views/LoginView.js                        |  50 +-
 app/views/OAuthView.js                        |  15 +-
 app/views/RegisterView.js                     |  62 +-
 app/views/RoomActionsView/index.js            |  95 +--
 app/views/RoomInfoView/index.js               |   2 +-
 app/views/RoomMembersView/index.js            |  19 +-
 app/views/RoomView/ListView.js                |   7 +-
 app/views/RoomView/index.js                   |  90 ++-
 app/views/RoomsListView/index.js              |  15 +-
 app/views/SetUsernameView.js                  |  50 +-
 e2e/03-forgotpassword.spec.js                 |   2 +-
 e2e/04-createuser.spec.js                     |  41 +-
 package-lock.json                             | 148 +----
 package.json                                  |   7 +-
 59 files changed, 882 insertions(+), 1393 deletions(-)
 delete mode 100644 app/sagas/connect.js
 create mode 100644 app/utils/isValidEmail.js

diff --git a/__tests__/__snapshots__/Storyshots.test.js.snap b/__tests__/__snapshots__/Storyshots.test.js.snap
index 326454c38..b9ce35685 100644
--- a/__tests__/__snapshots__/Storyshots.test.js.snap
+++ b/__tests__/__snapshots__/Storyshots.test.js.snap
@@ -34,7 +34,7 @@ exports[`Storyshots Avatar avatar 1`] = `
           source={
             Object {
               "priority": "high",
-              "uri": "baseUrl/avatar/test?format=png&size=50",
+              "uri": "baseUrl/avatar/test?format=png&width=50&height=50",
             }
           }
           style={
@@ -80,7 +80,7 @@ exports[`Storyshots Avatar avatar 1`] = `
           source={
             Object {
               "priority": "high",
-              "uri": "baseUrl/avatar/aa?format=png&size=50",
+              "uri": "baseUrl/avatar/aa?format=png&width=50&height=50",
             }
           }
           style={
@@ -126,7 +126,7 @@ exports[`Storyshots Avatar avatar 1`] = `
           source={
             Object {
               "priority": "high",
-              "uri": "baseUrl/avatar/bb?format=png&size=50",
+              "uri": "baseUrl/avatar/bb?format=png&width=50&height=50",
             }
           }
           style={
@@ -172,7 +172,7 @@ exports[`Storyshots Avatar avatar 1`] = `
           source={
             Object {
               "priority": "high",
-              "uri": "baseUrl/avatar/test?format=png&size=50",
+              "uri": "baseUrl/avatar/test?format=png&width=50&height=50",
             }
           }
           style={
diff --git a/app/ReactotronConfig.js b/app/ReactotronConfig.js
index 4f2db6146..d274cb6f3 100644
--- a/app/ReactotronConfig.js
+++ b/app/ReactotronConfig.js
@@ -17,4 +17,5 @@ if (__DEV__) {
     // $ adb reverse tcp:9090 tcp:9090
     Reactotron.clear();
     console.warn = Reactotron.log;
+    console.log = Reactotron.log;
 }
diff --git a/app/actions/actionsTypes.js b/app/actions/actionsTypes.js
index 74780887d..5238b5339 100644
--- a/app/actions/actionsTypes.js
+++ b/app/actions/actionsTypes.js
@@ -11,19 +11,10 @@ function createRequestTypes(base, types = defaultTypes) {
 // Login events
 export const LOGIN = createRequestTypes('LOGIN', [
 	...defaultTypes,
-	'SET_TOKEN',
-	'RESTORE_TOKEN',
-	'SUBMIT',
-	'REGISTER_SUBMIT',
-	'REGISTER_REQUEST',
-	'SET_USERNAME_SUBMIT',
-	'SET_USERNAME_REQUEST',
-	'SET_USERNAME_SUCCESS',
 	'SET_SERVICES',
 	'SET_PREFERENCE',
 	'SET_SORT_PREFERENCE'
 ]);
-export const FORGOT_PASSWORD = createRequestTypes('FORGOT_PASSWORD');
 export const USER = createRequestTypes('USER', ['SET']);
 export const ROOMS = createRequestTypes('ROOMS', [
 	...defaultTypes,
@@ -82,7 +73,7 @@ export const SERVER = createRequestTypes('SERVER', [
 	'INIT_ADD',
 	'FINISH_ADD'
 ]);
-export const METEOR = createRequestTypes('METEOR_CONNECT', [...defaultTypes, 'DISCONNECT', 'DISCONNECT_BY_USER']);
+export const METEOR = createRequestTypes('METEOR_CONNECT', [...defaultTypes, 'DISCONNECT']);
 export const LOGOUT = 'LOGOUT'; // logout is always success
 export const ACTIVE_USERS = createRequestTypes('ACTIVE_USERS', ['SET']);
 export const ROLES = createRequestTypes('ROLES', ['SET']);
@@ -93,6 +84,3 @@ export const SNIPPETED_MESSAGES = createRequestTypes('SNIPPETED_MESSAGES', ['OPE
 export const ROOM_FILES = createRequestTypes('ROOM_FILES', ['OPEN', 'READY', 'CLOSE', 'MESSAGES_RECEIVED']);
 export const DEEP_LINKING = createRequestTypes('DEEP_LINKING', ['OPEN']);
 export const SORT_PREFERENCES = createRequestTypes('SORT_PREFERENCES', ['SET_ALL', 'SET']);
-
-export const INCREMENT = 'INCREMENT';
-export const DECREMENT = 'DECREMENT';
diff --git a/app/actions/connect.js b/app/actions/connect.js
index 40049f28e..57f46c71b 100644
--- a/app/actions/connect.js
+++ b/app/actions/connect.js
@@ -12,21 +12,9 @@ export function connectSuccess() {
 	};
 }
 
-export function connectFailure(err) {
-	return {
-		type: types.METEOR.FAILURE,
-		err
-	};
-}
-
 export function disconnect(err) {
 	return {
 		type: types.METEOR.DISCONNECT,
 		err
 	};
 }
-export function disconnect_by_user() {
-	return {
-		type: types.METEOR.DISCONNECT_BY_USER
-	};
-}
diff --git a/app/actions/login.js b/app/actions/login.js
index cc5c17150..c406d8e89 100644
--- a/app/actions/login.js
+++ b/app/actions/login.js
@@ -1,11 +1,5 @@
 import * as types from './actionsTypes';
 
-export function loginSubmit(credentials) {
-	return {
-		type: types.LOGIN.SUBMIT,
-		credentials
-	};
-}
 export function loginRequest(credentials) {
 	return {
 		type: types.LOGIN.REQUEST,
@@ -13,45 +7,10 @@ export function loginRequest(credentials) {
 	};
 }
 
-export function registerSubmit(credentials) {
-	return {
-		type: types.LOGIN.REGISTER_SUBMIT,
-		credentials
-	};
-}
-
-export function registerRequest(credentials) {
-	return {
-		type: types.LOGIN.REGISTER_REQUEST,
-		credentials
-	};
-}
-
-export function setUsernameSubmit(credentials) {
-	return {
-		type: types.LOGIN.SET_USERNAME_SUBMIT,
-		credentials
-	};
-}
-
-export function setUsernameRequest(credentials) {
-	return {
-		type: types.LOGIN.SET_USERNAME_REQUEST,
-		credentials
-	};
-}
-
-export function setUsernameSuccess() {
-	return {
-		type: types.LOGIN.SET_USERNAME_SUCCESS
-	};
-}
-
 export function loginSuccess(user) {
 	return {
 		type: types.LOGIN.SUCCESS,
-		user,
-		token: user.token
+		user
 	};
 }
 
@@ -62,58 +21,16 @@ export function loginFailure(err) {
 	};
 }
 
-export function setToken(user = {}) {
-	return {
-		type: types.LOGIN.SET_TOKEN,
-		...user
-	};
-}
-
-export function restoreToken(token) {
-	return {
-		type: types.LOGIN.RESTORE_TOKEN,
-		token
-	};
-}
-
 export function logout() {
 	return {
 		type: types.LOGOUT
 	};
 }
 
-export function forgotPasswordInit() {
-	return {
-		type: types.FORGOT_PASSWORD.INIT
-	};
-}
-
-export function forgotPasswordRequest(email) {
-	return {
-		type: types.FORGOT_PASSWORD.REQUEST,
-		email
-	};
-}
-
-export function forgotPasswordSuccess() {
-	return {
-		type: types.FORGOT_PASSWORD.SUCCESS
-	};
-}
-
-export function forgotPasswordFailure(err) {
-	return {
-		type: types.FORGOT_PASSWORD.FAILURE,
-		err
-	};
-}
-
-export function setUser(action) {
+export function setUser(user) {
 	return {
-		// do not change this params order
-		// since we use spread operator, sometimes `type` is overriden
-		...action,
-		type: types.USER.SET
+		type: types.USER.SET,
+		user
 	};
 }
 
diff --git a/app/actions/room.js b/app/actions/room.js
index 2c2e603ad..ab8b1b1e6 100644
--- a/app/actions/room.js
+++ b/app/actions/room.js
@@ -35,17 +35,19 @@ export function closeRoom() {
 	};
 }
 
-export function leaveRoom(rid) {
+export function leaveRoom(rid, t) {
 	return {
 		type: types.ROOM.LEAVE,
-		rid
+		rid,
+		t
 	};
 }
 
-export function eraseRoom(rid) {
+export function eraseRoom(rid, t) {
 	return {
 		type: types.ROOM.ERASE,
-		rid
+		rid,
+		t
 	};
 }
 
diff --git a/app/constants/settings.js b/app/constants/settings.js
index 12277bf58..fe00972b4 100644
--- a/app/constants/settings.js
+++ b/app/constants/settings.js
@@ -58,6 +58,8 @@ export default {
 	},
 	UI_Use_Real_Name: {
 		type: 'valueAsBoolean'
+	},
+	Assets_favicon_512: {
+		type: null
 	}
 };
-export const settingsUpdatedAt = new Date('2018-11-14');
diff --git a/app/containers/Avatar.js b/app/containers/Avatar.js
index 29381de5b..fc531de1f 100644
--- a/app/containers/Avatar.js
+++ b/app/containers/Avatar.js
@@ -33,8 +33,15 @@ export default class Avatar extends React.PureComponent {
 			borderRadius
 		};
 
+		if (!text && !avatar) {
+			return null;
+		}
+
 		const room = type === 'd' ? text : `@${ text }`;
-		const uri = avatar || `${ baseUrl }/avatar/${ room }?format=png&size=${ size === 100 ? 100 : 50 }`;
+		// Avoid requesting several sizes by having only two sizes on cache
+		const uriSize = size === 100 ? 100 : 50;
+		const uri = avatar || `${ baseUrl }/avatar/${ room }?format=png&width=${ uriSize }&height=${ uriSize }`;
+
 		const image = (
 			<FastImage
 				style={avatarStyle}
diff --git a/app/containers/MessageActions.js b/app/containers/MessageActions.js
index bc9e78739..36f257b7d 100644
--- a/app/containers/MessageActions.js
+++ b/app/containers/MessageActions.js
@@ -245,10 +245,11 @@ export default class MessageActions extends React.Component {
 		showToast(I18n.t('Copied_to_clipboard'));
 	}
 
-	handleShare = () => {
+	handleShare = async() => {
 		const { actionMessage } = this.props;
+		const permalink = await this.getPermalink(actionMessage);
 		Share.share({
-			message: actionMessage.msg.content.replace(/<(?:.|\n)*?>/gm, '')
+			message: permalink
 		});
 	};
 
diff --git a/app/containers/MessageBox/Recording.js b/app/containers/MessageBox/Recording.js
index ebf8d087e..8652f27a0 100644
--- a/app/containers/MessageBox/Recording.js
+++ b/app/containers/MessageBox/Recording.js
@@ -101,7 +101,6 @@ export default class extends React.PureComponent {
 			}
 		} catch (err) {
 			this.finishRecording(false);
-			console.error(err);
 		}
 	}
 
diff --git a/app/containers/Sidebar.js b/app/containers/Sidebar.js
index 4dce24871..a9ff4af78 100644
--- a/app/containers/Sidebar.js
+++ b/app/containers/Sidebar.js
@@ -7,7 +7,7 @@ import { connect } from 'react-redux';
 import Icon from 'react-native-vector-icons/MaterialIcons';
 import { Navigation } from 'react-native-navigation';
 
-import { appStart as appStartAction, setStackRoot as setStackRootAction } from '../actions';
+import { setStackRoot as setStackRootAction } from '../actions';
 import { logout as logoutAction } from '../actions/login';
 import Avatar from './Avatar';
 import Status from './status';
@@ -95,7 +95,6 @@ const keyExtractor = item => item.id;
 	baseUrl: state.settings.Site_Url || state.server ? state.server.server : ''
 }), dispatch => ({
 	logout: () => dispatch(logoutAction()),
-	appStart: () => dispatch(appStartAction('outside')),
 	setStackRoot: stackRoot => dispatch(setStackRootAction(stackRoot))
 }))
 export default class Sidebar extends Component {
@@ -106,7 +105,6 @@ export default class Sidebar extends Component {
 		stackRoot: PropTypes.string.isRequired,
 		user: PropTypes.object,
 		logout: PropTypes.func.isRequired,
-		appStart: PropTypes.func,
 		setStackRoot: PropTypes.func
 	}
 
diff --git a/app/containers/message/Image.js b/app/containers/message/Image.js
index bef948757..6b81127dd 100644
--- a/app/containers/message/Image.js
+++ b/app/containers/message/Image.js
@@ -44,7 +44,7 @@ export default class extends React.PureComponent {
 		const { baseUrl, file, user } = this.props;
 		const img = `${ baseUrl }${ file.image_url }?rc_uid=${ user.id }&rc_token=${ user.token }`;
 
-		if (!baseUrl) {
+		if (!img) {
 			return null;
 		}
 
diff --git a/app/i18n/locales/en.js b/app/i18n/locales/en.js
index 415821633..425cacae0 100644
--- a/app/i18n/locales/en.js
+++ b/app/i18n/locales/en.js
@@ -1,5 +1,4 @@
 export default {
-	'1_online_member': '1 online member',
 	'1_person_reacted': '1 person reacted',
 	'1_user': '1 user',
 	'error-action-not-allowed': '{{action}} is not allowed',
@@ -184,6 +183,7 @@ export default {
 	Login_error: 'Your credentials were rejected! Please try again.',
 	Login_with: 'Login with',
 	Logout: 'Logout',
+	members: 'members',
 	Members: 'Members',
 	Mentioned_Messages: 'Mentioned Messages',
 	mentioned: 'mentioned',
@@ -198,7 +198,6 @@ export default {
 	Mute: 'Mute',
 	muted: 'muted',
 	My_servers: 'My servers',
-	N_online_members: '{{n}} online members',
 	N_people_reacted: '{{n}} people reacted',
 	N_users: '{{n}} users',
 	name: 'name',
@@ -254,6 +253,7 @@ export default {
 	Reply: 'Reply',
 	Resend: 'Resend',
 	Reset_password: 'Reset password',
+	resetting_password: 'resetting password',
 	RESET: 'RESET',
 	Roles: 'Roles',
 	Room_actions: 'Room actions',
diff --git a/app/i18n/locales/pt-BR.js b/app/i18n/locales/pt-BR.js
index 3f627b561..76d51ae2e 100644
--- a/app/i18n/locales/pt-BR.js
+++ b/app/i18n/locales/pt-BR.js
@@ -1,5 +1,4 @@
 export default {
-	'1_online_member': '1 membro online',
 	'1_person_reacted': '1 pessoa reagiu',
 	'1_user': '1 usuário',
 	'error-action-not-allowed': '{{action}} não é permitido',
@@ -202,7 +201,6 @@ export default {
 	Microphone_Permission: 'Acesso ao Microfone',
 	Mute: 'Mudo',
 	muted: 'mudo',
-	N_online_members: '{{n}} membros online',
 	N_people_reacted: '{{n}} pessoas reagiram',
 	N_users: '{{n}} usuários',
 	name: 'nome',
@@ -257,6 +255,7 @@ export default {
 	Reply: 'Responder',
 	Resend: 'Reenviar',
 	Reset_password: 'Resetar senha',
+	resetting_password: 'redefinindo senha',
 	RESET: 'RESETAR',
 	Roles: 'Papéis',
 	Room_actions: 'Ações',
@@ -305,7 +304,7 @@ export default {
 	Take_a_photo: 'Tirar uma foto',
 	Terms_of_Service: ' Termos de Serviço ',
 	The_URL_is_invalid: 'A URL fornecida é inválida ou não acessível. Por favor tente novamente, mas com uma url diferente.',
-	There_was_an_error_while_action: 'Acontece um erro {{action}}!',
+	There_was_an_error_while_action: 'Aconteceu um erro {{action}}!',
 	This_room_is_blocked: 'Este quarto está bloqueado',
 	This_room_is_read_only: 'Este quarto é apenas de leitura',
 	Timezone: 'Fuso horário',
diff --git a/app/i18n/locales/ru.js b/app/i18n/locales/ru.js
index 7fb8a0cc4..4cc484d49 100644
--- a/app/i18n/locales/ru.js
+++ b/app/i18n/locales/ru.js
@@ -1,5 +1,4 @@
 export default {
-	'1_online_member': '1 участник онлайн',
 	'1_person_reacted': '1 человек отреагировал',
 	'error-action-not-allowed': '{{action}} не допускается',
 	'error-application-not-found': 'Приложение не найдено',
@@ -175,7 +174,6 @@ export default {
 	Mute: 'Заглушить',
 	muted: 'Заглушен',
 	My_servers: 'Мои серверы',
-	N_online_members: '{{n}} пользователей онлайн',
 	N_person_reacted: '{{n}} людей отреагировало',
 	Name: 'Имя',
 	New_in_RocketChat_question_mark: 'Новичок в Rocket.Chat?',
diff --git a/app/i18n/locales/zh-CN.js b/app/i18n/locales/zh-CN.js
index 958058b46..b5c5e1528 100644
--- a/app/i18n/locales/zh-CN.js
+++ b/app/i18n/locales/zh-CN.js
@@ -1,5 +1,4 @@
 export default {
-	'1_online_member': '1 人在线',
 	'1_person_reacted': '1 人回复了',
 	'1_user': '1 位用户',
 	'error-action-not-allowed': '不允许 {{action}}',
@@ -199,7 +198,6 @@ export default {
 	Mute: '静音',
 	muted: '被静音',
 	My_servers: '我的服务器',
-	N_online_members: '{{n}} 位会员在线',
 	N_people_reacted: '{{n}} 人回复',
 	N_users: '{{n}} 位用户',
 	name: '名字',
diff --git a/app/index.js b/app/index.js
index c6cb8f6f6..579a84048 100644
--- a/app/index.js
+++ b/app/index.js
@@ -99,8 +99,6 @@ iconsLoaded();
 export default class App extends Component {
 	constructor(props) {
 		super(props);
-		store.dispatch(appInit());
-		store.subscribe(this.onStoreUpdate.bind(this));
 		initializePushNotifications();
 
 		Navigation.events().registerAppLaunchedListener(() => {
diff --git a/app/lib/methods/canOpenRoom.js b/app/lib/methods/canOpenRoom.js
index d37e8e933..f4a16e8d2 100644
--- a/app/lib/methods/canOpenRoom.js
+++ b/app/lib/methods/canOpenRoom.js
@@ -1,57 +1,37 @@
 import * as SDK from '@rocket.chat/sdk';
 
 import database from '../realm';
-import log from '../../utils/log';
 
-// TODO: api fix
-const ddpTypes = {
-	channel: 'c', direct: 'd', group: 'p'
-};
 const restTypes = {
 	channel: 'channels', direct: 'im', group: 'groups'
 };
 
-async function canOpenRoomREST({ type, rid }) {
+async function open({ type, rid }) {
 	try {
 		await SDK.api.post(`${ restTypes[type] }.open`, { roomId: rid });
 		return true;
-	} catch (error) {
-		// TODO: workround for 'already open for the sender' error
-		if (!error.errorType) {
+	} catch (e) {
+		if (e.data && /is already open/.test(e.data.error)) {
 			return true;
 		}
 		return false;
 	}
 }
 
-async function canOpenRoomDDP(...args) {
-	try {
-		const [{ type, name }] = args;
-		await SDK.driver.asyncCall('getRoomByTypeAndName', ddpTypes[type], name);
+export default async function canOpenRoom({ rid, path }) {
+	const [type] = path.split('/');
+	if (type === 'channel') {
 		return true;
-	} catch (error) {
-		if (error.isClientSafe) {
-			return false;
-		}
-		return canOpenRoomREST.call(this, ...args);
 	}
-}
-
-export default async function canOpenRoom({ rid, path }) {
-	const { database: db } = database;
 
-	const room = db.objects('subscriptions').filtered('rid == $0', rid);
+	const room = database.objects('subscriptions').filtered('rid == $0', rid);
 	if (room.length) {
 		return true;
 	}
 
-	const [type, name] = path.split('/');
-
 	try {
-		const data = await (this.connected() ? canOpenRoomDDP.call(this, { rid, type, name }) : canOpenRoomREST.call(this, { type, rid }));
-		return data;
+		return await open.call(this, { type, rid });
 	} catch (e) {
-		log('canOpenRoom', e);
 		return false;
 	}
 }
diff --git a/app/lib/methods/getCustomEmojis.js b/app/lib/methods/getCustomEmojis.js
index cded086d4..45d5994f5 100644
--- a/app/lib/methods/getCustomEmojis.js
+++ b/app/lib/methods/getCustomEmojis.js
@@ -16,7 +16,8 @@ const getLastMessage = () => {
 export default async function() {
 	try {
 		const lastMessage = getLastMessage();
-		let emojis = await SDK.driver.asyncCall('listEmojiCustom');
+		const result = await SDK.api.get('emoji-custom');
+		let { emojis } = result;
 		emojis = emojis.filter(emoji => !lastMessage || emoji._updatedAt > lastMessage);
 		emojis = this._prepareEmojis(emojis);
 		InteractionManager.runAfterInteractions(() => database.write(() => {
diff --git a/app/lib/methods/getPermissions.js b/app/lib/methods/getPermissions.js
index e0398c484..0c1e40e90 100644
--- a/app/lib/methods/getPermissions.js
+++ b/app/lib/methods/getPermissions.js
@@ -5,18 +5,14 @@ import database from '../realm';
 import log from '../../utils/log';
 import defaultPermissions from '../../constants/permissions';
 
-const getLastUpdate = () => {
-	const setting = database.objects('permissions').sorted('_updatedAt', true)[0];
-	return setting && setting._updatedAt;
-};
-
 export default async function() {
 	try {
-		const lastUpdate = getLastUpdate();
-		const result = await (!lastUpdate
-			? SDK.driver.asyncCall('permissions/get')
-			: SDK.driver.asyncCall('permissions/get', new Date(lastUpdate)));
-		const permissions = (result.update || result).filter(permission => defaultPermissions.includes(permission._id));
+		const result = await SDK.api.get('permissions.list');
+
+		if (!result.success) {
+			return;
+		}
+		const permissions = result.permissions.filter(permission => defaultPermissions.includes(permission._id));
 		permissions
 			.map((permission) => {
 				permission._updatedAt = new Date();
diff --git a/app/lib/methods/getRooms.js b/app/lib/methods/getRooms.js
index acf7ed01c..f43316a5a 100644
--- a/app/lib/methods/getRooms.js
+++ b/app/lib/methods/getRooms.js
@@ -12,31 +12,17 @@ const lastMessage = () => {
 	return message && new Date(message.roomUpdatedAt).toISOString();
 };
 
-const getRoomRest = async function() {
-	const updatedSince = lastMessage();
-	const [subscriptions, rooms] = await (updatedSince
-		? Promise.all([SDK.api.get('subscriptions.get', { updatedSince }), SDK.api.get('rooms.get', { updatedSince })])
-		: Promise.all([SDK.api.get('subscriptions.get'), SDK.api.get('rooms.get')])
-	);
-	return mergeSubscriptionsRooms(subscriptions, rooms);
-};
-
-const getRoomDpp = async function() {
-	try {
-		const updatedSince = lastMessage();
-		const [subscriptions, rooms] = await Promise.all([SDK.driver.asyncCall('subscriptions/get', updatedSince), SDK.driver.asyncCall('rooms/get', updatedSince)]);
-		return mergeSubscriptionsRooms(subscriptions, rooms);
-	} catch (e) {
-		return getRoomRest.apply(this);
-	}
-};
-
 export default function() {
 	const { database: db } = database;
 
 	return new Promise(async(resolve, reject) => {
 		try {
-			const { subscriptions, rooms } = await (this.connected() ? getRoomDpp.apply(this) : getRoomRest.apply(this));
+			const updatedSince = lastMessage();
+			const [subscriptionsResult, roomsResult] = await (updatedSince
+				? Promise.all([SDK.api.get('subscriptions.get', { updatedSince }), SDK.api.get('rooms.get', { updatedSince })])
+				: Promise.all([SDK.api.get('subscriptions.get'), SDK.api.get('rooms.get')])
+			);
+			const { subscriptions, rooms } = mergeSubscriptionsRooms(subscriptionsResult, roomsResult);
 
 			const data = rooms.map(room => ({ room, sub: database.objects('subscriptions').filtered('rid == $0', room._id) }));
 
diff --git a/app/lib/methods/getSettings.js b/app/lib/methods/getSettings.js
index ace906851..38a79b09f 100644
--- a/app/lib/methods/getSettings.js
+++ b/app/lib/methods/getSettings.js
@@ -5,12 +5,7 @@ import reduxStore from '../createStore';
 import database from '../realm';
 import * as actions from '../../actions';
 import log from '../../utils/log';
-import { settingsUpdatedAt } from '../../constants/settings';
-
-const getLastUpdate = () => {
-	const [setting] = database.objects('settings').sorted('_updatedAt', true);
-	return setting && setting._updatedAt;
-};
+import settings from '../../constants/settings';
 
 function updateServer(param) {
 	database.databases.serversDB.write(() => {
@@ -20,19 +15,14 @@ function updateServer(param) {
 
 export default async function() {
 	try {
-		// if (!SDK.driver.dd) {
-		// 	// TODO: should implement loop or get from rest?
-		// 	return;
-		// }
-
-		const lastUpdate = getLastUpdate();
-		const fetchNewSettings = lastUpdate < settingsUpdatedAt;
-		const result = await ((!lastUpdate || fetchNewSettings)
-			? SDK.driver.asyncCall('public-settings/get')
-			: SDK.driver.asyncCall('public-settings/get', new Date(lastUpdate)));
-		const data = result.update || result || [];
+		const settingsParams = JSON.stringify(Object.keys(settings));
+		const result = await fetch(`${ SDK.api.url }settings.public?query={"_id":{"$in":${ settingsParams }}}`).then(response => response.json());
 
-		const filteredSettings = this._prepareSettings(this._filterSettings(data));
+		if (!result.success) {
+			return;
+		}
+		const data = result.settings || [];
+		const filteredSettings = this._prepareSettings(data.filter(item => item._id !== 'Assets_favicon_512'));
 
 		InteractionManager.runAfterInteractions(
 			() => database.write(
diff --git a/app/lib/methods/loadMessagesForRoom.js b/app/lib/methods/loadMessagesForRoom.js
index e53c73e5b..f20b57c6d 100644
--- a/app/lib/methods/loadMessagesForRoom.js
+++ b/app/lib/methods/loadMessagesForRoom.js
@@ -5,47 +5,28 @@ import buildMessage from './helpers/buildMessage';
 import database from '../realm';
 import log from '../../utils/log';
 
-// TODO: api fix
-const types = {
-	c: 'channels', d: 'im', p: 'groups'
-};
-
-async function loadMessagesForRoomRest({ rid: roomId, latest, t }) {
+async function load({ rid: roomId, latest, t }) {
+	let params = { roomId, count: 50 };
 	if (latest) {
-		latest = new Date(latest).toISOString();
+		params = { ...params, latest: new Date(latest).toISOString() };
 	}
-	const data = await SDK.api.get(`${ types[t] }.history`, { roomId, latest, count: 50 });
+	const data = await SDK.api.get(`${ this.roomTypeToApiType(t) }.history`, params);
 	if (!data || data.status === 'error') {
 		return [];
 	}
 	return data.messages;
 }
 
-async function loadMessagesForRoomDDP(...args) {
-	const [{ rid: roomId, latest }] = args;
-	try {
-		const data = await SDK.driver.asyncCall('loadHistory', roomId, latest, 50);
-		if (!data || !data.messages.length) {
-			return [];
-		}
-		return data.messages;
-	} catch (e) {
-		return loadMessagesForRoomRest.call(this, ...args);
-	}
-}
-
 export default function loadMessagesForRoom(...args) {
 	const { database: db } = database;
 	return new Promise(async(resolve, reject) => {
 		try {
-			const data = (await (this.connected()
-				? loadMessagesForRoomDDP.call(this, ...args)
-				: loadMessagesForRoomRest.call(this, ...args))).map(buildMessage);
+			const data = await load.call(this, ...args);
 
 			if (data && data.length) {
 				InteractionManager.runAfterInteractions(() => {
 					db.write(() => data.forEach((message) => {
-						db.create('messages', message, true);
+						db.create('messages', buildMessage(message), true);
 					}));
 					return resolve(data);
 				});
diff --git a/app/lib/methods/loadMissedMessages.js b/app/lib/methods/loadMissedMessages.js
index 69ae0f18b..0ad952cdc 100644
--- a/app/lib/methods/loadMissedMessages.js
+++ b/app/lib/methods/loadMissedMessages.js
@@ -5,7 +5,7 @@ import buildMessage from './helpers/buildMessage';
 import database from '../realm';
 import log from '../../utils/log';
 
-async function loadMissedMessagesRest({ rid: roomId, lastOpen }) {
+async function load({ rid: roomId, lastOpen }) {
 	let lastUpdate;
 	if (lastOpen) {
 		lastUpdate = new Date(lastOpen).toISOString();
@@ -16,22 +16,11 @@ async function loadMissedMessagesRest({ rid: roomId, lastOpen }) {
 	return result;
 }
 
-async function loadMissedMessagesDDP(...args) {
-	const [{ rid, lastOpen: lastUpdate }] = args;
-
-	try {
-		const result = await SDK.driver.asyncCall('messages/get', rid, { lastUpdate: new Date(lastUpdate), count: 50 });
-		return result;
-	} catch (e) {
-		return loadMissedMessagesRest.call(this, ...args);
-	}
-}
-
 export default function loadMissedMessages(...args) {
 	const { database: db } = database;
 	return new Promise(async(resolve, reject) => {
 		try {
-			const data = (await (this.connected() ? loadMissedMessagesDDP.call(this, ...args) : loadMissedMessagesRest.call(this, ...args)));
+			const data = (await load.call(this, ...args));
 
 			if (data) {
 				if (data.updated && data.updated.length) {
diff --git a/app/lib/methods/readMessages.js b/app/lib/methods/readMessages.js
index 7b298d7ce..1f4562b86 100644
--- a/app/lib/methods/readMessages.js
+++ b/app/lib/methods/readMessages.js
@@ -3,25 +3,12 @@ import * as SDK from '@rocket.chat/sdk';
 import database from '../realm';
 import log from '../../utils/log';
 
-const readMessagesREST = function readMessagesREST(rid) {
-	return SDK.api.post('subscriptions.read', { rid });
-};
-
-const readMessagesDDP = function readMessagesDDP(rid) {
-	try {
-		return SDK.driver.asyncCall('readMessages', rid);
-	} catch (e) {
-		return readMessagesREST.call(this, rid);
-	}
-};
-
 export default async function readMessages(rid) {
 	const ls = new Date();
-	const { database: db } = database;
 	try {
-		const data = await (this.connected() ? readMessagesDDP.call(this, rid) : readMessagesREST.call(this, rid));
-		const [subscription] = db.objects('subscriptions').filtered('rid = $0', rid);
-		db.write(() => {
+		const data = await SDK.api.post('subscriptions.read', { rid });
+		const [subscription] = database.objects('subscriptions').filtered('rid = $0', rid);
+		database.write(() => {
 			subscription.open = true;
 			subscription.alert = false;
 			subscription.unread = 0;
diff --git a/app/lib/methods/sendMessage.js b/app/lib/methods/sendMessage.js
index a21211128..21b620d97 100644
--- a/app/lib/methods/sendMessage.js
+++ b/app/lib/methods/sendMessage.js
@@ -1,4 +1,3 @@
-import Random from 'react-native-meteor/lib/Random';
 import * as SDK from '@rocket.chat/sdk';
 
 import messagesStatus from '../../constants/messagesStatus';
@@ -6,9 +5,10 @@ import buildMessage from './helpers/buildMessage';
 import database from '../realm';
 import reduxStore from '../createStore';
 import log from '../../utils/log';
+import random from '../../utils/random';
 
 export const getMessage = (rid, msg = {}) => {
-	const _id = Random.id();
+	const _id = random(17);
 	const message = {
 		_id,
 		rid,
@@ -31,21 +31,9 @@ export const getMessage = (rid, msg = {}) => {
 	return message;
 };
 
-function sendMessageByRest(args) {
-	return SDK.api.post('chat.sendMessage', { message: args });
-}
-
-function sendMessageByDDP(...args) {
-	try {
-		return SDK.driver.asyncCall('sendMessage', ...args);
-	} catch (error) {
-		return sendMessageByRest.call(this, ...args);
-	}
-}
-
-export async function _sendMessageCall(message) {
+export async function sendMessageCall(message) {
 	const { _id, rid, msg } = message;
-	const data = await (this.connected() ? sendMessageByDDP.call(this, { _id, rid, msg }) : sendMessageByRest.call(this, { _id, rid, msg }));
+	const data = await SDK.api.post('chat.sendMessage', { message: { _id, rid, msg } });
 	return data;
 }
 
@@ -55,12 +43,13 @@ export default async function(rid, msg) {
 		const message = getMessage(rid, msg);
 		const room = db.objects('subscriptions').filtered('rid == $0', rid);
 
+		// TODO: do we need this?
 		db.write(() => {
 			room.lastMessage = message;
 		});
 
 		try {
-			const ret = await _sendMessageCall.call(this, message);
+			const ret = await sendMessageCall.call(this, message);
 			db.write(() => {
 				db.create('messages', buildMessage({ ...message, ...ret }), true);
 			});
diff --git a/app/lib/methods/subscriptions/room.js b/app/lib/methods/subscriptions/room.js
index c718cdcfb..3f619ac73 100644
--- a/app/lib/methods/subscriptions/room.js
+++ b/app/lib/methods/subscriptions/room.js
@@ -7,9 +7,7 @@ const subscribe = rid => Promise.all([
 	SDK.driver.subscribe('stream-notify-room', `${ rid }/typing`, false),
 	SDK.driver.subscribe('stream-notify-room', `${ rid }/deleteMessage`, false)
 ]);
-const unsubscribe = subscriptions => subscriptions.forEach(sub => sub.unsubscribe().catch((e) => {
-	log('unsubscribeRoom', e);
-}));
+const unsubscribe = subscriptions => subscriptions.forEach(sub => sub.unsubscribe().catch(() => console.log('unsubscribeRoom')));
 
 let timer = null;
 let promises;
@@ -43,26 +41,26 @@ export default function subscribeRoom({ rid, t }) {
 		}, 5000);
 	};
 
-	if (!this.connected()) {
-		loop();
-	} else {
-		SDK.driver.on('logged', () => {
-			clearTimeout(timer);
-			timer = false;
-		});
+	// if (!this.connected()) {
+	// 	loop();
+	// } else {
+	SDK.driver.on('logged', () => {
+		clearTimeout(timer);
+		timer = false;
+	});
 
-		SDK.driver.on('disconnected', () => {
-			if (SDK.driver.userId) {
-				loop();
-			}
-		});
-
-		try {
-			promises = subscribe(rid);
-		} catch (e) {
-			log('subscribeRoom', e);
+	SDK.driver.on('disconnected', () => {
+		if (SDK.driver.userId) {
+			loop();
 		}
+	});
+
+	try {
+		promises = subscribe(rid);
+	} catch (e) {
+		log('subscribeRoom', e);
 	}
+	// }
 
 	return {
 		stop: () => stop()
diff --git a/app/lib/methods/subscriptions/rooms.js b/app/lib/methods/subscriptions/rooms.js
index e12cdc37b..65862c8a7 100644
--- a/app/lib/methods/subscriptions/rooms.js
+++ b/app/lib/methods/subscriptions/rooms.js
@@ -1,4 +1,3 @@
-import Random from 'react-native-meteor/lib/Random';
 import * as SDK from '@rocket.chat/sdk';
 
 import database from '../../realm';
@@ -6,6 +5,7 @@ import { merge } from '../helpers/mergeSubscriptionsRooms';
 import protectedFunction from '../helpers/protectedFunction';
 import messagesStatus from '../../../constants/messagesStatus';
 import log from '../../../utils/log';
+import random from '../../../utils/random';
 
 export default async function subscribeRooms(id) {
 	const promises = Promise.all([
@@ -30,85 +30,81 @@ export default async function subscribeRooms(id) {
 		}, 5000);
 	};
 
-	if (!this.connected()) {
-		loop();
-	} else {
-		SDK.driver.on('logged', () => {
-			clearTimeout(timer);
-			timer = false;
-		});
+	SDK.driver.on('logged', () => {
+		clearTimeout(timer);
+		timer = false;
+	});
 
-		SDK.driver.on('logout', () => {
-			clearTimeout(timer);
-			timer = true;
-		});
+	SDK.driver.on('logout', () => {
+		clearTimeout(timer);
+		timer = true;
+	});
 
-		SDK.driver.on('disconnected', () => {
-			if (SDK.driver.userId) {
-				loop();
-			}
-		});
+	SDK.driver.on('disconnected', () => {
+		if (SDK.driver.userId) {
+			loop();
+		}
+	});
 
-		SDK.driver.on('stream-notify-user', protectedFunction((e, ddpMessage) => {
-			if (!this.ddp || ddpMessage.msg === 'added') {
-				return;
-			}
-			const [type, data] = ddpMessage.fields.args;
-			const [, ev] = ddpMessage.fields.eventName.split('/');
-			if (/subscriptions/.test(ev)) {
-				if (type === 'removed') {
-					let messages = [];
-					const [subscription] = database.objects('subscriptions').filtered('_id == $0', data._id);
+	SDK.driver.on('stream-notify-user', protectedFunction((e, ddpMessage) => {
+		if (ddpMessage.msg === 'added') {
+			return;
+		}
+		const [type, data] = ddpMessage.fields.args;
+		const [, ev] = ddpMessage.fields.eventName.split('/');
+		if (/subscriptions/.test(ev)) {
+			if (type === 'removed') {
+				let messages = [];
+				const [subscription] = database.objects('subscriptions').filtered('_id == $0', data._id);
 
-					if (subscription) {
-						messages = database.objects('messages').filtered('rid == $0', subscription.rid);
-					}
-					database.write(() => {
-						database.delete(messages);
-						database.delete(subscription);
-					});
-				} else {
-					const rooms = database.objects('rooms').filtered('_id == $0', data.rid);
-					const tpm = merge(data, rooms[0]);
-					database.write(() => {
-						database.create('subscriptions', tpm, true);
-						database.delete(rooms);
-					});
+				if (subscription) {
+					messages = database.objects('messages').filtered('rid == $0', subscription.rid);
 				}
+				database.write(() => {
+					database.delete(messages);
+					database.delete(subscription);
+				});
+			} else {
+				const rooms = database.objects('rooms').filtered('_id == $0', data.rid);
+				const tpm = merge(data, rooms[0]);
+				database.write(() => {
+					database.create('subscriptions', tpm, true);
+					database.delete(rooms);
+				});
 			}
-			if (/rooms/.test(ev)) {
-				if (type === 'updated') {
-					const [sub] = database.objects('subscriptions').filtered('rid == $0', data._id);
-					database.write(() => {
-						merge(sub, data);
-					});
-				} else if (type === 'inserted') {
-					database.write(() => {
-						database.create('rooms', data, true);
-					});
-				}
+		}
+		if (/rooms/.test(ev)) {
+			if (type === 'updated') {
+				const [sub] = database.objects('subscriptions').filtered('rid == $0', data._id);
+				database.write(() => {
+					merge(sub, data);
+				});
+			} else if (type === 'inserted') {
+				database.write(() => {
+					database.create('rooms', data, true);
+				});
 			}
-			if (/message/.test(ev)) {
-				const [args] = ddpMessage.fields.args;
-				const _id = Random.id();
-				const message = {
+		}
+		if (/message/.test(ev)) {
+			const [args] = ddpMessage.fields.args;
+			const _id = random(17);
+			const message = {
+				_id,
+				rid: args.rid,
+				msg: args.msg,
+				ts: new Date(),
+				_updatedAt: new Date(),
+				status: messagesStatus.SENT,
+				u: {
 					_id,
-					rid: args.rid,
-					msg: args.msg,
-					ts: new Date(),
-					_updatedAt: new Date(),
-					status: messagesStatus.SENT,
-					u: {
-						_id,
-						username: 'rocket.cat'
-					}
-				};
-				requestAnimationFrame(() => database.write(() => {
-					database.create('messages', message, true);
-				}));
-			}
-		}));
-	}
+					username: 'rocket.cat'
+				}
+			};
+			requestAnimationFrame(() => database.write(() => {
+				database.create('messages', message, true);
+			}));
+		}
+	}));
 
 	try {
 		await promises;
diff --git a/app/lib/rocketchat.js b/app/lib/rocketchat.js
index df48e2753..85bfb584e 100644
--- a/app/lib/rocketchat.js
+++ b/app/lib/rocketchat.js
@@ -8,12 +8,11 @@ import defaultSettings from '../constants/settings';
 import messagesStatus from '../constants/messagesStatus';
 import database from './realm';
 import log from '../utils/log';
-// import * as actions from '../actions';
 
 import {
-	setUser, setLoginServices, loginRequest, loginSuccess, loginFailure, logout
+	setUser, setLoginServices, loginRequest, loginFailure, logout
 } from '../actions/login';
-import { disconnect, connectSuccess } from '../actions/connect';
+import { disconnect, connectSuccess, connectRequest } from '../actions/connect';
 import { setActiveUser } from '../actions/activeUsers';
 import { starredMessagesReceived, starredMessageUnstarred } from '../actions/starredMessages';
 import { pinnedMessagesReceived, pinnedMessageUnpinned } from '../actions/pinnedMessages';
@@ -39,7 +38,7 @@ import _buildMessage from './methods/helpers/buildMessage';
 import loadMessagesForRoom from './methods/loadMessagesForRoom';
 import loadMissedMessages from './methods/loadMissedMessages';
 
-import sendMessage, { getMessage, _sendMessageCall } from './methods/sendMessage';
+import sendMessage, { getMessage, sendMessageCall } from './methods/sendMessage';
 import { sendFileMessage, cancelUpload, isUploadActive } from './methods/sendFileMessage';
 
 import { getDeviceToken } from '../push';
@@ -124,320 +123,257 @@ const RocketChat = {
 			this.activeUsers[ddpMessage.id] = { ...this.activeUsers[ddpMessage.id], ...activeUser, ...ddpMessage.fields };
 		}
 	},
-	async loginSuccess(user) {
-		if (!user) {
-			const { user: u } = reduxStore.getState().login;
-			user = Object.assign({}, u);
-		}
+	loginSuccess({ user }) {
+		SDK.driver.login({ resume: user.token });
+		reduxStore.dispatch(setUser(user));
+		this.getRooms().catch(e => console.log(e));
+		this.getPermissions();
+		this.getCustomEmoji();
+		this.registerPushToken().then(result => console.log(result)).catch(e => alert(e));
+	},
+	connect({ server, user }) {
+		database.setActiveDB(server);
 
-		// TODO: one api call
-		// call /me only one time
-		try {
-			if (!user.username) {
-				// get me from api
-				let me = await SDK.api.get('me');
-				// if server didn't found username
-				if (!me.username) {
-					// search username from credentials (sent during registerSubmit)
-					const { username } = reduxStore.getState().login.credentials;
-					if (username) {
-						// set username
-						await RocketChat.setUsername({ username });
-						me = { ...me, username };
-					}
-				}
-				user = { ...user, ...me };
-			}
-		} catch (e) {
-			log('SDK.loginSuccess set username', e);
+		if (this.ddp) {
+			RocketChat.disconnect();
+			this.ddp = null;
 		}
 
-		try {
-			if (user.username) {
-				const userInfo = await SDK.api.get('users.info', { userId: user.id });
-				user = { ...user, ...userInfo.user };
-			}
+		SDK.api.setBaseUrl(server);
+		this.getSettings();
 
-			RocketChat.registerPushToken(user.id);
-			reduxStore.dispatch(setUser(user));
-			reduxStore.dispatch(loginSuccess(user));
-			this.ddp.subscribe('userData');
-		} catch (e) {
-			log('SDK.loginSuccess', e);
+		if (user && user.token) {
+			reduxStore.dispatch(loginRequest({ resume: user.token }));
 		}
-	},
-	connect(url, login) {
-		return new Promise(() => {
-			if (this.ddp) {
-				RocketChat.disconnect();
-				this.ddp = null;
-			}
 
-			SDK.api.setBaseUrl(url);
+		// Use useSsl: false only if server url starts with http://
+		const useSsl = !/http:\/\//.test(server);
 
-			if (login) {
-				SDK.api.setAuth({ authToken: login.token, userId: login.id });
-				RocketChat.setApiUser({ userId: login.id, authToken: login.token });
+		reduxStore.dispatch(connectRequest());
+		SDK.driver.connect({ host: server, useSsl }, (err, ddp) => {
+			if (err) {
+				return console.warn(err);
 			}
+			this.ddp = ddp;
+			if (user && user.token) {
+				SDK.driver.login({ resume: user.token });
+			}
+		});
 
-			SDK.driver.connect({ host: url, useSsl: true }, (err, ddp) => {
-				if (err) {
-					return console.warn(err);
-				}
-				this.ddp = ddp;
-				if (login) {
-					SDK.driver.login({ resume: login.resume });
-				}
-			});
-
-			SDK.driver.on('connected', () => {
-				reduxStore.dispatch(connectSuccess());
-				SDK.driver.subscribe('activeUsers');
-				SDK.driver.subscribe('roles');
-				RocketChat.getSettings();
-				RocketChat.getPermissions();
-				RocketChat.getCustomEmoji();
-			});
+		SDK.driver.on('connected', () => {
+			reduxStore.dispatch(connectSuccess());
+		});
 
-			SDK.driver.on('login', protectedFunction(() => reduxStore.dispatch(loginRequest())));
+		SDK.driver.on('disconnected', protectedFunction(() => {
+			reduxStore.dispatch(disconnect());
+		}));
 
-			SDK.driver.on('forbidden', protectedFunction(() => reduxStore.dispatch(logout())));
+		SDK.driver.on('logged', protectedFunction((error, u) => {
+			this.subscribeRooms(u.id);
+			SDK.driver.subscribe('activeUsers');
+			SDK.driver.subscribe('roles');
+		}));
 
-			SDK.driver.on('users', protectedFunction((error, ddpMessage) => RocketChat._setUser(ddpMessage)));
+		SDK.driver.on('forbidden', protectedFunction(() => reduxStore.dispatch(logout())));
 
-			// SDK.driver.on('background', () => this.getRooms().catch(e => log('background getRooms', e)));
+		SDK.driver.on('users', protectedFunction((error, ddpMessage) => RocketChat._setUser(ddpMessage)));
 
-			SDK.driver.on('logged', protectedFunction((error, user) => {
-				RocketChat.setApiUser({ userId: user.id, authToken: user.token });
-				this.loginSuccess(user);
-				this.getRooms().catch(e => log('logged getRooms', e));
-				this.subscribeRooms(user.id);
-			}));
+		SDK.driver.on('stream-room-messages', (error, ddpMessage) => {
+			// TODO: debounce
+			const message = _buildMessage(ddpMessage.fields.args[0]);
+			requestAnimationFrame(() => reduxStore.dispatch(roomMessageReceived(message)));
+		});
 
-			SDK.driver.on('disconnected', protectedFunction(() => {
-				reduxStore.dispatch(disconnect());
-			}));
+		SDK.driver.on('stream-notify-room', protectedFunction((error, ddpMessage) => {
+			const [_rid, ev] = ddpMessage.fields.eventName.split('/');
+			if (ev === 'typing') {
+				reduxStore.dispatch(someoneTyping({ _rid, username: ddpMessage.fields.args[0], typing: ddpMessage.fields.args[1] }));
+			} else if (ev === 'deleteMessage') {
+				database.write(() => {
+					if (ddpMessage && ddpMessage.fields && ddpMessage.fields.args.length > 0) {
+						const { _id } = ddpMessage.fields.args[0];
+						const message = database.objects('messages').filtered('_id = $0', _id);
+						database.delete(message);
+					}
+				});
+			}
+		}));
 
-			SDK.driver.on('stream-room-messages', (error, ddpMessage) => {
-				// TODO: debounce
-				const message = _buildMessage(ddpMessage.fields.args[0]);
-				requestAnimationFrame(() => reduxStore.dispatch(roomMessageReceived(message)));
-			});
+		SDK.driver.on('rocketchat_starred_message', protectedFunction((error, ddpMessage) => {
+			if (ddpMessage.msg === 'added') {
+				this.starredMessages = this.starredMessages || [];
 
-			SDK.driver.on('stream-notify-room', protectedFunction((error, ddpMessage) => {
-				const [_rid, ev] = ddpMessage.fields.eventName.split('/');
-				if (ev === 'typing') {
-					reduxStore.dispatch(someoneTyping({ _rid, username: ddpMessage.fields.args[0], typing: ddpMessage.fields.args[1] }));
-				} else if (ev === 'deleteMessage') {
-					database.write(() => {
-						if (ddpMessage && ddpMessage.fields && ddpMessage.fields.args.length > 0) {
-							const { _id } = ddpMessage.fields.args[0];
-							const message = database.objects('messages').filtered('_id = $0', _id);
-							database.delete(message);
-						}
-					});
+				if (this.starredMessagesTimer) {
+					clearTimeout(this.starredMessagesTimer);
+					this.starredMessagesTimer = null;
 				}
-			}));
 
-			SDK.driver.on('rocketchat_starred_message', protectedFunction((error, ddpMessage) => {
-				if (ddpMessage.msg === 'added') {
-					this.starredMessages = this.starredMessages || [];
+				this.starredMessagesTimer = setTimeout(protectedFunction(() => {
+					reduxStore.dispatch(starredMessagesReceived(this.starredMessages));
+					this.starredMessagesTimer = null;
+					return this.starredMessages = [];
+				}), 1000);
+				const message = ddpMessage.fields;
+				message._id = ddpMessage.id;
+				const starredMessage = _buildMessage(message);
+				this.starredMessages = [...this.starredMessages, starredMessage];
+			}
+			if (ddpMessage.msg === 'removed') {
+				if (reduxStore.getState().starredMessages.isOpen) {
+					return reduxStore.dispatch(starredMessageUnstarred(ddpMessage.id));
+				}
+			}
+		}));
 
-					if (this.starredMessagesTimer) {
-						clearTimeout(this.starredMessagesTimer);
-						this.starredMessagesTimer = null;
-					}
+		SDK.driver.on('rocketchat_pinned_message', protectedFunction((error, ddpMessage) => {
+			if (ddpMessage.msg === 'added') {
+				this.pinnedMessages = this.pinnedMessages || [];
 
-					this.starredMessagesTimer = setTimeout(protectedFunction(() => {
-						reduxStore.dispatch(starredMessagesReceived(this.starredMessages));
-						this.starredMessagesTimer = null;
-						return this.starredMessages = [];
-					}), 1000);
-					const message = ddpMessage.fields;
-					message._id = ddpMessage.id;
-					const starredMessage = _buildMessage(message);
-					this.starredMessages = [...this.starredMessages, starredMessage];
+				if (this.pinnedMessagesTimer) {
+					clearTimeout(this.pinnedMessagesTimer);
+					this.pinnedMessagesTimer = null;
 				}
-				if (ddpMessage.msg === 'removed') {
-					if (reduxStore.getState().starredMessages.isOpen) {
-						return reduxStore.dispatch(starredMessageUnstarred(ddpMessage.id));
-					}
-				}
-			}));
 
-			SDK.driver.on('rocketchat_pinned_message', protectedFunction((error, ddpMessage) => {
-				if (ddpMessage.msg === 'added') {
-					this.pinnedMessages = this.pinnedMessages || [];
+				this.pinnedMessagesTimer = setTimeout(() => {
+					reduxStore.dispatch(pinnedMessagesReceived(this.pinnedMessages));
+					this.pinnedMessagesTimer = null;
+					return this.pinnedMessages = [];
+				}, 1000);
+				const message = ddpMessage.fields;
+				message._id = ddpMessage.id;
+				const pinnedMessage = _buildMessage(message);
+				this.pinnedMessages = [...this.pinnedMessages, pinnedMessage];
+			}
+			if (ddpMessage.msg === 'removed') {
+				if (reduxStore.getState().pinnedMessages.isOpen) {
+					return reduxStore.dispatch(pinnedMessageUnpinned(ddpMessage.id));
+				}
+			}
+		}));
 
-					if (this.pinnedMessagesTimer) {
-						clearTimeout(this.pinnedMessagesTimer);
-						this.pinnedMessagesTimer = null;
-					}
+		SDK.driver.on('rocketchat_mentioned_message', protectedFunction((error, ddpMessage) => {
+			if (ddpMessage.msg === 'added') {
+				this.mentionedMessages = this.mentionedMessages || [];
 
-					this.pinnedMessagesTimer = setTimeout(() => {
-						reduxStore.dispatch(pinnedMessagesReceived(this.pinnedMessages));
-						this.pinnedMessagesTimer = null;
-						return this.pinnedMessages = [];
-					}, 1000);
-					const message = ddpMessage.fields;
-					message._id = ddpMessage.id;
-					const pinnedMessage = _buildMessage(message);
-					this.pinnedMessages = [...this.pinnedMessages, pinnedMessage];
-				}
-				if (ddpMessage.msg === 'removed') {
-					if (reduxStore.getState().pinnedMessages.isOpen) {
-						return reduxStore.dispatch(pinnedMessageUnpinned(ddpMessage.id));
-					}
+				if (this.mentionedMessagesTimer) {
+					clearTimeout(this.mentionedMessagesTimer);
+					this.mentionedMessagesTimer = null;
 				}
-			}));
 
-			SDK.driver.on('rocketchat_mentioned_message', protectedFunction((error, ddpMessage) => {
-				if (ddpMessage.msg === 'added') {
-					this.mentionedMessages = this.mentionedMessages || [];
+				this.mentionedMessagesTimer = setTimeout(() => {
+					reduxStore.dispatch(mentionedMessagesReceived(this.mentionedMessages));
+					this.mentionedMessagesTimer = null;
+					return this.mentionedMessages = [];
+				}, 1000);
+				const message = ddpMessage.fields;
+				message._id = ddpMessage.id;
+				const mentionedMessage = _buildMessage(message);
+				this.mentionedMessages = [...this.mentionedMessages, mentionedMessage];
+			}
+		}));
 
-					if (this.mentionedMessagesTimer) {
-						clearTimeout(this.mentionedMessagesTimer);
-						this.mentionedMessagesTimer = null;
-					}
+		SDK.driver.on('rocketchat_snippeted_message', protectedFunction((error, ddpMessage) => {
+			if (ddpMessage.msg === 'added') {
+				this.snippetedMessages = this.snippetedMessages || [];
 
-					this.mentionedMessagesTimer = setTimeout(() => {
-						reduxStore.dispatch(mentionedMessagesReceived(this.mentionedMessages));
-						this.mentionedMessagesTimer = null;
-						return this.mentionedMessages = [];
-					}, 1000);
-					const message = ddpMessage.fields;
-					message._id = ddpMessage.id;
-					const mentionedMessage = _buildMessage(message);
-					this.mentionedMessages = [...this.mentionedMessages, mentionedMessage];
+				if (this.snippetedMessagesTimer) {
+					clearTimeout(this.snippetedMessagesTimer);
+					this.snippetedMessagesTimer = null;
 				}
-			}));
 
-			SDK.driver.on('rocketchat_snippeted_message', protectedFunction((error, ddpMessage) => {
-				if (ddpMessage.msg === 'added') {
-					this.snippetedMessages = this.snippetedMessages || [];
+				this.snippetedMessagesTimer = setTimeout(() => {
+					reduxStore.dispatch(snippetedMessagesReceived(this.snippetedMessages));
+					this.snippetedMessagesTimer = null;
+					return this.snippetedMessages = [];
+				}, 1000);
+				const message = ddpMessage.fields;
+				message._id = ddpMessage.id;
+				const snippetedMessage = _buildMessage(message);
+				this.snippetedMessages = [...this.snippetedMessages, snippetedMessage];
+			}
+		}));
 
-					if (this.snippetedMessagesTimer) {
-						clearTimeout(this.snippetedMessagesTimer);
-						this.snippetedMessagesTimer = null;
-					}
+		SDK.driver.on('room_files', protectedFunction((error, ddpMessage) => {
+			if (ddpMessage.msg === 'added') {
+				this.roomFiles = this.roomFiles || [];
 
-					this.snippetedMessagesTimer = setTimeout(() => {
-						reduxStore.dispatch(snippetedMessagesReceived(this.snippetedMessages));
-						this.snippetedMessagesTimer = null;
-						return this.snippetedMessages = [];
-					}, 1000);
-					const message = ddpMessage.fields;
-					message._id = ddpMessage.id;
-					const snippetedMessage = _buildMessage(message);
-					this.snippetedMessages = [...this.snippetedMessages, snippetedMessage];
+				if (this.roomFilesTimer) {
+					clearTimeout(this.roomFilesTimer);
+					this.roomFilesTimer = null;
 				}
-			}));
-
-			SDK.driver.on('room_files', protectedFunction((error, ddpMessage) => {
-				if (ddpMessage.msg === 'added') {
-					this.roomFiles = this.roomFiles || [];
-
-					if (this.roomFilesTimer) {
-						clearTimeout(this.roomFilesTimer);
-						this.roomFilesTimer = null;
-					}
 
-					this.roomFilesTimer = setTimeout(() => {
-						reduxStore.dispatch(roomFilesReceived(this.roomFiles));
-						this.roomFilesTimer = null;
-						return this.roomFiles = [];
-					}, 1000);
-					const { fields } = ddpMessage;
-					const message = {
-						_id: ddpMessage.id,
-						ts: fields.uploadedAt,
-						msg: fields.description,
-						status: 0,
-						attachments: [{
-							title: fields.name
-						}],
-						urls: [],
-						reactions: [],
-						u: {
-							username: fields.user.username
-						}
-					};
-					const fileUrl = `/file-upload/${ ddpMessage.id }/${ fields.name }`;
-					if (/image/.test(fields.type)) {
-						message.attachments[0].image_type = fields.type;
-						message.attachments[0].image_url = fileUrl;
-					} else if (/audio/.test(fields.type)) {
-						message.attachments[0].audio_type = fields.type;
-						message.attachments[0].audio_url = fileUrl;
-					} else if (/video/.test(fields.type)) {
-						message.attachments[0].video_type = fields.type;
-						message.attachments[0].video_url = fileUrl;
+				this.roomFilesTimer = setTimeout(() => {
+					reduxStore.dispatch(roomFilesReceived(this.roomFiles));
+					this.roomFilesTimer = null;
+					return this.roomFiles = [];
+				}, 1000);
+				const { fields } = ddpMessage;
+				const message = {
+					_id: ddpMessage.id,
+					ts: fields.uploadedAt,
+					msg: fields.description,
+					status: 0,
+					attachments: [{
+						title: fields.name
+					}],
+					urls: [],
+					reactions: [],
+					u: {
+						username: fields.user.username
 					}
-					this.roomFiles = [...this.roomFiles, message];
+				};
+				const fileUrl = `/file-upload/${ ddpMessage.id }/${ fields.name }`;
+				if (/image/.test(fields.type)) {
+					message.attachments[0].image_type = fields.type;
+					message.attachments[0].image_url = fileUrl;
+				} else if (/audio/.test(fields.type)) {
+					message.attachments[0].audio_type = fields.type;
+					message.attachments[0].audio_url = fileUrl;
+				} else if (/video/.test(fields.type)) {
+					message.attachments[0].video_type = fields.type;
+					message.attachments[0].video_url = fileUrl;
 				}
-			}));
+				this.roomFiles = [...this.roomFiles, message];
+			}
+		}));
 
-			SDK.driver.on('rocketchat_roles', protectedFunction((error, ddpMessage) => {
-				this.roles = this.roles || {};
+		SDK.driver.on('rocketchat_roles', protectedFunction((error, ddpMessage) => {
+			this.roles = this.roles || {};
 
-				if (this.roleTimer) {
-					clearTimeout(this.roleTimer);
-					this.roleTimer = null;
-				}
-				this.roleTimer = setTimeout(() => {
-					reduxStore.dispatch(setRoles(this.roles));
+			if (this.roleTimer) {
+				clearTimeout(this.roleTimer);
+				this.roleTimer = null;
+			}
+			this.roleTimer = setTimeout(() => {
+				reduxStore.dispatch(setRoles(this.roles));
 
-					database.write(() => {
-						foreach(this.roles, (description, _id) => {
-							database.create('roles', { _id, description }, true);
-						});
+				database.write(() => {
+					foreach(this.roles, (description, _id) => {
+						database.create('roles', { _id, description }, true);
 					});
+				});
 
-					this.roleTimer = null;
-					return this.roles = {};
-				}, 1000);
-				this.roles[ddpMessage.id] = (ddpMessage.fields && ddpMessage.fields.description) || undefined;
-			}));
-
-			// SDK.driver.on('error', (err) => {
-			// 	log('SDK.onerror', err);
-			// 	reduxStore.dispatch(connectFailure());
-			// });
-
-			// SDK.driver.on('open', protectedFunction(() => {
-			// 	RocketChat.getSettings();
-			// 	RocketChat.getPermissions();
-			// 	reduxStore.dispatch(connectSuccess());
-			// 	resolve();
-			// }));
-
-			// this.ddp.once('open', protectedFunction(() => {
-			// 	this.ddp.subscribe('activeUsers');
-			// 	this.ddp.subscribe('roles');
-			// 	RocketChat.getCustomEmoji();
-			// }));
-		}).catch((e) => {
-			log('SDK.connect catch', e);
-		});
-	},
-	connected() {
-		return SDK.driver.ddp && SDK.driver.ddp._logged;
+				this.roleTimer = null;
+				return this.roles = {};
+			}, 1000);
+			this.roles[ddpMessage.id] = (ddpMessage.fields && ddpMessage.fields.description) || undefined;
+		}));
 	},
 
-	register({ credentials }) {
-		return call('registerUser', credentials);
+	register(credentials) {
+		return SDK.api.post('users.register', credentials, false);
 	},
 
-	setUsername({ username }) {
+	setUsername(username) {
 		return call('setUsername', username);
 	},
 
 	forgotPassword(email) {
-		return call('sendForgotPasswordEmail', email);
+		return SDK.api.post('users.forgotPassword', { email }, false);
 	},
 
-	async loginWithPassword({ username, password, code }) {
-		let params = { username, password };
+	async loginWithPassword({ user, password, code }) {
+		let params = { user, password };
 		const state = reduxStore.getState();
 
 		if (state.settings.LDAP_Enable) {
@@ -451,16 +387,12 @@ const RocketChat = {
 				...params,
 				crowd: true
 			};
-		} else if (typeof username === 'string' && username.indexOf('@') !== -1) {
-			params.email = username;
-			delete params.username;
 		}
 
 		if (code) {
 			params = {
 				...params,
-				code,
-				totp: true
+				code
 			};
 		}
 
@@ -471,59 +403,84 @@ const RocketChat = {
 		}
 	},
 
+	async loginOAuth(params) {
+		try {
+			const result = await SDK.driver.login(params);
+			reduxStore.dispatch(loginRequest({ resume: result.token }));
+		} catch (error) {
+			throw error;
+		}
+	},
+
 	async login(params) {
 		try {
-			await SDK.driver.login(params);
+			return await SDK.api.login(params);
 		} catch (e) {
 			reduxStore.dispatch(loginFailure(e));
 			throw e;
 		}
 	},
-	logout({ server }) {
+	async logout({ server }) {
+		// this.removePushToken().catch(error => console.log(error));
 		try {
-			RocketChat.disconnect();
-			SDK.driver.logout();
+			await this.removePushToken();
 		} catch (error) {
-			console.warn(error);
+			console.log('logout -> removePushToken -> catch -> error', error);
 		}
-		AsyncStorage.removeItem(TOKEN_KEY);
-		AsyncStorage.removeItem(`${ TOKEN_KEY }-${ server }`);
+		try {
+			await SDK.api.logout();
+		} catch (error) {
+			console.log('​logout -> api logout -> catch -> error', error);
+		}
+		SDK.driver.ddp.disconnect();
+		this.ddp = null;
+
+		Promise.all([
+			AsyncStorage.removeItem('currentServer'),
+			AsyncStorage.removeItem(TOKEN_KEY),
+			AsyncStorage.removeItem(`${ TOKEN_KEY }-${ server }`)
+		]).catch(error => console.log(error));
+
 		try {
 			database.deleteAll();
 		} catch (error) {
-			console.warn(error);
+			console.log(error);
 		}
 	},
 	disconnect() {
 		try {
 			SDK.driver.unsubscribeAll();
 		} catch (error) {
-			console.warn(error);
+			console.log(error);
 		}
 		RocketChat.setApiUser({ userId: null, authToken: null });
 	},
 	setApiUser({ userId, authToken }) {
 		SDK.api.setAuth({ userId, authToken });
-		SDK.api.currentLogin = { userId, authToken };
-	},
-	registerPushToken(userId) {
-		const deviceToken = getDeviceToken();
-		if (deviceToken) {
-			const key = Platform.OS === 'ios' ? 'apn' : 'gcm';
-			const data = {
-				id: `RocketChatRN${ userId }`,
-				token: { [key]: deviceToken },
-				appName: 'chat.rocket.reactnative', // TODO: try to get from config file
-				userId,
-				metadata: {}
-			};
-			return call('raix:push-update', data);
+		SDK.api.currentLogin = null;
+	},
+	registerPushToken() {
+		return new Promise((resolve) => {
+			const token = getDeviceToken();
+			if (token) {
+				const type = Platform.OS === 'ios' ? 'apn' : 'gcm';
+				const data = {
+					value: token,
+					type,
+					appName: 'chat.rocket.reactnative' // TODO: try to get from config file
+				};
+				return SDK.api.post('push.token', data);
+			}
+			return resolve();
+		});
+	},
+	removePushToken() {
+		const token = getDeviceToken();
+		if (token) {
+			return SDK.api.del('push.token', { token });
 		}
+		return Promise.resolve();
 	},
-
-	// updatePushToken(pushId) {
-	// 	return call('raix:push-setuser', pushId);
-	// },
 	loadMissedMessages,
 	loadMessagesForRoom,
 	getMessage,
@@ -532,11 +489,18 @@ const RocketChat = {
 	readMessages,
 	async resendMessage(messageId) {
 		const message = await database.objects('messages').filtered('_id = $0', messageId)[0];
-		database.write(() => {
-			message.status = messagesStatus.TEMP;
-			database.create('messages', message, true);
-		});
-		return _sendMessageCall.call(this, JSON.parse(JSON.stringify(message)));
+		try {
+			database.write(() => {
+				message.status = messagesStatus.TEMP;
+				database.create('messages', message, true);
+			});
+			await sendMessageCall.call(this, JSON.parse(JSON.stringify(message)));
+		} catch (error) {
+			database.write(() => {
+				message.status = messagesStatus.ERROR;
+				database.create('messages', message, true);
+			});
+		}
 	},
 
 	async search({ text, filterUsers = true, filterRooms = true }) {
@@ -596,10 +560,11 @@ const RocketChat = {
 	},
 
 	createDirectMessage(username) {
-		return call('createDirectMessage', username);
+		return SDK.api.post('im.create', { username });
 	},
-	joinRoom(rid) {
-		return call('joinRoom', rid);
+	joinRoom(roomId) {
+		// TODO: join code
+		return SDK.api.post('channels.join', { roomId });
 	},
 	sendFileMessage,
 	cancelUpload,
@@ -608,8 +573,7 @@ const RocketChat = {
 	getPermissions,
 	getCustomEmoji,
 	parseSettings: settings => settings.reduce((ret, item) => {
-		ret[item._id] = item[defaultSettings[item._id].type] || item.valueAsString || item.valueAsNumber
-			|| item.valueAsBoolean || item.value;
+		ret[item._id] = item[defaultSettings[item._id].type];
 		return ret;
 	}, {}),
 	_prepareSettings(settings) {
@@ -618,7 +582,6 @@ const RocketChat = {
 			return setting;
 		});
 	},
-	_filterSettings: settings => settings.filter(setting => defaultSettings[setting._id] && (setting.value || setting.valueAsString || setting.valueAsNumber || setting.valueAsBoolean)),
 	parseEmojis: emojis => emojis.reduce((ret, item) => {
 		ret[item.name] = item.extension;
 		item.aliases.forEach((alias) => {
@@ -633,20 +596,24 @@ const RocketChat = {
 		return emojis;
 	},
 	deleteMessage(message) {
-		return call('deleteMessage', { _id: message._id });
+		const { _id, rid } = message;
+		return SDK.api.post('chat.delete', { roomId: rid, msgId: _id });
 	},
 	editMessage(message) {
 		const { _id, msg, rid } = message;
-		return call('updateMessage', { _id, msg, rid });
+		return SDK.api.post('chat.update', { roomId: rid, msgId: _id, text: msg });
 	},
 	toggleStarMessage(message) {
-		return call('starMessage', { _id: message._id, rid: message.rid, starred: !message.starred });
+		if (message.starred) {
+			return SDK.api.post('chat.unStarMessage', { messageId: message._id });
+		}
+		return SDK.api.post('chat.starMessage', { messageId: message._id });
 	},
 	togglePinMessage(message) {
 		if (message.pinned) {
-			return call('unpinMessage', message);
+			return SDK.api.post('chat.unPinMessage', { messageId: message._id });
 		}
-		return call('pinMessage', message);
+		return SDK.api.post('chat.pinMessage', { messageId: message._id });
 	},
 	getRoom(rid) {
 		const [result] = database.objects('subscriptions').filtered('rid = $0', rid);
@@ -655,6 +622,9 @@ const RocketChat = {
 		}
 		return Promise.resolve(result);
 	},
+	getRoomInfo(roomId) {
+		return SDK.api.get('rooms.info', { roomId });
+	},
 	async getPermalink(message) {
 		let room;
 		try {
@@ -691,10 +661,10 @@ const RocketChat = {
 		return call('UserPresence:setDefaultStatus', status);
 	},
 	setReaction(emoji, messageId) {
-		return call('setReaction', emoji, messageId);
+		return SDK.api.post('chat.react', { emoji, messageId });
 	},
-	toggleFavorite(rid, f) {
-		return call('toggleFavorite', rid, !f);
+	toggleFavorite(roomId, favorite) {
+		return SDK.api.post('rooms.favorite', { roomId, favorite });
 	},
 	getRoomMembers(rid, allUsers) {
 		return call('getUsersOfRoom', rid, allUsers);
@@ -702,6 +672,9 @@ const RocketChat = {
 	getUserRoles() {
 		return call('getUserRoles');
 	},
+	getRoomCounters(roomId, t) {
+		return SDK.api.get(`${ this.roomTypeToApiType(t) }.counters`, { roomId });
+	},
 	async getRoomMember(rid, currentUserId) {
 		try {
 			const membersResult = await RocketChat.getRoomMembers(rid, true);
@@ -716,8 +689,8 @@ const RocketChat = {
 		}
 		return call('unblockUser', { rid, blocked });
 	},
-	leaveRoom(rid) {
-		return call('leaveRoom', rid);
+	leaveRoom(roomId, t) {
+		return SDK.api.post(`${ this.roomTypeToApiType(t) }.leave`, { roomId });
 	},
 	eraseRoom(rid) {
 		return call('eraseRoom', rid);
@@ -743,8 +716,8 @@ const RocketChat = {
 	saveUserPreferences(params) {
 		return call('saveUserPreferences', params);
 	},
-	saveNotificationSettings(rid, param, value) {
-		return call('saveNotificationSettings', rid, param, value);
+	saveNotificationSettings(roomId, notifications) {
+		return SDK.api.post('rooms.saveNotification', { roomId, notifications });
 	},
 	messageSearch(text, rid, limit) {
 		return call('messageSearch', text, rid, limit);
@@ -824,7 +797,13 @@ const RocketChat = {
 		}
 	},
 	getUsernameSuggestion() {
-		return SDK.driver.asyncCall('getUsernameSuggestion');
+		return SDK.api.get('users.getUsernameSuggestion');
+	},
+	roomTypeToApiType(t) {
+		const types = {
+			c: 'channels', d: 'im', p: 'groups'
+		};
+		return types[t];
 	}
 };
 
diff --git a/app/reducers/app.js b/app/reducers/app.js
index 7e0dec2a1..2e06cb67b 100644
--- a/app/reducers/app.js
+++ b/app/reducers/app.js
@@ -4,7 +4,6 @@ import { APP } from '../actions/actionsTypes';
 const initialState = {
 	root: null,
 	stackRoot: 'RoomsListView',
-	starting: true,
 	ready: false,
 	inactive: false,
 	background: false
@@ -46,14 +45,12 @@ export default function app(state = initialState, action) {
 		case APP.INIT:
 			return {
 				...state,
-				ready: false,
-				starting: true
+				ready: false
 			};
 		case APP.READY:
 			return {
 				...state,
-				ready: true,
-				starting: false
+				ready: true
 			};
 		default:
 			return state;
diff --git a/app/reducers/connect.js b/app/reducers/connect.js
index abfd142c1..324cb710a 100644
--- a/app/reducers/connect.js
+++ b/app/reducers/connect.js
@@ -2,10 +2,7 @@ import { METEOR } from '../actions/actionsTypes';
 
 const initialState = {
 	connecting: false,
-	connected: false,
-	errorMessage: '',
-	disconnected_by_user: false,
-	failure: false
+	connected: false
 };
 
 export default function connect(state = initialState, action) {
@@ -13,28 +10,13 @@ export default function connect(state = initialState, action) {
 		case METEOR.REQUEST:
 			return {
 				...state,
-				connecting: true,
-				disconnected_by_user: false
+				connecting: true
 			};
 		case METEOR.SUCCESS:
 			return {
 				...state,
 				connecting: false,
-				connected: true,
-				failure: false
-			};
-		case METEOR.FAILURE:
-			return {
-				...state,
-				connecting: false,
-				connected: false,
-				failure: true,
-				errorMessage: action.err
-			};
-		case METEOR.DISCONNECT_BY_USER:
-			return {
-				...state,
-				disconnected_by_user: true
+				connected: true
 			};
 		case METEOR.DISCONNECT:
 			return initialState;
diff --git a/app/reducers/login.js b/app/reducers/login.js
index ef222d06c..77c3c6f6d 100644
--- a/app/reducers/login.js
+++ b/app/reducers/login.js
@@ -3,11 +3,9 @@ import * as types from '../actions/actionsTypes';
 const initialState = {
 	isAuthenticated: false,
 	isFetching: false,
-	token: '',
 	user: {},
-	error: '',
-	services: {},
-	credentials: {}
+	error: {},
+	services: {}
 };
 
 export default function login(state = initialState, action) {
@@ -20,21 +18,16 @@ export default function login(state = initialState, action) {
 				isFetching: true,
 				isAuthenticated: false,
 				failure: false,
-				error: ''
+				error: {}
 			};
 		case types.LOGIN.SUCCESS:
 			return {
 				...state,
 				isFetching: false,
 				isAuthenticated: true,
-				user: {
-					...state.user,
-					...action.user
-				},
-				token: action.user.token,
+				user: action.user,
 				failure: false,
-				error: '',
-				credentials: {}
+				error: {}
 			};
 		case types.LOGIN.FAILURE:
 			return {
@@ -46,70 +39,12 @@ export default function login(state = initialState, action) {
 			};
 		case types.LOGOUT:
 			return initialState;
-		case types.LOGIN.SET_TOKEN:
-			return {
-				...state,
-				token: action.token,
-				user: action.user
-			};
-		case types.LOGIN.RESTORE_TOKEN:
-			return {
-				...state,
-				token: action.token
-			};
-		case types.LOGIN.REGISTER_SUBMIT:
-			return {
-				...state,
-				isFetching: true,
-				failure: false,
-				error: '',
-				credentials: action.credentials
-			};
-		case types.LOGIN.REGISTER_SUCCESS:
-			return {
-				...state,
-				isFetching: false,
-				failure: false,
-				error: '',
-				credentials: {}
-			};
-		case types.LOGIN.SET_USERNAME_SUBMIT:
-			return {
-				...state,
-				isFetching: true,
-				credentials: action.credentials
-			};
-		case types.LOGIN.SET_USERNAME_SUCCESS:
-			return {
-				...state,
-				isFetching: false
-			};
-		case types.FORGOT_PASSWORD.REQUEST:
-			return {
-				...state,
-				isFetching: true,
-				failure: false,
-				success: false
-			};
-		case types.FORGOT_PASSWORD.SUCCESS:
-			return {
-				...state,
-				isFetching: false,
-				success: true
-			};
-		case types.FORGOT_PASSWORD.FAILURE:
-			return {
-				...state,
-				isFetching: false,
-				failure: true,
-				error: action.err
-			};
 		case types.USER.SET:
 			return {
 				...state,
 				user: {
 					...state.user,
-					...action
+					...action.user
 				}
 			};
 		case types.LOGIN.SET_SERVICES:
diff --git a/app/reducers/sortPreferences.js b/app/reducers/sortPreferences.js
index d5cd2ba3d..eee86ea6d 100644
--- a/app/reducers/sortPreferences.js
+++ b/app/reducers/sortPreferences.js
@@ -2,9 +2,9 @@ import { SORT_PREFERENCES } from '../actions/actionsTypes';
 
 const initialState = {
 	sortBy: 'activity',
-	groupByType: true,
-	showFavorites: true,
-	showUnread: true
+	groupByType: false,
+	showFavorites: false,
+	showUnread: false
 };
 
 
diff --git a/app/sagas/connect.js b/app/sagas/connect.js
deleted file mode 100644
index bac42bbaa..000000000
--- a/app/sagas/connect.js
+++ /dev/null
@@ -1,50 +0,0 @@
-import {
-	call, takeLatest, select, put
-} from 'redux-saga/effects';
-import { AsyncStorage } from 'react-native';
-import { METEOR } from '../actions/actionsTypes';
-import RocketChat from '../lib/rocketchat';
-import { setToken } from '../actions/login';
-
-const getServer = ({ server }) => server.server;
-const getToken = function* getToken() {
-	const currentServer = yield select(getServer);
-	const user = yield call([AsyncStorage, 'getItem'], `${ RocketChat.TOKEN_KEY }-${ currentServer }`);
-	if (user) {
-		yield put(setToken(JSON.parse(user)));
-		try {
-			yield call([AsyncStorage, 'setItem'], RocketChat.TOKEN_KEY, JSON.parse(user).token || '');
-		} catch (error) {
-			console.warn('getToken', error);
-		}
-		return JSON.parse(user);
-	}
-
-	yield AsyncStorage.removeItem(RocketChat.TOKEN_KEY);
-	yield put(setToken());
-	return null;
-};
-
-
-const connect = (...args) => RocketChat.connect(...args);
-
-const test = function* test() {
-	try {
-		const server = yield select(getServer);
-		const user = yield call(getToken);
-		// const response =
-		// yield all([call(connect, server, user && user.token ? { resume: user.token, ...user.user } : undefined)]);// , put(loginRequest({ resume: user.token }))]);
-		yield call(connect, server, user && user.token ? { resume: user.token, ...user } : null);
-	// yield put(connectSuccess(response));
-	} catch (err) {
-		console.warn('test', err);
-	// yield put(connectFailure(err.status));
-	}
-};
-
-const root = function* root() {
-	yield takeLatest(METEOR.REQUEST, test);
-	// yield take(METEOR.SUCCESS, watchConnect);
-	// yield takeLatest(METEOR.SUCCESS, watchConnect);
-};
-export default root;
diff --git a/app/sagas/index.js b/app/sagas/index.js
index 7547ed382..d0e0d675d 100644
--- a/app/sagas/index.js
+++ b/app/sagas/index.js
@@ -1,6 +1,5 @@
 import { all } from 'redux-saga/effects';
 import login from './login';
-import connect from './connect';
 import rooms from './rooms';
 import messages from './messages';
 import selectServer from './selectServer';
@@ -20,7 +19,6 @@ const root = function* root() {
 		createChannel(),
 		rooms(),
 		login(),
-		connect(),
 		messages(),
 		selectServer(),
 		state(),
diff --git a/app/sagas/init.js b/app/sagas/init.js
index 022cba0be..6807ad032 100644
--- a/app/sagas/init.js
+++ b/app/sagas/init.js
@@ -1,44 +1,33 @@
 import { AsyncStorage } from 'react-native';
-import { call, put, takeLatest } from 'redux-saga/effects';
+import { put, takeLatest, all } from 'redux-saga/effects';
 
 import * as actions from '../actions';
 import { selectServerRequest } from '../actions/server';
-import { restoreToken, setUser } from '../actions/login';
 import { setAllPreferences } from '../actions/sortPreferences';
 import { APP } from '../actions/actionsTypes';
 import RocketChat from '../lib/rocketchat';
 import log from '../utils/log';
-import I18n from '../i18n';
 
 const restore = function* restore() {
 	try {
-		const token = yield call([AsyncStorage, 'getItem'], RocketChat.TOKEN_KEY);
-		if (token) {
-			yield put(restoreToken(token));
-		} else {
-			yield put(actions.appStart('outside'));
-		}
-
-		const currentServer = yield call([AsyncStorage, 'getItem'], 'currentServer');
-		if (currentServer) {
-			const user = yield call([AsyncStorage, 'getItem'], `${ RocketChat.TOKEN_KEY }-${ currentServer }`);
-			if (user) {
-				const userParsed = JSON.parse(user);
-				if (userParsed.language) {
-					I18n.locale = userParsed.language;
-				}
-				yield put(selectServerRequest(currentServer));
-				yield put(setUser(userParsed));
-			} else {
-				yield put(actions.appStart('outside'));
-			}
-		} else {
-			yield put(actions.appStart('outside'));
-		}
+		const { token, server } = yield all({
+			token: AsyncStorage.getItem(RocketChat.TOKEN_KEY),
+			server: AsyncStorage.getItem('currentServer')
+		});
 
 		const sortPreferences = yield RocketChat.getSortPreferences();
 		yield put(setAllPreferences(sortPreferences));
 
+		if (!token || !server) {
+			yield all([
+				AsyncStorage.removeItem(RocketChat.TOKEN_KEY),
+				AsyncStorage.removeItem('currentServer')
+			]);
+			yield put(actions.appStart('outside'));
+		} else if (server) {
+			yield put(selectServerRequest(server));
+		}
+
 		yield put(actions.appReady({}));
 	} catch (e) {
 		log('restore', e);
diff --git a/app/sagas/login.js b/app/sagas/login.js
index 480482643..6dad0566c 100644
--- a/app/sagas/login.js
+++ b/app/sagas/login.js
@@ -1,83 +1,68 @@
 import { AsyncStorage } from 'react-native';
-import { delay } from 'redux-saga';
 import {
-	put, call, takeLatest, select, all
+	put, call, takeLatest, select
 } from 'redux-saga/effects';
 import { Navigation } from 'react-native-navigation';
 
 import * as types from '../actions/actionsTypes';
 import { appStart } from '../actions';
 import { serverFinishAdd } from '../actions/server';
-import {
-	registerRequest,
-	loginFailure,
-	setUsernameRequest,
-	setUsernameSuccess,
-	forgotPasswordSuccess,
-	forgotPasswordFailure
-} from '../actions/login';
+import { loginFailure, loginSuccess } from '../actions/login';
 import RocketChat from '../lib/rocketchat';
 import log from '../utils/log';
 import I18n from '../i18n';
 
-const getUser = state => state.login.user;
 const getServer = state => state.server.server;
-
-const loginCall = args => RocketChat.loginWithPassword(args);
-const registerCall = args => RocketChat.register(args);
-const setUsernameCall = args => RocketChat.setUsername(args);
-const loginSuccessCall = () => RocketChat.loginSuccess();
+const loginWithPasswordCall = args => RocketChat.loginWithPassword(args);
+const loginCall = args => RocketChat.login(args);
 const logoutCall = args => RocketChat.logout(args);
-const forgotPasswordCall = args => RocketChat.forgotPassword(args);
 
-const handleLoginSuccess = function* handleLoginSuccess() {
+const handleLoginRequest = function* handleLoginRequest({ credentials }) {
 	try {
-		const user = yield select(getUser);
-		const adding = yield select(state => state.server.adding);
-		yield AsyncStorage.setItem(RocketChat.TOKEN_KEY, user.token);
-
-		if (!user.username) {
-			return yield put(appStart('setUsername'));
-		}
-
-		if (adding) {
-			yield put(serverFinishAdd());
-			yield Navigation.dismissAllModals();
+		let result;
+		if (credentials.resume) {
+			result = yield call(loginCall, credentials);
 		} else {
-			yield put(appStart('inside'));
+			result = yield call(loginWithPasswordCall, credentials);
+		}
+		if (result.status === 'success') {
+			const { data } = result;
+			const user = {
+				id: data.userId,
+				token: data.authToken,
+				username: data.me.username,
+				name: data.me.name,
+				language: data.me.language,
+				status: data.me.status
+			};
+			return yield put(loginSuccess(user));
 		}
-	} catch (e) {
-		log('handleLoginSuccess', e);
+	} catch (error) {
+		yield put(loginFailure(error));
 	}
 };
 
-const handleRegisterSubmit = function* handleRegisterSubmit({ credentials }) {
-	yield put(registerRequest(credentials));
-};
+const handleLoginSuccess = function* handleLoginSuccess({ user }) {
+	const adding = yield select(state => state.server.adding);
+	yield AsyncStorage.setItem(RocketChat.TOKEN_KEY, user.token);
 
-const handleRegisterRequest = function* handleRegisterRequest({ credentials }) {
+	const server = yield select(getServer);
 	try {
-		yield call(registerCall, { credentials });
-		yield call(loginCall, {
-			username: credentials.email,
-			password: credentials.pass
-		});
-	} catch (err) {
-		yield put(loginFailure(err));
+		RocketChat.loginSuccess({ user });
+		I18n.locale = user.language;
+		yield AsyncStorage.setItem(`${ RocketChat.TOKEN_KEY }-${ server }`, JSON.stringify(user));
+	} catch (error) {
+		console.log('loginSuccess saga -> error', error);
 	}
-};
 
-const handleSetUsernameSubmit = function* handleSetUsernameSubmit({ credentials }) {
-	yield put(setUsernameRequest(credentials));
-};
-
-const handleSetUsernameRequest = function* handleSetUsernameRequest({ credentials }) {
-	try {
-		yield call(setUsernameCall, credentials);
-		yield put(setUsernameSuccess());
-		yield call(loginSuccessCall);
-	} catch (err) {
-		yield put(loginFailure(err));
+	if (!user.username) {
+		RocketChat.loginSuccess({ user });
+		yield put(appStart('setUsername'));
+	} else if (adding) {
+		yield put(serverFinishAdd());
+		yield Navigation.dismissAllModals();
+	} else {
+		yield put(appStart('inside'));
 	}
 };
 
@@ -85,42 +70,24 @@ const handleLogout = function* handleLogout() {
 	const server = yield select(getServer);
 	if (server) {
 		try {
-			yield put(appStart('outside'));
 			yield call(logoutCall, { server });
+			yield put(appStart('outside'));
 		} catch (e) {
 			log('handleLogout', e);
 		}
 	}
 };
 
-const handleForgotPasswordRequest = function* handleForgotPasswordRequest({ email }) {
-	try {
-		yield call(forgotPasswordCall, email);
-		yield put(forgotPasswordSuccess());
-	} catch (err) {
-		yield put(forgotPasswordFailure(err));
-	}
-};
-
-const handleSetUser = function* handleSetUser() {
-	yield delay(2000);
-	const [server, user] = yield all([select(getServer), select(getUser)]);
-	if (user && user.id) {
-		if (user.language) {
-			I18n.locale = user.language;
-		}
-		yield AsyncStorage.setItem(`${ RocketChat.TOKEN_KEY }-${ server }`, JSON.stringify(user));
+const handleSetUser = function handleSetUser({ user }) {
+	if (user && user.language) {
+		I18n.locale = user.language;
 	}
 };
 
 const root = function* root() {
+	yield takeLatest(types.LOGIN.REQUEST, handleLoginRequest);
 	yield takeLatest(types.LOGIN.SUCCESS, handleLoginSuccess);
-	yield takeLatest(types.LOGIN.REGISTER_REQUEST, handleRegisterRequest);
-	yield takeLatest(types.LOGIN.REGISTER_SUBMIT, handleRegisterSubmit);
-	yield takeLatest(types.LOGIN.SET_USERNAME_SUBMIT, handleSetUsernameSubmit);
-	yield takeLatest(types.LOGIN.SET_USERNAME_REQUEST, handleSetUsernameRequest);
 	yield takeLatest(types.LOGOUT, handleLogout);
-	yield takeLatest(types.FORGOT_PASSWORD.REQUEST, handleForgotPasswordRequest);
 	yield takeLatest(types.USER.SET, handleSetUser);
 };
 export default root;
diff --git a/app/sagas/messages.js b/app/sagas/messages.js
index 01bda80c2..1cdafc66f 100644
--- a/app/sagas/messages.js
+++ b/app/sagas/messages.js
@@ -34,8 +34,7 @@ const get = function* get({ room }) {
 		}
 		yield put(messagesSuccess());
 	} catch (err) {
-		console.warn('messagesFailure', err);
-		yield put(messagesFailure(err.status));
+		yield put(messagesFailure(err));
 	}
 };
 
diff --git a/app/sagas/rooms.js b/app/sagas/rooms.js
index 7032b408f..1296fb3b2 100644
--- a/app/sagas/rooms.js
+++ b/app/sagas/rooms.js
@@ -3,37 +3,21 @@ import {
 	put, call, takeLatest, take, select, race, fork, cancel, takeEvery
 } from 'redux-saga/effects';
 import { delay } from 'redux-saga';
-import { BACKGROUND } from 'redux-enhancer-react-native-appstate';
 import { Navigation } from 'react-native-navigation';
 
 import * as types from '../actions/actionsTypes';
-// import { roomsSuccess, roomsFailure } from '../actions/rooms';
-import { addUserTyping, removeUserTyping, setLastOpen } from '../actions/room';
+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';
 
-const leaveRoom = rid => RocketChat.leaveRoom(rid);
 const eraseRoom = rid => RocketChat.eraseRoom(rid);
 
 let sub;
 let thread;
 
-// const getRooms = function* getRooms() {
-// 	return yield RocketChat.getRooms();
-// };
-
-// const watchRoomsRequest = function* watchRoomsRequest() {
-// 	try {
-// 		yield call(getRooms);
-// 		yield put(roomsSuccess());
-// 	} catch (err) {
-// 		yield put(roomsFailure(err.status));
-// 	}
-// };
-
 const cancelTyping = function* cancelTyping(username) {
 	while (true) {
 		const { typing, timeout } = yield race({
@@ -89,7 +73,13 @@ const watchRoomOpen = function* watchRoomOpen({ room }) {
 		if (room._id) {
 			RocketChat.readMessages(room.rid);
 		}
+
+		const auth = yield select(state => state.login.isAuthenticated);
+		if (!auth) {
+			yield take(types.LOGIN.SUCCESS);
+		}
 		sub = yield RocketChat.subscribeRoom(room);
+
 		thread = yield fork(usersTyping, { rid: room.rid });
 		yield race({
 			open: take(types.ROOM.OPEN),
@@ -129,20 +119,8 @@ const watchuserTyping = function* watchuserTyping({ status }) {
 	}
 };
 
-// const updateRoom = function* updateRoom() {
-// 	const room = yield select(state => state.room);
-// 	if (!room || !room.rid) {
-// 		return;
-// 	}
-// 	yield put(messagesRequest({ rid: room.rid }));
-// };
-
-const updateLastOpen = function* updateLastOpen() {
-	yield put(setLastOpen());
-};
-
-const goRoomsListAndDelete = function* goRoomsListAndDelete(rid, type) {
-	yield Navigation.popToRoot(type === 'erase' ? 'RoomActionsView' : 'RoomInfoEditView');
+const goRoomsListAndDelete = function* goRoomsListAndDelete(rid) {
+	yield Navigation.popToRoot('RoomsListView');
 	try {
 		database.write(() => {
 			const messages = database.objects('messages').filtered('rid = $0', rid);
@@ -155,16 +133,16 @@ const goRoomsListAndDelete = function* goRoomsListAndDelete(rid, type) {
 	}
 };
 
-const handleLeaveRoom = function* handleLeaveRoom({ rid }) {
+const handleLeaveRoom = function* handleLeaveRoom({ rid, t }) {
 	try {
 		sub.stop();
-		yield call(leaveRoom, rid);
-		yield goRoomsListAndDelete(rid, 'delete');
+		yield RocketChat.leaveRoom(rid, t);
+		yield goRoomsListAndDelete(rid);
 	} catch (e) {
-		if (e.error === 'error-you-are-last-owner') {
-			Alert.alert(I18n.t(e.error));
+		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('There_was_an_error_while_action', { action: I18n.t('leaving_room') }));
+			Alert.alert(I18n.t('Oops'), I18n.t('There_was_an_error_while_action', { action: I18n.t('leaving_room') }));
 		}
 	}
 };
@@ -172,10 +150,10 @@ const handleLeaveRoom = function* handleLeaveRoom({ rid }) {
 const handleEraseRoom = function* handleEraseRoom({ rid }) {
 	try {
 		sub.stop();
-		yield call(eraseRoom, rid);
+		yield eraseRoom(rid);
 		yield goRoomsListAndDelete(rid, 'erase');
 	} catch (e) {
-		Alert.alert(I18n.t('There_was_an_error_while_action', { action: I18n.t('erasing_room') }));
+		Alert.alert(I18n.t('Oops'), I18n.t('There_was_an_error_while_action', { action: I18n.t('erasing_room') }));
 	}
 };
 
@@ -183,9 +161,6 @@ const root = function* root() {
 	yield takeLatest(types.ROOM.USER_TYPING, watchuserTyping);
 	yield takeLatest(types.ROOM.OPEN, watchRoomOpen);
 	yield takeEvery(types.ROOM.MESSAGE_RECEIVED, handleMessageReceived);
-	// yield takeLatest(FOREGROUND, updateRoom);
-	// yield takeLatest(FOREGROUND, watchRoomsRequest);
-	yield takeLatest(BACKGROUND, updateLastOpen);
 	yield takeLatest(types.ROOM.LEAVE, handleLeaveRoom);
 	yield takeLatest(types.ROOM.ERASE, handleEraseRoom);
 };
diff --git a/app/sagas/selectServer.js b/app/sagas/selectServer.js
index 82f8d94cb..f3e9fd1d8 100644
--- a/app/sagas/selectServer.js
+++ b/app/sagas/selectServer.js
@@ -1,4 +1,4 @@
-import { put, call, takeLatest } from 'redux-saga/effects';
+import { put, takeLatest } from 'redux-saga/effects';
 import { AsyncStorage } from 'react-native';
 import { Navigation } from 'react-native-navigation';
 import { Provider } from 'react-redux';
@@ -6,9 +6,9 @@ import { gestureHandlerRootHOC } from 'react-native-gesture-handler';
 
 import { SERVER } from '../actions/actionsTypes';
 import * as actions from '../actions';
-import { connectRequest } from '../actions/connect';
 import { serverFailure, selectServerRequest, selectServerSuccess } from '../actions/server';
 import { setRoles } from '../actions/roles';
+import { setUser } from '../actions/login';
 import RocketChat from '../lib/rocketchat';
 import database from '../lib/realm';
 import log from '../utils/log';
@@ -19,16 +19,20 @@ let LoginView = null;
 
 const handleSelectServer = function* handleSelectServer({ server }) {
 	try {
-		yield database.setActiveDB(server);
-		yield put(connectRequest());
-		yield call([AsyncStorage, 'setItem'], 'currentServer', server);
-		const token = yield AsyncStorage.getItem(`${ RocketChat.TOKEN_KEY }-${ server }`);
-		if (token) {
+		yield AsyncStorage.setItem('currentServer', server);
+		const userStringified = yield AsyncStorage.getItem(`${ RocketChat.TOKEN_KEY }-${ server }`);
+
+		if (userStringified) {
+			const user = JSON.parse(userStringified);
+			yield put(setUser(user));
 			yield put(actions.appStart('inside'));
+			RocketChat.connect({ server, user });
+		} else {
+			RocketChat.connect({ server });
 		}
 
 		const settings = database.objects('settings');
-		yield put(actions.setAllSettings(RocketChat.parseSettings(RocketChat._filterSettings(settings.slice(0, settings.length)))));
+		yield put(actions.setAllSettings(RocketChat.parseSettings(settings.slice(0, settings.length))));
 		const emojis = database.objects('customEmojis');
 		yield put(actions.setCustomEmojis(RocketChat.parseEmojis(emojis.slice(0, emojis.length))));
 		const roles = database.objects('roles');
diff --git a/app/sagas/state.js b/app/sagas/state.js
index 20dc38d91..fa6adc599 100644
--- a/app/sagas/state.js
+++ b/app/sagas/state.js
@@ -1,8 +1,7 @@
 import { takeLatest, select } from 'redux-saga/effects';
-import { FOREGROUND, BACKGROUND, INACTIVE } from 'redux-enhancer-react-native-appstate';
+import { FOREGROUND, BACKGROUND } from 'redux-enhancer-react-native-appstate';
 
 import RocketChat from '../lib/rocketchat';
-import log from '../utils/log';
 import { setBadgeCount } from '../push';
 
 const appHasComeBackToForeground = function* appHasComeBackToForeground() {
@@ -18,7 +17,7 @@ const appHasComeBackToForeground = function* appHasComeBackToForeground() {
 		setBadgeCount();
 		return yield RocketChat.setUserPresenceOnline();
 	} catch (e) {
-		log('appHasComeBackToForeground', e);
+		console.log('appHasComeBackToForeground', e);
 	}
 };
 
@@ -34,7 +33,7 @@ const appHasComeBackToBackground = function* appHasComeBackToBackground() {
 	try {
 		return yield RocketChat.setUserPresenceAway();
 	} catch (e) {
-		log('appHasComeBackToBackground', e);
+		console.log('appHasComeBackToBackground', e);
 	}
 };
 
@@ -47,10 +46,10 @@ const root = function* root() {
 		BACKGROUND,
 		appHasComeBackToBackground
 	);
-	yield takeLatest(
-		INACTIVE,
-		appHasComeBackToBackground
-	);
+	// yield takeLatest(
+	// 	INACTIVE,
+	// 	appHasComeBackToBackground
+	// );
 };
 
 export default root;
diff --git a/app/utils/isValidEmail.js b/app/utils/isValidEmail.js
new file mode 100644
index 000000000..58cc9077b
--- /dev/null
+++ b/app/utils/isValidEmail.js
@@ -0,0 +1,5 @@
+export default function isValidEmail(email) {
+	/* eslint-disable no-useless-escape */
+	const reg = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
+	return reg.test(email);
+}
diff --git a/app/utils/log.js b/app/utils/log.js
index e1c98aef8..d59efad09 100644
--- a/app/utils/log.js
+++ b/app/utils/log.js
@@ -4,7 +4,7 @@ export default (event, error) => {
 	if (typeof error !== 'object') {
 		error = { error };
 	}
-	Answers.logCustom(event, error);
+	Answers.logCustom(event);
 	if (__DEV__) {
 		console.warn(event, error);
 	}
diff --git a/app/views/ForgotPasswordView.js b/app/views/ForgotPasswordView.js
index fc5e0178c..c099539ac 100644
--- a/app/views/ForgotPasswordView.js
+++ b/app/views/ForgotPasswordView.js
@@ -1,26 +1,21 @@
 import React from 'react';
 import PropTypes from 'prop-types';
 import { Text, ScrollView } from 'react-native';
-import { connect } from 'react-redux';
 import { Navigation } from 'react-native-navigation';
 import SafeAreaView from 'react-native-safe-area-view';
 
 import LoggedView from './View';
-import { forgotPasswordRequest as forgotPasswordRequestAction } from '../actions/login';
 import KeyboardView from '../presentation/KeyboardView';
 import TextInput from '../containers/TextInput';
 import Button from '../containers/Button';
 import sharedStyles from './Styles';
 import { showErrorAlert } from '../utils/info';
+import isValidEmail from '../utils/isValidEmail';
 import scrollPersistTaps from '../utils/scrollPersistTaps';
 import I18n from '../i18n';
 import { DARK_HEADER } from '../constants/headerOptions';
+import RocketChat from '../lib/rocketchat';
 
-@connect(state => ({
-	login: state.login
-}), dispatch => ({
-	forgotPasswordRequest: email => dispatch(forgotPasswordRequestAction(email))
-}))
 /** @extends React.Component */
 export default class ForgotPasswordView extends LoggedView {
 	static options() {
@@ -30,9 +25,7 @@ export default class ForgotPasswordView extends LoggedView {
 	}
 
 	static propTypes = {
-		componentId: PropTypes.string,
-		forgotPasswordRequest: PropTypes.func.isRequired,
-		login: PropTypes.object
+		componentId: PropTypes.string
 	}
 
 	constructor(props) {
@@ -40,7 +33,8 @@ export default class ForgotPasswordView extends LoggedView {
 
 		this.state = {
 			email: '',
-			invalidEmail: true
+			invalidEmail: true,
+			isFetching: false
 		};
 	}
 
@@ -50,16 +44,6 @@ export default class ForgotPasswordView extends LoggedView {
 		}, 600);
 	}
 
-	componentDidUpdate() {
-		const { login, componentId } = this.props;
-		if (login.success) {
-			Navigation.pop(componentId);
-			setTimeout(() => {
-				showErrorAlert(I18n.t('Forgot_password_If_this_email_is_registered'), I18n.t('Alert'));
-			});
-		}
-	}
-
 	componentWillUnmount() {
 		if (this.timeout) {
 			clearTimeout(this.timeout);
@@ -67,27 +51,35 @@ export default class ForgotPasswordView extends LoggedView {
 	}
 
 	validate = (email) => {
-		/* eslint-disable no-useless-escape */
-		const reg = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
-		if (!reg.test(email)) {
+		if (!isValidEmail(email)) {
 			this.setState({ invalidEmail: true });
 			return;
 		}
 		this.setState({ email, invalidEmail: false });
 	}
 
-	resetPassword = () => {
+	resetPassword = async() => {
 		const { email, invalidEmail } = this.state;
-		const { forgotPasswordRequest } = this.props;
 		if (invalidEmail || !email) {
 			return;
 		}
-		forgotPasswordRequest(email);
+		try {
+			this.setState({ isFetching: true });
+			const result = await RocketChat.forgotPassword(email);
+			if (result.success) {
+				const { componentId } = this.props;
+				Navigation.pop(componentId);
+				showErrorAlert(I18n.t('Forgot_password_If_this_email_is_registered'), I18n.t('Alert'));
+			}
+		} catch (e) {
+			const msg = (e.data && e.data.error) || I18n.t('There_was_an_error_while_action', I18n.t('resetting_password'));
+			showErrorAlert(msg, I18n.t('Alert'));
+		}
+		this.setState({ isFetching: false });
 	}
 
 	render() {
-		const { invalidEmail } = this.state;
-		const { login } = this.props;
+		const { invalidEmail, isFetching } = this.state;
 
 		return (
 			<KeyboardView
@@ -113,7 +105,7 @@ export default class ForgotPasswordView extends LoggedView {
 							type='primary'
 							onPress={this.resetPassword}
 							testID='forgot-password-view-submit'
-							loading={login.isFetching}
+							loading={isFetching}
 							disabled={invalidEmail}
 						/>
 					</SafeAreaView>
diff --git a/app/views/LoginSignupView.js b/app/views/LoginSignupView.js
index 92f1dfc15..084f9cc3c 100644
--- a/app/views/LoginSignupView.js
+++ b/app/views/LoginSignupView.js
@@ -95,8 +95,6 @@ const SERVICES_COLLAPSED_HEIGHT = 174;
 @connect(state => ({
 	server: state.server.server,
 	isFetching: state.login.isFetching,
-	Accounts_EmailOrUsernamePlaceholder: state.settings.Accounts_EmailOrUsernamePlaceholder,
-	Accounts_PasswordPlaceholder: state.settings.Accounts_PasswordPlaceholder,
 	Site_Name: state.settings.Site_Name,
 	services: state.login.services
 }))
@@ -120,16 +118,8 @@ export default class LoginSignupView extends LoggedView {
 		componentId: PropTypes.string,
 		isFetching: PropTypes.bool,
 		server: PropTypes.string,
-		Accounts_EmailOrUsernamePlaceholder: PropTypes.bool,
-		Accounts_PasswordPlaceholder: PropTypes.string,
-		Accounts_OAuth_Facebook: PropTypes.bool,
-		Accounts_OAuth_Github: PropTypes.bool,
-		Accounts_OAuth_Gitlab: PropTypes.bool,
-		Accounts_OAuth_Google: PropTypes.bool,
-		Accounts_OAuth_Linkedin: PropTypes.bool,
-		Accounts_OAuth_Meteor: PropTypes.bool,
-		Accounts_OAuth_Twitter: PropTypes.bool,
-		services: PropTypes.object
+		services: PropTypes.object,
+		Site_Name: PropTypes.string
 	}
 
 	constructor(props) {
diff --git a/app/views/LoginView.js b/app/views/LoginView.js
index 013e95711..1f6947f05 100644
--- a/app/views/LoginView.js
+++ b/app/views/LoginView.js
@@ -8,8 +8,8 @@ import { Navigation } from 'react-native-navigation';
 import { Answers } from 'react-native-fabric';
 import SafeAreaView from 'react-native-safe-area-view';
 import { gestureHandlerRootHOC } from 'react-native-gesture-handler';
+import equal from 'deep-equal';
 
-import RocketChat from '../lib/rocketchat';
 import KeyboardView from '../presentation/KeyboardView';
 import TextInput from '../containers/TextInput';
 import Button from '../containers/Button';
@@ -19,6 +19,7 @@ import LoggedView from './View';
 import I18n from '../i18n';
 import store from '../lib/createStore';
 import { DARK_HEADER } from '../constants/headerOptions';
+import { loginRequest as loginRequestAction } from '../actions/login';
 
 let RegisterView = null;
 let ForgotPasswordView = null;
@@ -52,11 +53,13 @@ const styles = StyleSheet.create({
 
 @connect(state => ({
 	isFetching: state.login.isFetching,
+	failure: state.login.failure,
+	error: state.login.error,
 	Site_Name: state.settings.Site_Name,
 	Accounts_EmailOrUsernamePlaceholder: state.settings.Accounts_EmailOrUsernamePlaceholder,
 	Accounts_PasswordPlaceholder: state.settings.Accounts_PasswordPlaceholder
-}), () => ({
-	loginSubmit: params => RocketChat.loginWithPassword(params)
+}), dispatch => ({
+	loginRequest: params => dispatch(loginRequestAction(params))
 }))
 /** @extends React.Component */
 export default class LoginView extends LoggedView {
@@ -76,18 +79,19 @@ export default class LoginView extends LoggedView {
 
 	static propTypes = {
 		componentId: PropTypes.string,
-		loginSubmit: PropTypes.func.isRequired,
-		login: PropTypes.object,
+		loginRequest: PropTypes.func.isRequired,
+		error: PropTypes.object,
 		Site_Name: PropTypes.string,
 		Accounts_EmailOrUsernamePlaceholder: PropTypes.string,
 		Accounts_PasswordPlaceholder: PropTypes.string,
-		isFetching: PropTypes.bool
+		isFetching: PropTypes.bool,
+		failure: PropTypes.bool
 	}
 
 	constructor(props) {
 		super('LoginView', props);
 		this.state = {
-			username: '',
+			user: '',
 			password: '',
 			code: '',
 			showTOTP: false
@@ -103,10 +107,22 @@ export default class LoginView extends LoggedView {
 		}, 600);
 	}
 
-	componentDidUpdate(prevProps) {
-		const { componentId, Site_Name } = this.props;
-		if (Site_Name && prevProps.Site_Name !== Site_Name) {
-			this.setTitle(componentId, Site_Name);
+	componentWillReceiveProps(nextProps) {
+		const { componentId, Site_Name, error } = this.props;
+		if (Site_Name && nextProps.Site_Name !== Site_Name) {
+			this.setTitle(componentId, nextProps.Site_Name);
+		} else if (nextProps.failure && !equal(error, nextProps.error)) {
+			if (nextProps.error && nextProps.error.error === 'totp-required') {
+				LayoutAnimation.easeInEaseOut();
+				this.setState({ showTOTP: true });
+				setTimeout(() => {
+					if (this.codeInput && this.codeInput.focus) {
+						this.codeInput.focus();
+					}
+				}, 300);
+				return;
+			}
+			Alert.alert(I18n.t('Oops'), I18n.t('Login_error'));
 		}
 	}
 
@@ -147,12 +163,12 @@ export default class LoginView extends LoggedView {
 
 	valid = () => {
 		const {
-			username, password, code, showTOTP
+			user, password, code, showTOTP
 		} = this.state;
 		if (showTOTP) {
 			return code.trim();
 		}
-		return username.trim() && password.trim();
+		return user.trim() && password.trim();
 	}
 
 	submit = async() => {
@@ -160,12 +176,12 @@ export default class LoginView extends LoggedView {
 			return;
 		}
 
-		const {	username, password, code } = this.state;
-		const { loginSubmit } = this.props;
+		const { user, password, code } = this.state;
+		const { loginRequest } = this.props;
 		Keyboard.dismiss();
 
 		try {
-			await loginSubmit({ username, password, code });
+			await loginRequest({ user, password, code });
 			Answers.logLogin('Email', true);
 		} catch (e) {
 			if (e && e.error === 'totp-required') {
@@ -265,7 +281,7 @@ export default class LoginView extends LoggedView {
 					keyboardType='email-address'
 					returnKeyType='next'
 					iconLeft='mention'
-					onChangeText={value => this.setState({ username: value })}
+					onChangeText={value => this.setState({ user: value })}
 					onSubmitEditing={() => { this.passwordInput.focus(); }}
 					testID='login-view-email'
 				/>
diff --git a/app/views/OAuthView.js b/app/views/OAuthView.js
index 16497f053..c5af7cd13 100644
--- a/app/views/OAuthView.js
+++ b/app/views/OAuthView.js
@@ -37,6 +37,9 @@ export default class OAuthView extends React.PureComponent {
 
 	constructor(props) {
 		super(props);
+		this.state = {
+			logging: false
+		};
 		this.redirectRegex = new RegExp(`(?=.*(${ props.server }))(?=.*(credentialToken))(?=.*(credentialSecret))`, 'g');
 		Navigation.events().bindComponent(this);
 	}
@@ -53,11 +56,20 @@ export default class OAuthView extends React.PureComponent {
 	}
 
 	login = async(params) => {
+		const { logging } = this.state;
+		if (logging) {
+			return;
+		}
+
+		this.setState({ logging: true });
+
 		try {
-			await RocketChat.login(params);
+			await RocketChat.loginOAuth(params);
 		} catch (e) {
 			console.warn(e);
 		}
+		this.setState({ logging: false });
+		this.dismiss();
 	}
 
 	render() {
@@ -72,7 +84,6 @@ export default class OAuthView extends React.PureComponent {
 						const parts = url.split('#');
 						const credentials = JSON.parse(parts[1]);
 						this.login({ oauth: { ...credentials } });
-						this.dismiss();
 					}
 				}}
 			/>
diff --git a/app/views/RegisterView.js b/app/views/RegisterView.js
index 1c623cf07..debd84e93 100644
--- a/app/views/RegisterView.js
+++ b/app/views/RegisterView.js
@@ -7,9 +7,7 @@ import { connect, Provider } from 'react-redux';
 import { Navigation } from 'react-native-navigation';
 import SafeAreaView from 'react-native-safe-area-view';
 import { gestureHandlerRootHOC } from 'react-native-gesture-handler';
-import equal from 'deep-equal';
 
-import { registerSubmit as registerSubmitAction } from '../actions/login';
 import TextInput from '../containers/TextInput';
 import Button from '../containers/Button';
 import KeyboardView from '../presentation/KeyboardView';
@@ -19,16 +17,16 @@ import LoggedView from './View';
 import I18n from '../i18n';
 import store from '../lib/createStore';
 import { DARK_HEADER } from '../constants/headerOptions';
+import RocketChat from '../lib/rocketchat';
+import { loginRequest as loginRequestAction } from '../actions/login';
+import isValidEmail from '../utils/isValidEmail';
 
 let TermsServiceView = null;
 let PrivacyPolicyView = null;
 let LegalView = null;
 
-@connect(state => ({
-	server: state.server.server,
-	login: state.login
-}), dispatch => ({
-	registerSubmit: params => dispatch(registerSubmitAction(params))
+@connect(null, dispatch => ({
+	loginRequest: params => dispatch(loginRequestAction(params))
 }))
 /** @extends React.Component */
 export default class RegisterView extends LoggedView {
@@ -48,13 +46,7 @@ export default class RegisterView extends LoggedView {
 
 	static propTypes = {
 		componentId: PropTypes.string,
-		server: PropTypes.string,
-		registerSubmit: PropTypes.func.isRequired,
-		Accounts_UsernamePlaceholder: PropTypes.string,
-		Accounts_NamePlaceholder: PropTypes.string,
-		Accounts_EmailOrUsernamePlaceholder: PropTypes.string,
-		Accounts_PasswordPlaceholder: PropTypes.string,
-		login: PropTypes.object
+		loginRequest: PropTypes.func
 	}
 
 	constructor(props) {
@@ -63,7 +55,8 @@ export default class RegisterView extends LoggedView {
 			name: '',
 			email: '',
 			password: '',
-			username: ''
+			username: '',
+			saving: false
 		};
 		Navigation.events().bindComponent(this);
 	}
@@ -75,10 +68,8 @@ export default class RegisterView extends LoggedView {
 	}
 
 	componentDidUpdate(prevProps) {
-		const { login, componentId, Site_Name } = this.props;
-		if (login && login.failure && login.error && !equal(login.error, prevProps.login.error)) {
-			Alert.alert(I18n.t('Oops'), login.error.reason);
-		} else if (Site_Name && prevProps.Site_Name !== Site_Name) {
+		const { componentId, Site_Name } = this.props;
+		if (Site_Name && prevProps.Site_Name !== Site_Name) {
 			this.setTitle(componentId, Site_Name);
 		}
 	}
@@ -122,26 +113,30 @@ export default class RegisterView extends LoggedView {
 		const {
 			name, email, password, username
 		} = this.state;
-		return name.trim() && email.trim() && password.trim() && username.trim();
+		return name.trim() && email.trim() && password.trim() && username.trim() && isValidEmail(email);
 	}
 
-	invalidEmail = () => {
-		const { login } = this.props;
-		return login.failure && /Email/.test(login.error && login.error.reason) ? login.error : {};
-	}
-
-	submit = () => {
+	submit = async() => {
 		if (!this.valid()) {
 			return;
 		}
+		this.setState({ saving: true });
+		Keyboard.dismiss();
+
 		const {
 			name, email, password, username
 		} = this.state;
-		const { registerSubmit } = this.props;
-		registerSubmit({
-			name, email, pass: password, username
-		});
-		Keyboard.dismiss();
+		const { loginRequest } = this.props;
+
+		try {
+			await RocketChat.register({
+				name, email, pass: password, username
+			});
+			await loginRequest({ user: email, password });
+		} catch (e) {
+			Alert.alert(I18n.t('Oops'), e.data.error);
+		}
+		this.setState({ saving: false });
 	}
 
 	termsService = () => {
@@ -187,7 +182,7 @@ export default class RegisterView extends LoggedView {
 	}
 
 	render() {
-		const { login } = this.props;
+		const { saving } = this.state;
 		return (
 			<KeyboardView contentContainerStyle={sharedStyles.container}>
 				<ScrollView {...scrollPersistTaps} contentContainerStyle={sharedStyles.containerScrollView}>
@@ -219,7 +214,6 @@ export default class RegisterView extends LoggedView {
 							iconLeft='mail'
 							onChangeText={email => this.setState({ email })}
 							onSubmitEditing={() => { this.passwordInput.focus(); }}
-							error={this.invalidEmail()}
 							testID='register-view-email'
 						/>
 						<TextInput
@@ -240,7 +234,7 @@ export default class RegisterView extends LoggedView {
 							onPress={this.submit}
 							testID='register-view-submit'
 							disabled={!this.valid()}
-							loading={login.isFetching}
+							loading={saving}
 						/>
 					</SafeAreaView>
 				</ScrollView>
diff --git a/app/views/RoomActionsView/index.js b/app/views/RoomActionsView/index.js
index 7a059d54d..329a91895 100644
--- a/app/views/RoomActionsView/index.js
+++ b/app/views/RoomActionsView/index.js
@@ -35,7 +35,7 @@ const modules = {};
 	username: state.login.user && state.login.user.username,
 	baseUrl: state.settings.Site_Url || state.server ? state.server.server : ''
 }), dispatch => ({
-	leaveRoom: rid => dispatch(leaveRoomAction(rid))
+	leaveRoom: (rid, t) => dispatch(leaveRoomAction(rid, t))
 }))
 /** @extends React.Component */
 export default class RoomActionsView extends LoggedView {
@@ -67,16 +67,26 @@ export default class RoomActionsView extends LoggedView {
 		this.rooms = database.objects('subscriptions').filtered('rid = $0', rid);
 		this.state = {
 			room: this.rooms[0] || {},
-			onlineMembers: [],
-			allMembers: [],
+			membersCount: 0,
 			member: {}
 		};
 	}
 
 	async componentDidMount() {
+		const { room } = this.state;
+		if (room && room.t !== 'd' && this.canViewMembers) {
+			const { rid } = this.props;
+			try {
+				const counters = await RocketChat.getRoomCounters(rid, room.t);
+				if (counters.success) {
+					this.setState({ membersCount: counters.members, joined: counters.joined });
+				}
+			} catch (error) {
+				console.log('RoomActionsView -> getRoomCounters -> error', error);
+			}
+		}
+
 		this.rooms.addListener(this.updateRoom);
-		const [members, member] = await Promise.all([this.updateRoomMembers(), this.updateRoomMember()]);
-		this.setState({ ...members, ...member });
 	}
 
 	componentWillUnmount() {
@@ -96,10 +106,6 @@ export default class RoomActionsView extends LoggedView {
 					name: item.route,
 					passProps: item.params
 				}
-				// screen: item.route,
-				// title: item.name,
-				// passProps: item.params,
-				// backButtonTitle: ''
 			});
 		}
 		if (item.event) {
@@ -108,12 +114,10 @@ export default class RoomActionsView extends LoggedView {
 	}
 
 	get canAddUser() {
-		const { allMembers, room } = this.state;
-		const { username } = this.props;
+		const { room, joined } = this.state;
 		const { rid, t } = room;
 
-		// TODO: same test joined
-		const userInRoom = !!allMembers.find(m => m.username === username);
+		const userInRoom = joined;
 		const permissions = RocketChat.hasPermission(['add-user-to-joined-room', 'add-user-to-any-c-room', 'add-user-to-any-p-room'], rid);
 
 		if (userInRoom && permissions['add-user-to-joined-room']) {
@@ -138,11 +142,16 @@ export default class RoomActionsView extends LoggedView {
 				return false;
 			}
 		}
-		return (t === 'c' || t === 'p');
+
+		// This method is executed only in componentDidMount and returns a value
+		// We save the state to read in render
+		const result = (t === 'c' || t === 'p');
+		this.setState({ canViewMembers: result });
+		return result;
 	}
 
 	get sections() {
-		const { onlineMembers, room } = this.state;
+		const { room, membersCount, canViewMembers } = this.state;
 		const {
 			rid, t, blocker, notifications
 		} = room;
@@ -255,15 +264,13 @@ export default class RoomActionsView extends LoggedView {
 		} else if (t === 'c' || t === 'p') {
 			const actions = [];
 
-			if (this.canViewMembers) {
+			if (canViewMembers) {
 				actions.push({
 					icon: 'ios-people',
 					name: I18n.t('Members'),
-					description: (onlineMembers.length === 1
-						? I18n.t('1_online_member')
-						: I18n.t('N_online_members', { n: onlineMembers.length })),
+					description: `${ membersCount } ${ I18n.t('members') }`,
 					route: 'RoomMembersView',
-					params: { rid, members: onlineMembers },
+					params: { rid },
 					testID: 'room-actions-members',
 					require: () => require('../RoomMembersView').default
 				});
@@ -299,47 +306,6 @@ export default class RoomActionsView extends LoggedView {
 		return sections;
 	}
 
-	updateRoomMembers = async() => {
-		const { room } = this.state;
-		const { rid, t } = room;
-
-		if (!this.canViewMembers) {
-			return {};
-		}
-
-		if (t === 'c' || t === 'p') {
-			let onlineMembers = [];
-			let allMembers = [];
-			try {
-				const onlineMembersCall = RocketChat.getRoomMembers(rid, false);
-				const allMembersCall = RocketChat.getRoomMembers(rid, true);
-				const [onlineMembersResult, allMembersResult] = await Promise.all([onlineMembersCall, allMembersCall]);
-				onlineMembers = onlineMembersResult.records;
-				allMembers = allMembersResult.records;
-				return { onlineMembers, allMembers };
-			} catch (error) {
-				return {};
-			}
-		}
-	}
-
-	updateRoomMember = async() => {
-		const { room } = this.state;
-		const { rid, t } = room;
-		const { userId } = this.props;
-
-		if (t !== 'd') {
-			return {};
-		}
-		try {
-			const member = await RocketChat.getRoomMember(rid, userId);
-			return { member };
-		} catch (e) {
-			log('RoomActions updateRoomMember', e);
-			return {};
-		}
-	}
-
 	updateRoom = () => {
 		this.setState({ room: this.rooms[0] || {} });
 	}
@@ -370,7 +336,7 @@ export default class RoomActionsView extends LoggedView {
 				{
 					text: I18n.t('Yes_action_it', { action: I18n.t('leave') }),
 					style: 'destructive',
-					onPress: () => leaveRoom(room.rid)
+					onPress: () => leaveRoom(room.rid, room.t)
 				}
 			]
 		);
@@ -379,7 +345,10 @@ export default class RoomActionsView extends LoggedView {
 	toggleNotifications = () => {
 		const { room } = this.state;
 		try {
-			RocketChat.saveNotificationSettings(room.rid, 'mobilePushNotifications', room.notifications ? 'default' : 'nothing');
+			const notifications = {
+				mobilePushNotifications: room.notifications ? 'default' : 'nothing'
+			};
+			RocketChat.saveNotificationSettings(room.rid, notifications);
 		} catch (e) {
 			log('toggleNotifications', e);
 		}
diff --git a/app/views/RoomInfoView/index.js b/app/views/RoomInfoView/index.js
index 66a0fae0f..00d41e966 100644
--- a/app/views/RoomInfoView/index.js
+++ b/app/views/RoomInfoView/index.js
@@ -154,7 +154,7 @@ export default class RoomInfoView extends LoggedView {
 			if (room.t === 'd') {
 				try {
 					const roomUser = await RocketChat.getRoomMember(room.rid, userId);
-					this.setState({ roomUser });
+					this.setState({ roomUser: roomUser || {} });
 					const username = room.name;
 
 					const activeUser = activeUsers[roomUser._id];
diff --git a/app/views/RoomMembersView/index.js b/app/views/RoomMembersView/index.js
index e9b42173a..744be6541 100644
--- a/app/views/RoomMembersView/index.js
+++ b/app/views/RoomMembersView/index.js
@@ -67,12 +67,13 @@ export default class RoomMembersView extends LoggedView {
 			members,
 			membersFiltered: [],
 			userLongPressed: {},
-			room: {}
+			room: this.rooms[0] || {}
 		};
 		Navigation.events().bindComponent(this);
 	}
 
 	componentDidMount() {
+		this.fetchMembers();
 		this.rooms.addListener(this.updateRoom);
 	}
 
@@ -91,7 +92,8 @@ export default class RoomMembersView extends LoggedView {
 						rightButtons: [{
 							id: 'toggleOnline',
 							text: allUsers ? I18n.t('Online') : I18n.t('All'),
-							testID: 'room-members-view-toggle-status'
+							testID: 'room-members-view-toggle-status',
+							color: Platform.OS === 'android' ? '#FFF' : undefined
 						}]
 					}
 				});
@@ -121,8 +123,10 @@ export default class RoomMembersView extends LoggedView {
 			if (subscriptions.length) {
 				this.goRoom({ rid: subscriptions[0].rid });
 			} else {
-				const room = await RocketChat.createDirectMessage(item.username);
-				this.goRoom({ rid: room.rid });
+				const result = await RocketChat.createDirectMessage(item.username);
+				if (result.success) {
+					this.goRoom({ rid: result.room._id });
+				}
 			}
 		} catch (e) {
 			log('onPressUser', e);
@@ -151,6 +155,13 @@ export default class RoomMembersView extends LoggedView {
 		}
 	}
 
+	fetchMembers = async(status) => {
+		const { rid } = this.state;
+		const membersResult = await RocketChat.getRoomMembers(rid, status);
+		const members = membersResult.records;
+		this.setState({ allUsers: status, members });
+	}
+
 	updateRoom = async() => {
 		const [room] = this.rooms;
 		await this.setState({ room });
diff --git a/app/views/RoomView/ListView.js b/app/views/RoomView/ListView.js
index a30fc01a6..6f11d236c 100644
--- a/app/views/RoomView/ListView.js
+++ b/app/views/RoomView/ListView.js
@@ -32,7 +32,8 @@ export class List extends React.Component {
 		renderFooter: PropTypes.func,
 		renderRow: PropTypes.func,
 		room: PropTypes.string,
-		end: PropTypes.bool
+		end: PropTypes.bool,
+		loadingMore: PropTypes.bool
 	};
 
 	constructor(props) {
@@ -49,8 +50,8 @@ export class List extends React.Component {
 	}
 
 	shouldComponentUpdate(nextProps) {
-		const { end } = this.props;
-		return end !== nextProps.end;
+		const { end, loadingMore } = this.props;
+		return end !== nextProps.end || loadingMore !== nextProps.loadingMore;
 	}
 
 	componentWillUnmount() {
diff --git a/app/views/RoomView/index.js b/app/views/RoomView/index.js
index f893df2aa..748a6d4db 100644
--- a/app/views/RoomView/index.js
+++ b/app/views/RoomView/index.js
@@ -23,7 +23,6 @@ import UploadProgress from './UploadProgress';
 import styles from './styles';
 import log from '../../utils/log';
 import I18n from '../../i18n';
-import debounce from '../../utils/debounce';
 import { iconsMap } from '../../Icons';
 import store from '../../lib/createStore';
 import ConnectionBadge from '../../containers/ConnectionBadge';
@@ -39,7 +38,8 @@ let RoomActionsView = null;
 	},
 	actionMessage: state.messages.actionMessage,
 	showActions: state.messages.showActions,
-	showErrorActions: state.messages.showErrorActions
+	showErrorActions: state.messages.showErrorActions,
+	appState: state.app.ready && state.app.foreground ? 'foreground' : 'background'
 }), dispatch => ({
 	openRoom: room => dispatch(openRoomAction(room)),
 	setLastOpen: date => dispatch(setLastOpenAction(date)),
@@ -87,6 +87,7 @@ export default class RoomView extends LoggedView {
 		showActions: PropTypes.bool,
 		showErrorActions: PropTypes.bool,
 		actionMessage: PropTypes.object,
+		appState: PropTypes.string,
 		toggleReactionPicker: PropTypes.func.isRequired,
 		actionsShow: PropTypes.func,
 		closeRoom: PropTypes.func
@@ -100,23 +101,33 @@ export default class RoomView extends LoggedView {
 			loaded: false,
 			joined: this.rooms.length > 0,
 			room: {},
-			end: false
+			end: false,
+			loadingMore: false
 		};
 		this.onReactionPress = this.onReactionPress.bind(this);
 		Navigation.events().bindComponent(this);
 	}
 
-	componentDidMount() {
-		this.updateRoom();
+	async componentDidMount() {
+		if (this.rooms.length === 0 && this.rid) {
+			const result = await RocketChat.getRoomInfo(this.rid);
+			if (result.success) {
+				const { room } = result;
+				this.setState(
+					{ room: { rid: room._id, t: room.t, name: room.name } },
+					() => this.updateRoom()
+				);
+			}
+		}
 		this.rooms.addListener(this.updateRoom);
 		this.internalSetState({ loaded: true });
 	}
 
 	shouldComponentUpdate(nextProps, nextState) {
 		const {
-			room, loaded, joined, end
+			room, loaded, joined, end, loadingMore
 		} = this.state;
-		const { showActions, showErrorActions } = this.props;
+		const { showActions, showErrorActions, appState } = this.props;
 
 		if (room.ro !== nextState.room.ro) {
 			return true;
@@ -128,17 +139,21 @@ export default class RoomView extends LoggedView {
 			return true;
 		} else if (end !== nextState.end) {
 			return true;
+		} else if (loadingMore !== nextState.loadingMore) {
+			return true;
 		} else if (showActions !== nextProps.showActions) {
 			return true;
 		} else if (showErrorActions !== nextProps.showErrorActions) {
 			return true;
+		} else if (appState !== nextProps.appState) {
+			return true;
 		}
 		return false;
 	}
 
 	componentDidUpdate(prevProps, prevState) {
 		const { room } = this.state;
-		const { componentId } = this.props;
+		const { componentId, appState } = this.props;
 
 		if (prevState.room.f !== room.f) {
 			Navigation.mergeOptions(componentId, {
@@ -154,32 +169,41 @@ export default class RoomView extends LoggedView {
 					}]
 				}
 			});
+		} else if (appState === 'foreground' && appState !== prevProps.appState) {
+			RocketChat.loadMissedMessages(room).catch(e => console.log(e));
+			RocketChat.readMessages(room.rid).catch(e => console.log(e));
 		}
 	}
 
 	componentWillUnmount() {
 		const { closeRoom } = this.props;
 		this.rooms.removeAllListeners();
-		this.onEndReached.stop();
+		if (this.onEndReached && this.onEndReached.stop) {
+			this.onEndReached.stop();
+		}
 		closeRoom();
 	}
 
-	onEndReached = debounce((lastRowData) => {
+	onEndReached = async(lastRowData) => {
 		if (!lastRowData) {
-			this.internalSetState({ end: true });
 			return;
 		}
 
-		requestAnimationFrame(async() => {
-			const { room } = this.state;
-			try {
-				const result = await RocketChat.loadMessagesForRoom({ rid: this.rid, t: room.t, latest: lastRowData.ts });
-				this.internalSetState({ end: result < 50 });
-			} catch (e) {
-				log('RoomView.onEndReached', e);
-			}
-		});
-	})
+		const { loadingMore, end } = this.state;
+		if (loadingMore || end) {
+			return;
+		}
+
+		this.setState({ loadingMore: true });
+		const { room } = this.state;
+		try {
+			const result = await RocketChat.loadMessagesForRoom({ rid: this.rid, t: room.t, latest: lastRowData.ts });
+			this.internalSetState({ end: result.length < 50, loadingMore: false });
+		} catch (e) {
+			this.internalSetState({ loadingMore: false });
+			log('RoomView.onEndReached', e);
+		}
+	}
 
 	onMessageLongPress = (message) => {
 		const { actionsShow } = this.props;
@@ -228,7 +252,7 @@ export default class RoomView extends LoggedView {
 			});
 		} else if (buttonId === 'star') {
 			try {
-				RocketChat.toggleFavorite(rid, f);
+				RocketChat.toggleFavorite(rid, !f);
 			} catch (e) {
 				log('toggleFavorite', e);
 			}
@@ -254,7 +278,8 @@ export default class RoomView extends LoggedView {
 				}
 			}
 		} else {
-			openRoom({ rid: this.rid });
+			const { room } = this.state;
+			openRoom(room);
 			this.internalSetState({ joined: false });
 		}
 	}
@@ -270,10 +295,12 @@ export default class RoomView extends LoggedView {
 	joinRoom = async() => {
 		const { rid } = this.props;
 		try {
-			await RocketChat.joinRoom(rid);
-			this.internalSetState({
-				joined: true
-			});
+			const result = await RocketChat.joinRoom(rid);
+			if (result.success) {
+				this.internalSetState({
+					joined: true
+				});
+			}
 		} catch (e) {
 			log('joinRoom', e);
 		}
@@ -364,15 +391,15 @@ export default class RoomView extends LoggedView {
 	};
 
 	renderHeader = () => {
-		const { end } = this.state;
-		if (!end) {
-			return <ActivityIndicator style={[styles.loading, { transform: [{ scaleY: -1 }] }]} />;
+		const { loadingMore } = this.state;
+		if (loadingMore) {
+			return <ActivityIndicator style={styles.loadingMore} />;
 		}
 		return null;
 	}
 
 	renderList = () => {
-		const { loaded, end } = this.state;
+		const { loaded, end, loadingMore } = this.state;
 		if (!loaded) {
 			return <ActivityIndicator style={styles.loading} />;
 		}
@@ -381,6 +408,7 @@ export default class RoomView extends LoggedView {
 				<List
 					key='room-view-messages'
 					end={end}
+					loadingMore={loadingMore}
 					room={this.rid}
 					renderFooter={this.renderHeader}
 					onEndReached={this.onEndReached}
diff --git a/app/views/RoomsListView/index.js b/app/views/RoomsListView/index.js
index ee77977c4..b531a00ea 100644
--- a/app/views/RoomsListView/index.js
+++ b/app/views/RoomsListView/index.js
@@ -66,7 +66,8 @@ let NewMessageView = null;
 	groupByType: state.sortPreferences.groupByType,
 	showFavorites: state.sortPreferences.showFavorites,
 	showUnread: state.sortPreferences.showUnread,
-	useRealName: state.settings.UI_Use_Real_Name
+	useRealName: state.settings.UI_Use_Real_Name,
+	appState: state.app.ready && state.app.foreground ? 'foreground' : 'background'
 }), dispatch => ({
 	toggleSortDropdown: () => dispatch(toggleSortDropdownAction()),
 	openSearchHeader: () => dispatch(openSearchHeaderAction()),
@@ -114,6 +115,7 @@ export default class RoomsListView extends LoggedView {
 		showFavorites: PropTypes.bool,
 		showUnread: PropTypes.bool,
 		useRealName: PropTypes.bool,
+		appState: PropTypes.string,
 		toggleSortDropdown: PropTypes.func,
 		openSearchHeader: PropTypes.func,
 		closeSearchHeader: PropTypes.func,
@@ -164,7 +166,7 @@ export default class RoomsListView extends LoggedView {
 
 	componentDidUpdate(prevProps) {
 		const {
-			sortBy, groupByType, showFavorites, showUnread
+			sortBy, groupByType, showFavorites, showUnread, appState
 		} = this.props;
 
 		if (!(
@@ -174,6 +176,8 @@ export default class RoomsListView extends LoggedView {
 			&& (prevProps.showUnread === showUnread)
 		)) {
 			this.getSubscriptions();
+		} else if (appState === 'foreground' && appState !== prevProps.appState) {
+			RocketChat.getRooms().catch(e => console.log(e));
 		}
 	}
 
@@ -416,9 +420,10 @@ export default class RoomsListView extends LoggedView {
 			// if user is using the search we need first to join/create room
 			try {
 				const { username } = item;
-				const sub = await RocketChat.createDirectMessage(username);
-				const { rid } = sub;
-				return this.goRoom(rid);
+				const result = await RocketChat.createDirectMessage(username);
+				if (result.success) {
+					return this.goRoom(result.room._id);
+				}
 			} catch (e) {
 				log('RoomsListView._onPressItem', e);
 			}
diff --git a/app/views/SetUsernameView.js b/app/views/SetUsernameView.js
index 5851fff09..486368707 100644
--- a/app/views/SetUsernameView.js
+++ b/app/views/SetUsernameView.js
@@ -1,14 +1,13 @@
 import React from 'react';
 import PropTypes from 'prop-types';
 import {
-	Text, ScrollView, Alert, StyleSheet
+	Text, ScrollView, StyleSheet
 } from 'react-native';
 import { connect } from 'react-redux';
 import SafeAreaView from 'react-native-safe-area-view';
-import equal from 'deep-equal';
 import { Navigation } from 'react-native-navigation';
 
-import { setUsernameSubmit as setUsernameSubmitAction } from '../actions/login';
+import { loginRequest as loginRequestAction } from '../actions/login';
 import TextInput from '../containers/TextInput';
 import Button from '../containers/Button';
 import KeyboardView from '../presentation/KeyboardView';
@@ -28,9 +27,9 @@ const styles = StyleSheet.create({
 
 @connect(state => ({
 	server: state.server.server,
-	login: state.login
+	token: state.login.user && state.login.user.token
 }), dispatch => ({
-	setUsernameSubmit: params => dispatch(setUsernameSubmitAction(params))
+	loginRequest: params => dispatch(loginRequestAction(params))
 }))
 /** @extends React.Component */
 export default class SetUsernameView extends LoggedView {
@@ -43,15 +42,15 @@ export default class SetUsernameView extends LoggedView {
 	static propTypes = {
 		componentId: PropTypes.string,
 		server: PropTypes.string,
-		setUsernameSubmit: PropTypes.func.isRequired,
-		Accounts_UsernamePlaceholder: PropTypes.string,
-		login: PropTypes.object
+		userId: PropTypes.string,
+		loginRequest: PropTypes.func
 	}
 
 	constructor(props) {
 		super('SetUsernameView', props);
 		this.state = {
-			username: ''
+			username: '',
+			saving: false
 		};
 		const { componentId, server } = this.props;
 		Navigation.mergeOptions(componentId, {
@@ -68,13 +67,8 @@ export default class SetUsernameView extends LoggedView {
 			this.usernameInput.focus();
 		}, 600);
 		const suggestion = await RocketChat.getUsernameSuggestion();
-		this.setState({ username: suggestion });
-	}
-
-	componentDidUpdate(prevProps) {
-		const { login } = this.props;
-		if (login && login.failure && login.error && !equal(login.error, prevProps.login.error)) {
-			Alert.alert(I18n.t('Oops'), login.error.reason);
+		if (suggestion.success) {
+			this.setState({ username: suggestion.result });
 		}
 	}
 
@@ -84,15 +78,27 @@ export default class SetUsernameView extends LoggedView {
 		}
 	}
 
-	submit = () => {
+	submit = async() => {
 		const { username } = this.state;
-		const { setUsernameSubmit } = this.props;
-		setUsernameSubmit({ username });
+		const { loginRequest, token } = this.props;
+
+		if (!username.trim()) {
+			return;
+		}
+
+		this.setState({ saving: true });
+		try {
+			await RocketChat.setUsername(username);
+			RocketChat.setApiUser({ userId: null, authToken: null });
+			await loginRequest({ resume: token });
+		} catch (e) {
+			console.log('SetUsernameView -> catch -> e', e);
+		}
+		this.setState({ saving: false });
 	}
 
 	render() {
-		const { username } = this.state;
-		const { login } = this.props;
+		const { username, saving } = this.state;
 		return (
 			<KeyboardView contentContainerStyle={sharedStyles.container}>
 				<ScrollView {...scrollPersistTaps} contentContainerStyle={sharedStyles.containerScrollView}>
@@ -117,7 +123,7 @@ export default class SetUsernameView extends LoggedView {
 							onPress={this.submit}
 							testID='set-username-view-submit'
 							disabled={!username}
-							loading={login.isFetching}
+							loading={saving}
 						/>
 					</SafeAreaView>
 				</ScrollView>
diff --git a/e2e/03-forgotpassword.spec.js b/e2e/03-forgotpassword.spec.js
index 3e887fc95..04391ad78 100644
--- a/e2e/03-forgotpassword.spec.js
+++ b/e2e/03-forgotpassword.spec.js
@@ -32,7 +32,7 @@ describe('Forgot password screen', () => {
 
 	describe('Usage', async() => {
 		it('should reset password and navigate to login', async() => {
-			await element(by.id('forgot-password-view-email')).replaceText(data.email);
+			await element(by.id('forgot-password-view-email')).replaceText('diego.mello@rocket.chat');
 			await element(by.id('forgot-password-view-submit')).tap();
 			await waitFor(element(by.id('login-view'))).toBeVisible().withTimeout(60000);
 			await expect(element(by.id('login-view'))).toBeVisible();
diff --git a/e2e/04-createuser.spec.js b/e2e/04-createuser.spec.js
index 79e33d972..5097efe93 100644
--- a/e2e/04-createuser.spec.js
+++ b/e2e/04-createuser.spec.js
@@ -58,27 +58,37 @@ describe('Create user screen', () => {
 	});
 
 	describe('Usage', () => {
-		it('should submit invalid email and raise error', async() => {
+		// FIXME: Detox isn't able to check if it's tappable: https://github.com/wix/Detox/issues/246
+		// it.only('should submit invalid email and do nothing', async() => {
+		// 	const invalidEmail = 'invalidemail';
+		// 	await element(by.id('register-view-name')).replaceText(data.user);
+		// 	await element(by.id('register-view-username')).replaceText(data.user);
+		// 	await element(by.id('register-view-email')).replaceText(invalidEmail);
+		// 	await element(by.id('register-view-password')).replaceText(data.password);
+		// 	await element(by.id('register-view-submit')).tap();
+		// });
+
+		it('should submit email already taken and raise error', async() => {
 			const invalidEmail = 'invalidemail';
 			await element(by.id('register-view-name')).replaceText(data.user);
 			await element(by.id('register-view-username')).replaceText(data.user);
-			await element(by.id('register-view-email')).replaceText(invalidEmail);
+			await element(by.id('register-view-email')).replaceText('diego.mello@rocket.chat');
 			await element(by.id('register-view-password')).replaceText(data.password);
 			await element(by.id('register-view-submit')).tap();
-			await waitFor(element(by.text(`Invalid email ${ invalidEmail }`)).atIndex(0)).toExist().withTimeout(10000);
-			await expect(element(by.text(`Invalid email ${ invalidEmail }`)).atIndex(0)).toExist();
+			await waitFor(element(by.text('Email already exists. [403]')).atIndex(0)).toExist().withTimeout(10000);
+			await expect(element(by.text('Email already exists. [403]')).atIndex(0)).toExist();
 			await element(by.text('OK')).tap();
 		});
 
 		it('should submit email already taken and raise error', async() => {
 			const invalidEmail = 'invalidemail';
 			await element(by.id('register-view-name')).replaceText(data.user);
-			await element(by.id('register-view-username')).replaceText(data.user);
-			await element(by.id('register-view-email')).replaceText('diego.mello@rocket.chat');
+			await element(by.id('register-view-username')).replaceText('diego.mello');
+			await element(by.id('register-view-email')).replaceText(data.email);
 			await element(by.id('register-view-password')).replaceText(data.password);
 			await element(by.id('register-view-submit')).tap();
-			await waitFor(element(by.text('Email already exists.')).atIndex(0)).toExist().withTimeout(10000);
-			await expect(element(by.text('Email already exists.')).atIndex(0)).toExist();
+			await waitFor(element(by.text('Username is already in use')).atIndex(0)).toExist().withTimeout(10000);
+			await expect(element(by.text('Username is already in use')).atIndex(0)).toExist();
 			await element(by.text('OK')).tap();
 		});
 
@@ -92,21 +102,6 @@ describe('Create user screen', () => {
 			await expect(element(by.id('rooms-list-view'))).toBeVisible();
 		});
 
-		it('should pick an existing username, suggest another and finish register', async() => {
-			await logout();
-			await navigateToRegister();
-			await element(by.id('register-view-name')).replaceText(data.user);
-			await element(by.id('register-view-username')).replaceText(data.user);
-			await element(by.id('register-view-email')).replaceText(`${ data.email }2`);
-			await element(by.id('register-view-password')).replaceText(data.password);
-			await element(by.id('register-view-submit')).tap();
-			await waitFor(element(by.id('set-username-view'))).toBeVisible().withTimeout(60000);
-			await expect(element(by.id('set-username-view'))).toBeVisible();
-			await element(by.id('set-username-view-submit')).tap();
-			await waitFor(element(by.id('rooms-list-view'))).toBeVisible().withTimeout(60000);
-			await expect(element(by.id('rooms-list-view'))).toBeVisible();
-		});
-
 		afterEach(async() => {
 			takeScreenshot();
 		});
diff --git a/package-lock.json b/package-lock.json
index 3c27dc22d..0aebf2ce2 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -2149,8 +2149,8 @@
       "integrity": "sha512-iOD1PRnTSVr9sDWQdesIpfRrwJhHfeEQe5BpalQxC5OhM9thpiE6cu2NlW1KBWl0RJG4ZiJaF1xLlCo9YxU6dA=="
     },
     "@rocket.chat/sdk": {
-      "version": "git+https://github.com/RocketChat/Rocket.Chat.js.SDK.git#86d0b0f544ea700f742a66f59a21e1679aa7ff50",
-      "from": "git+https://github.com/RocketChat/Rocket.Chat.js.SDK.git#ddp",
+      "version": "git+https://github.com/RocketChat/Rocket.Chat.js.SDK.git#3257e342690eb103f3ea5eec918fb73670ddb6a8",
+      "from": "git+https://github.com/RocketChat/Rocket.Chat.js.SDK.git#temp-ddp",
       "requires": {
         "@types/lru-cache": "^4.1.0",
         "@types/node": "^9.4.6",
@@ -2573,9 +2573,9 @@
       "integrity": "sha512-FWR7QB7EqBRq1s9BMk0ccOSOuRLfVEWYpHQYpFPaXtCoqN6dJx2ttdsdQbUxLLnAlKpYeVjveGGhQ3583TTa7g=="
     },
     "@types/node": {
-      "version": "9.6.36",
-      "resolved": "https://registry.npmjs.org/@types/node/-/node-9.6.36.tgz",
-      "integrity": "sha512-Fbw+AdRLL01vv7Rk7bYaNPecqmKoinJHGbpKnDpbUZmUj/0vj3nLqPQ4CNBzr3q2zso6Cq/4jHoCAdH78fvJrw=="
+      "version": "9.6.40",
+      "resolved": "https://registry.npmjs.org/@types/node/-/node-9.6.40.tgz",
+      "integrity": "sha512-M3HHoXXndsho/sTbQML2BJr7/uwNhMg8P0D4lb+UsM65JQZx268faiz9hKpY4FpocWqpwlLwa8vevw8hLtKjOw=="
     },
     "@types/react": {
       "version": "16.4.6",
@@ -4642,6 +4642,7 @@
       "version": "6.26.0",
       "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz",
       "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=",
+      "dev": true,
       "requires": {
         "core-js": "^2.4.0",
         "regenerator-runtime": "^0.11.0"
@@ -4650,7 +4651,8 @@
         "regenerator-runtime": {
           "version": "0.11.1",
           "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz",
-          "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg=="
+          "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==",
+          "dev": true
         }
       }
     },
@@ -6664,11 +6666,6 @@
         "randomfill": "^1.0.3"
       }
     },
-    "crypto-js": {
-      "version": "3.1.8",
-      "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-3.1.8.tgz",
-      "integrity": "sha1-cV8HC/YBTyrpkqmLOSkli3E/CNU="
-    },
     "crypto-random-string": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-1.0.0.tgz",
@@ -8246,11 +8243,6 @@
       "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-1.1.1.tgz",
       "integrity": "sha1-qG5e5r2qFgVEddp5fM3fDFVphJE="
     },
-    "eventemitter3": {
-      "version": "1.2.0",
-      "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-1.2.0.tgz",
-      "integrity": "sha1-HIaZHYFq0eUEdQ5zh0Ik7PO+xQg="
-    },
     "events": {
       "version": "2.1.0",
       "resolved": "https://registry.npmjs.org/events/-/events-2.1.0.tgz",
@@ -8813,9 +8805,9 @@
       }
     },
     "follow-redirects": {
-      "version": "1.5.9",
-      "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.9.tgz",
-      "integrity": "sha512-Bh65EZI/RU8nx0wbYF9shkFZlqLP+6WT/5FnA3cE/djNSuKNHJEinGGZgu/cQEkeeb2GdFOgenAmn8qaqYke2w==",
+      "version": "1.5.10",
+      "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz",
+      "integrity": "sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==",
       "requires": {
         "debug": "=3.1.0"
       },
@@ -10427,7 +10419,8 @@
     "hoist-non-react-statics": {
       "version": "1.2.0",
       "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-1.2.0.tgz",
-      "integrity": "sha1-qkSM8JhtVcxAdzsXF0t90GbLfPs="
+      "integrity": "sha1-qkSM8JhtVcxAdzsXF0t90GbLfPs=",
+      "dev": true
     },
     "home-or-tmp": {
       "version": "2.0.0",
@@ -14127,7 +14120,8 @@
     "lodash._getnative": {
       "version": "3.9.1",
       "resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz",
-      "integrity": "sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U="
+      "integrity": "sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U=",
+      "dev": true
     },
     "lodash.assign": {
       "version": "4.2.0",
@@ -14174,12 +14168,14 @@
     "lodash.isarguments": {
       "version": "3.1.0",
       "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz",
-      "integrity": "sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo="
+      "integrity": "sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo=",
+      "dev": true
     },
     "lodash.isarray": {
       "version": "3.0.4",
       "resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz",
-      "integrity": "sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U="
+      "integrity": "sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U=",
+      "dev": true
     },
     "lodash.isequal": {
       "version": "4.5.0",
@@ -14196,6 +14192,7 @@
       "version": "3.1.2",
       "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz",
       "integrity": "sha1-TbwEcrFWvlCgsoaFXRvQsMZWCYo=",
+      "dev": true,
       "requires": {
         "lodash._getnative": "^3.0.0",
         "lodash.isarguments": "^3.0.0",
@@ -14958,23 +14955,6 @@
       "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
       "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ="
     },
-    "minimongo-cache": {
-      "version": "0.0.48",
-      "resolved": "https://registry.npmjs.org/minimongo-cache/-/minimongo-cache-0.0.48.tgz",
-      "integrity": "sha1-pvu3i2YnVUJJr+78EkPPfLpr6gc=",
-      "requires": {
-        "eventemitter3": "^1.1.0",
-        "invariant": "^2.1.1",
-        "lodash": "~2.4.1"
-      },
-      "dependencies": {
-        "lodash": {
-          "version": "2.4.2",
-          "resolved": "https://registry.npmjs.org/lodash/-/lodash-2.4.2.tgz",
-          "integrity": "sha1-+t2DS5aDBz2hebPq5tnA0VBT9z4="
-        }
-      }
-    },
     "minipass": {
       "version": "2.3.5",
       "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.3.5.tgz",
@@ -15078,11 +15058,6 @@
         }
       }
     },
-    "mobx": {
-      "version": "2.7.0",
-      "resolved": "https://registry.npmjs.org/mobx/-/mobx-2.7.0.tgz",
-      "integrity": "sha1-zz2C0YwMp/RY2PKiQIF7PcflSgE="
-    },
     "mocha": {
       "version": "5.2.0",
       "resolved": "https://registry.npmjs.org/mocha/-/mocha-5.2.0.tgz",
@@ -17690,21 +17665,6 @@
         }
       }
     },
-    "raf": {
-      "version": "3.1.0",
-      "resolved": "https://registry.npmjs.org/raf/-/raf-3.1.0.tgz",
-      "integrity": "sha1-XYS/gbV/l5+MSSvgg3jFOLtO7Pw=",
-      "requires": {
-        "performance-now": "~0.2.0"
-      },
-      "dependencies": {
-        "performance-now": {
-          "version": "0.2.0",
-          "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-0.2.0.tgz",
-          "integrity": "sha1-M+8wxcd9TqIcWlOGnZG1bY8lVeU="
-        }
-      }
-    },
     "ramda": {
       "version": "0.24.1",
       "resolved": "https://registry.npmjs.org/ramda/-/ramda-0.24.1.tgz",
@@ -17970,32 +17930,11 @@
       "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.6.3.tgz",
       "integrity": "sha512-u7FDWtthB4rWibG/+mFbVd5FvdI20yde86qKGx4lVUTWmPlSWQ4QxbBIrrs+HnXGbxOUlUzTAP/VDmvCwaP2yA=="
     },
-    "react-komposer": {
-      "version": "1.13.1",
-      "resolved": "https://registry.npmjs.org/react-komposer/-/react-komposer-1.13.1.tgz",
-      "integrity": "sha1-S4rEvMcTI710E9yrlcgxGX9Q7tA=",
-      "requires": {
-        "babel-runtime": "6.x.x",
-        "hoist-non-react-statics": "1.x.x",
-        "invariant": "2.x.x",
-        "mobx": "^2.3.4",
-        "shallowequal": "0.2.x"
-      }
-    },
     "react-lifecycles-compat": {
       "version": "3.0.4",
       "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz",
       "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA=="
     },
-    "react-mixin": {
-      "version": "3.1.1",
-      "resolved": "https://registry.npmjs.org/react-mixin/-/react-mixin-3.1.1.tgz",
-      "integrity": "sha512-z9fZ0aCRDjlgxLdMeWkJ9TwhmVLhQ09r8RFpin/cEPA2T6jsb7YHNWcIe0Oii+hhJNyMymdy91CSya5mRkuCkg==",
-      "requires": {
-        "object-assign": "^4.0.1",
-        "smart-mixin": "^2.0.0"
-      }
-    },
     "react-modal": {
       "version": "3.5.1",
       "resolved": "https://registry.npmjs.org/react-modal/-/react-modal-3.5.1.tgz",
@@ -18239,9 +18178,9 @@
       "from": "github:corymsmith/react-native-fabric#523a4edab3b2bf55ea9eeea2cf0dde82c5c29dd4"
     },
     "react-native-fast-image": {
-      "version": "5.1.1",
-      "resolved": "https://registry.npmjs.org/react-native-fast-image/-/react-native-fast-image-5.1.1.tgz",
-      "integrity": "sha512-kEzgZxbbXYhy27u5GnhrKitn+XDBFAHSDUJdYC6llMi5cDPjgcqhOAQABj0K+ga5pn+/xPZLmD882rrUGiwVVA=="
+      "version": "5.0.11",
+      "resolved": "https://registry.npmjs.org/react-native-fast-image/-/react-native-fast-image-5.0.11.tgz",
+      "integrity": "sha512-5NNQwRniOfSBAvKldyPEs1xotWxrFcplOSQiVc78dv/EhH4G0IpdrLtsQmBdB91EMtPQfvoT269sKqj5MJCgyA=="
     },
     "react-native-fit-image": {
       "version": "1.5.4",
@@ -18277,9 +18216,8 @@
       }
     },
     "react-native-image-crop-picker": {
-      "version": "0.21.3",
-      "resolved": "https://registry.npmjs.org/react-native-image-crop-picker/-/react-native-image-crop-picker-0.21.3.tgz",
-      "integrity": "sha512-qzY8aSYZxH4L9XYRk4V1n8x1gfq+ykNG0Kc0a9ne+JWwAQkf2P8aTKeNd4noNFZEOSJBiD4XXE/pbX55dQ5F3g=="
+      "version": "git+https://github.com/RocketChat/react-native-image-crop-picker.git#6c205596b5496b207daa93408c9cef886e04bdbb",
+      "from": "git+https://github.com/RocketChat/react-native-image-crop-picker.git"
     },
     "react-native-image-pan-zoom": {
       "version": "2.1.11",
@@ -18334,23 +18272,6 @@
         "react-native-fit-image": "^1.5.2"
       }
     },
-    "react-native-meteor": {
-      "version": "1.4.0",
-      "resolved": "https://registry.npmjs.org/react-native-meteor/-/react-native-meteor-1.4.0.tgz",
-      "integrity": "sha512-Bm5RGTDv7LsJqqWjaR8KCv2mpeeMMPOIeZWHSx1yeTLUnEx71jVWAbHNXmEEynyH61/NVUpwDaXZKxiw9OwhFA==",
-      "requires": {
-        "base-64": "^0.1.0",
-        "crypto-js": "^3.1.6",
-        "ejson": "^2.1.2",
-        "minimongo-cache": "0.0.48",
-        "prop-types": "^15.5.10",
-        "react-komposer": "^1.8.0",
-        "react-mixin": "^3.0.3",
-        "trackr": "^2.0.2",
-        "underscore": "^1.8.3",
-        "wolfy87-eventemitter": "^4.3.0"
-      }
-    },
     "react-native-modal": {
       "version": "7.0.0",
       "resolved": "https://registry.npmjs.org/react-native-modal/-/react-native-modal-7.0.0.tgz",
@@ -20180,6 +20101,7 @@
       "version": "0.2.2",
       "resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-0.2.2.tgz",
       "integrity": "sha1-HjL9W8q2rWiKSBLLDMBO/HXHAU4=",
+      "dev": true,
       "requires": {
         "lodash.keys": "^3.1.2"
       }
@@ -20301,11 +20223,6 @@
       "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-1.1.15.tgz",
       "integrity": "sha1-fxFLW2X6s+KjWqd1uxLw0cZJvxY="
     },
-    "smart-mixin": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/smart-mixin/-/smart-mixin-2.0.0.tgz",
-      "integrity": "sha1-o0oQVeMqdbMNK048oyPcmctT9Dc="
-    },
     "snapdragon": {
       "version": "0.8.2",
       "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz",
@@ -21812,14 +21729,6 @@
         }
       }
     },
-    "trackr": {
-      "version": "2.0.2",
-      "resolved": "https://registry.npmjs.org/trackr/-/trackr-2.0.2.tgz",
-      "integrity": "sha1-7jixO1gLMN9ejgJw0c89AhLEdF4=",
-      "requires": {
-        "raf": "~3.1.0"
-      }
-    },
     "trim-right": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz",
@@ -22767,11 +22676,6 @@
       "integrity": "sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0=",
       "dev": true
     },
-    "wolfy87-eventemitter": {
-      "version": "4.3.0",
-      "resolved": "https://registry.npmjs.org/wolfy87-eventemitter/-/wolfy87-eventemitter-4.3.0.tgz",
-      "integrity": "sha1-ZJc5bJXnQ1nwa241QJM5MY2Nlk8="
-    },
     "wordwrap": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz",
diff --git a/package.json b/package.json
index fa2bce6a7..c43bf40e0 100644
--- a/package.json
+++ b/package.json
@@ -23,7 +23,7 @@
   },
   "dependencies": {
     "@remobile/react-native-toast": "^1.0.7",
-    "@rocket.chat/sdk": "git+https://github.com/RocketChat/Rocket.Chat.js.SDK.git#ddp",
+    "@rocket.chat/sdk": "git+https://github.com/RocketChat/Rocket.Chat.js.SDK.git#temp-ddp",
     "deep-equal": "^1.0.1",
     "ejson": "^2.1.2",
     "js-base64": "^2.4.9",
@@ -41,16 +41,15 @@
     "react-native-device-info": "^0.24.3",
     "react-native-dialog": "^5.4.0",
     "react-native-fabric": "github:corymsmith/react-native-fabric#523a4edab3b2bf55ea9eeea2cf0dde82c5c29dd4",
-    "react-native-fast-image": "^5.1.1",
+    "react-native-fast-image": "^5.0.11",
     "react-native-gesture-handler": "^1.0.9",
     "react-native-i18n": "^2.0.15",
-    "react-native-image-crop-picker": "0.21.3",
+    "react-native-image-crop-picker": "git+https://github.com/RocketChat/react-native-image-crop-picker.git",
     "react-native-image-zoom-viewer": "^2.2.23",
     "react-native-keyboard-aware-scroll-view": "^0.7.4",
     "react-native-keyboard-input": "^5.3.1",
     "react-native-keyboard-tracking-view": "^5.5.0",
     "react-native-markdown-renderer": "^3.2.8",
-    "react-native-meteor": "^1.4.0",
     "react-native-modal": "^7.0.0",
     "react-native-navigation": "^2.1.3",
     "react-native-notifications": "^1.1.21",
-- 
GitLab