From ad375860650eef87ef512e010325e3a33a9c7f63 Mon Sep 17 00:00:00 2001
From: Diego Mello <diegolmello@gmail.com>
Date: Wed, 12 Dec 2018 13:15:10 -0200
Subject: [PATCH] Use Rest API pt 2 (#568)

* Room files

* Pinned messages

* Starred messages

* Mentioned messages

* Search messages

* Bug fixes

* Profile

* Livechat

* Block/unblock user

* Erase room

* Archive room

* Remove unused method

* Bug fix
---
 app/actions/actionsTypes.js              |   4 -
 app/actions/mentionedMessages.js         |  29 ----
 app/actions/pinnedMessages.js            |  36 -----
 app/actions/roomFiles.js                 |  28 ----
 app/actions/starredMessages.js           |  35 -----
 app/containers/message/Message.js        |  10 +-
 app/containers/message/User.js           |   5 +-
 app/i18n/locales/en.js                   |   2 +
 app/i18n/locales/pt-BR.js                |   2 +
 app/lib/methods/loadMessagesForRoom.js   |  13 ++
 app/lib/rocketchat.js                    | 168 +++++------------------
 app/reducers/index.js                    |   8 --
 app/reducers/mentionedMessages.js        |  30 ----
 app/reducers/pinnedMessages.js           |  37 -----
 app/reducers/roomFiles.js                |  30 ----
 app/reducers/starredMessages.js          |  37 -----
 app/sagas/index.js                       |   8 --
 app/sagas/login.js                       |   3 +-
 app/sagas/mentionedMessages.js           |  41 ------
 app/sagas/pinnedMessages.js              |  41 ------
 app/sagas/roomFiles.js                   |  43 ------
 app/sagas/rooms.js                       |  30 ++--
 app/sagas/starredMessages.js             |  41 ------
 app/views/MentionedMessagesView/index.js | 103 +++++++-------
 app/views/PinnedMessagesView/index.js    | 116 ++++++++--------
 app/views/ProfileView/index.js           | 168 ++++++++++++-----------
 app/views/RoomActionsView/index.js       |  21 ++-
 app/views/RoomFilesView/index.js         | 113 ++++++++-------
 app/views/RoomInfoEditView/index.js      |  10 +-
 app/views/RoomMembersView/index.js       |   9 +-
 app/views/RoomView/index.js              |  32 +++--
 app/views/RoomView/styles.js             |   7 +-
 app/views/SearchMessagesView/index.js    | 139 +++++++++----------
 app/views/SearchMessagesView/styles.js   |   4 +-
 app/views/SnippetedMessagesView/index.js |   2 +-
 app/views/StarredMessagesView/index.js   | 122 ++++++++--------
 36 files changed, 530 insertions(+), 997 deletions(-)
 delete mode 100644 app/actions/mentionedMessages.js
 delete mode 100644 app/actions/pinnedMessages.js
 delete mode 100644 app/actions/roomFiles.js
 delete mode 100644 app/actions/starredMessages.js
 delete mode 100644 app/reducers/mentionedMessages.js
 delete mode 100644 app/reducers/pinnedMessages.js
 delete mode 100644 app/reducers/roomFiles.js
 delete mode 100644 app/reducers/starredMessages.js
 delete mode 100644 app/sagas/mentionedMessages.js
 delete mode 100644 app/sagas/pinnedMessages.js
 delete mode 100644 app/sagas/roomFiles.js
 delete mode 100644 app/sagas/starredMessages.js

diff --git a/app/actions/actionsTypes.js b/app/actions/actionsTypes.js
index 5238b5339..89b84a240 100644
--- a/app/actions/actionsTypes.js
+++ b/app/actions/actionsTypes.js
@@ -77,10 +77,6 @@ export const METEOR = createRequestTypes('METEOR_CONNECT', [...defaultTypes, 'DI
 export const LOGOUT = 'LOGOUT'; // logout is always success
 export const ACTIVE_USERS = createRequestTypes('ACTIVE_USERS', ['SET']);
 export const ROLES = createRequestTypes('ROLES', ['SET']);
-export const STARRED_MESSAGES = createRequestTypes('STARRED_MESSAGES', ['OPEN', 'READY', 'CLOSE', 'MESSAGES_RECEIVED', 'MESSAGE_UNSTARRED']);
-export const PINNED_MESSAGES = createRequestTypes('PINNED_MESSAGES', ['OPEN', 'READY', 'CLOSE', 'MESSAGES_RECEIVED', 'MESSAGE_UNPINNED']);
-export const MENTIONED_MESSAGES = createRequestTypes('MENTIONED_MESSAGES', ['OPEN', 'READY', 'CLOSE', 'MESSAGES_RECEIVED']);
 export const SNIPPETED_MESSAGES = createRequestTypes('SNIPPETED_MESSAGES', ['OPEN', 'READY', 'CLOSE', 'MESSAGES_RECEIVED']);
-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']);
diff --git a/app/actions/mentionedMessages.js b/app/actions/mentionedMessages.js
deleted file mode 100644
index e4d9e3be9..000000000
--- a/app/actions/mentionedMessages.js
+++ /dev/null
@@ -1,29 +0,0 @@
-import * as types from './actionsTypes';
-
-export function openMentionedMessages(rid, limit) {
-	return {
-		type: types.MENTIONED_MESSAGES.OPEN,
-		rid,
-		limit
-	};
-}
-
-export function readyMentionedMessages() {
-	return {
-		type: types.MENTIONED_MESSAGES.READY
-	};
-}
-
-
-export function closeMentionedMessages() {
-	return {
-		type: types.MENTIONED_MESSAGES.CLOSE
-	};
-}
-
-export function mentionedMessagesReceived(messages) {
-	return {
-		type: types.MENTIONED_MESSAGES.MESSAGES_RECEIVED,
-		messages
-	};
-}
diff --git a/app/actions/pinnedMessages.js b/app/actions/pinnedMessages.js
deleted file mode 100644
index 406010037..000000000
--- a/app/actions/pinnedMessages.js
+++ /dev/null
@@ -1,36 +0,0 @@
-import * as types from './actionsTypes';
-
-export function openPinnedMessages(rid, limit) {
-	return {
-		type: types.PINNED_MESSAGES.OPEN,
-		rid,
-		limit
-	};
-}
-
-export function readyPinnedMessages() {
-	return {
-		type: types.PINNED_MESSAGES.READY
-	};
-}
-
-
-export function closePinnedMessages() {
-	return {
-		type: types.PINNED_MESSAGES.CLOSE
-	};
-}
-
-export function pinnedMessagesReceived(messages) {
-	return {
-		type: types.PINNED_MESSAGES.MESSAGES_RECEIVED,
-		messages
-	};
-}
-
-export function pinnedMessageUnpinned(messageId) {
-	return {
-		type: types.PINNED_MESSAGES.MESSAGE_UNPINNED,
-		messageId
-	};
-}
diff --git a/app/actions/roomFiles.js b/app/actions/roomFiles.js
deleted file mode 100644
index 906912a5c..000000000
--- a/app/actions/roomFiles.js
+++ /dev/null
@@ -1,28 +0,0 @@
-import * as types from './actionsTypes';
-
-export function openRoomFiles(rid, limit) {
-	return {
-		type: types.ROOM_FILES.OPEN,
-		rid,
-		limit
-	};
-}
-
-export function readyRoomFiles() {
-	return {
-		type: types.ROOM_FILES.READY
-	};
-}
-
-export function closeRoomFiles() {
-	return {
-		type: types.ROOM_FILES.CLOSE
-	};
-}
-
-export function roomFilesReceived(messages) {
-	return {
-		type: types.ROOM_FILES.MESSAGES_RECEIVED,
-		messages
-	};
-}
diff --git a/app/actions/starredMessages.js b/app/actions/starredMessages.js
deleted file mode 100644
index a8f82faf9..000000000
--- a/app/actions/starredMessages.js
+++ /dev/null
@@ -1,35 +0,0 @@
-import * as types from './actionsTypes';
-
-export function openStarredMessages(rid, limit) {
-	return {
-		type: types.STARRED_MESSAGES.OPEN,
-		rid,
-		limit
-	};
-}
-
-export function readyStarredMessages() {
-	return {
-		type: types.STARRED_MESSAGES.READY
-	};
-}
-
-export function closeStarredMessages() {
-	return {
-		type: types.STARRED_MESSAGES.CLOSE
-	};
-}
-
-export function starredMessagesReceived(messages) {
-	return {
-		type: types.STARRED_MESSAGES.MESSAGES_RECEIVED,
-		messages
-	};
-}
-
-export function starredMessageUnstarred(messageId) {
-	return {
-		type: types.STARRED_MESSAGES.MESSAGE_UNSTARRED,
-		messageId
-	};
-}
diff --git a/app/containers/message/Message.js b/app/containers/message/Message.js
index b2f32dc02..6657ae770 100644
--- a/app/containers/message/Message.js
+++ b/app/containers/message/Message.js
@@ -39,7 +39,8 @@ const SYSTEM_MESSAGES = [
 	'room_changed_description',
 	'room_changed_announcement',
 	'room_changed_topic',
-	'room_changed_privacy'
+	'room_changed_privacy',
+	'message_snippeted'
 ];
 
 const getInfoMessage = ({
@@ -76,6 +77,8 @@ const getInfoMessage = ({
 		return I18n.t('Room_changed_topic', { topic: msg, userBy: username });
 	} else if (type === 'room_changed_privacy') {
 		return I18n.t('Room_changed_privacy', { type: msg, userBy: username });
+	} else if (type === 'message_snippeted') {
+		return I18n.t('Created_snippet');
 	}
 	return '';
 };
@@ -107,7 +110,10 @@ export default class Message extends PureComponent {
 		header: PropTypes.bool,
 		avatar: PropTypes.string,
 		alias: PropTypes.string,
-		ts: PropTypes.instanceOf(Date),
+		ts: PropTypes.oneOfType([
+			PropTypes.instanceOf(Date),
+			PropTypes.string
+		]),
 		edited: PropTypes.bool,
 		attachments: PropTypes.oneOfType([
 			PropTypes.array,
diff --git a/app/containers/message/User.js b/app/containers/message/User.js
index c3d4b3dd0..6f2d5bf42 100644
--- a/app/containers/message/User.js
+++ b/app/containers/message/User.js
@@ -35,7 +35,10 @@ export default class User extends React.PureComponent {
 		timeFormat: PropTypes.string.isRequired,
 		username: PropTypes.string,
 		alias: PropTypes.string,
-		ts: PropTypes.instanceOf(Date),
+		ts: PropTypes.oneOfType([
+			PropTypes.instanceOf(Date),
+			PropTypes.string
+		]),
 		temp: PropTypes.bool
 	}
 
diff --git a/app/i18n/locales/en.js b/app/i18n/locales/en.js
index 425cacae0..8e3487be4 100644
--- a/app/i18n/locales/en.js
+++ b/app/i18n/locales/en.js
@@ -131,6 +131,7 @@ export default {
 	Copy_Permalink: 'Copy Permalink',
 	Create_account: 'Create an account',
 	Create_Channel: 'Create Channel',
+	Created_snippet: 'Created a snippet',
 	Create_a_new_workspace: 'Create a new workspace',
 	Create: 'Create',
 	Delete_Room_Warning: 'Deleting a room will delete all messages posted within the room. This cannot be undone.',
@@ -209,6 +210,7 @@ export default {
 	No_files: 'No files',
 	No_mentioned_messages: 'No mentioned messages',
 	No_pinned_messages: 'No pinned messages',
+	No_results_found: 'No results found',
 	No_snippeted_messages: 'No snippeted messages',
 	No_starred_messages: 'No starred messages',
 	No_announcement_provided: 'No announcement provided.',
diff --git a/app/i18n/locales/pt-BR.js b/app/i18n/locales/pt-BR.js
index 76d51ae2e..f7e49cf89 100644
--- a/app/i18n/locales/pt-BR.js
+++ b/app/i18n/locales/pt-BR.js
@@ -138,6 +138,7 @@ export default {
 	Copy_Permalink: 'Copiar Link-Permanente',
 	Create_account: 'Criar conta',
 	Create_Channel: 'Criar Canal',
+	Created_snippet: 'Criou um snippet',
 	Create_a_new_workspace: 'Criar nova área de trabalho',
 	Create: 'Criar',
 	Delete_Room_Warning: 'A exclusão de uma sala irá apagar todas as mensagens postadas na sala. Isso não pode ser desfeito.',
@@ -212,6 +213,7 @@ export default {
 	No_files: 'Não há arquivos',
 	No_mentioned_messages: 'Não há menções',
 	No_pinned_messages: 'Não há mensagens fixadas',
+	No_results_found: 'Nenhum resultado encontrado',
 	No_snippeted_messages: 'Não há trechos de mensagens',
 	No_starred_messages: 'Não há mensagens favoritas',
 	No_announcement_provided: 'Sem anúncio.',
diff --git a/app/lib/methods/loadMessagesForRoom.js b/app/lib/methods/loadMessagesForRoom.js
index f20b57c6d..1258769c0 100644
--- a/app/lib/methods/loadMessagesForRoom.js
+++ b/app/lib/methods/loadMessagesForRoom.js
@@ -6,6 +6,19 @@ import database from '../realm';
 import log from '../../utils/log';
 
 async function load({ rid: roomId, latest, t }) {
+	if (t === 'l') {
+		try {
+			const data = await SDK.driver.asyncCall('loadHistory', roomId, null, 50, latest);
+			if (!data || data.status === 'error') {
+				return [];
+			}
+			return data.messages;
+		} catch (error) {
+			console.log(error);
+			return [];
+		}
+	}
+
 	let params = { roomId, count: 50 };
 	if (latest) {
 		params = { ...params, latest: new Date(latest).toISOString() };
diff --git a/app/lib/rocketchat.js b/app/lib/rocketchat.js
index 85bfb584e..7bfec9cc7 100644
--- a/app/lib/rocketchat.js
+++ b/app/lib/rocketchat.js
@@ -14,11 +14,7 @@ import {
 } from '../actions/login';
 import { disconnect, connectSuccess, connectRequest } from '../actions/connect';
 import { setActiveUser } from '../actions/activeUsers';
-import { starredMessagesReceived, starredMessageUnstarred } from '../actions/starredMessages';
-import { pinnedMessagesReceived, pinnedMessageUnpinned } from '../actions/pinnedMessages';
-import { mentionedMessagesReceived } from '../actions/mentionedMessages';
 import { snippetedMessagesReceived } from '../actions/snippetedMessages';
-import { roomFilesReceived } from '../actions/roomFiles';
 import { someoneTyping, roomMessageReceived } from '../actions/room';
 import { setRoles } from '../actions/roles';
 
@@ -199,79 +195,6 @@ const RocketChat = {
 			}
 		}));
 
-		SDK.driver.on('rocketchat_starred_message', protectedFunction((error, ddpMessage) => {
-			if (ddpMessage.msg === 'added') {
-				this.starredMessages = this.starredMessages || [];
-
-				if (this.starredMessagesTimer) {
-					clearTimeout(this.starredMessagesTimer);
-					this.starredMessagesTimer = null;
-				}
-
-				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));
-				}
-			}
-		}));
-
-		SDK.driver.on('rocketchat_pinned_message', protectedFunction((error, ddpMessage) => {
-			if (ddpMessage.msg === 'added') {
-				this.pinnedMessages = this.pinnedMessages || [];
-
-				if (this.pinnedMessagesTimer) {
-					clearTimeout(this.pinnedMessagesTimer);
-					this.pinnedMessagesTimer = null;
-				}
-
-				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));
-				}
-			}
-		}));
-
-		SDK.driver.on('rocketchat_mentioned_message', protectedFunction((error, ddpMessage) => {
-			if (ddpMessage.msg === 'added') {
-				this.mentionedMessages = this.mentionedMessages || [];
-
-				if (this.mentionedMessagesTimer) {
-					clearTimeout(this.mentionedMessagesTimer);
-					this.mentionedMessagesTimer = null;
-				}
-
-				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];
-			}
-		}));
-
 		SDK.driver.on('rocketchat_snippeted_message', protectedFunction((error, ddpMessage) => {
 			if (ddpMessage.msg === 'added') {
 				this.snippetedMessages = this.snippetedMessages || [];
@@ -293,50 +216,6 @@ const RocketChat = {
 			}
 		}));
 
-		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.roomFiles = [...this.roomFiles, message];
-			}
-		}));
-
 		SDK.driver.on('rocketchat_roles', protectedFunction((error, ddpMessage) => {
 			this.roles = this.roles || {};
 
@@ -678,7 +557,7 @@ const RocketChat = {
 	async getRoomMember(rid, currentUserId) {
 		try {
 			const membersResult = await RocketChat.getRoomMembers(rid, true);
-			return Promise.resolve(membersResult.records.find(m => m.id !== currentUserId));
+			return Promise.resolve(membersResult.records.find(m => m._id !== currentUserId));
 		} catch (error) {
 			return Promise.reject(error);
 		}
@@ -692,8 +571,8 @@ const RocketChat = {
 	leaveRoom(roomId, t) {
 		return SDK.api.post(`${ this.roomTypeToApiType(t) }.leave`, { roomId });
 	},
-	eraseRoom(rid) {
-		return call('eraseRoom', rid);
+	eraseRoom(roomId, t) {
+		return SDK.api.post(`${ this.roomTypeToApiType(t) }.delete`, { roomId });
 	},
 	toggleMuteUserInRoom(rid, username, mute) {
 		if (mute) {
@@ -701,17 +580,17 @@ const RocketChat = {
 		}
 		return call('unmuteUserInRoom', { rid, username });
 	},
-	toggleArchiveRoom(rid, archive) {
+	toggleArchiveRoom(roomId, t, archive) {
 		if (archive) {
-			return call('archiveRoom', rid);
+			return SDK.api.post(`${ this.roomTypeToApiType(t) }.archive`, { roomId });
 		}
-		return call('unarchiveRoom', rid);
+		return SDK.api.post(`${ this.roomTypeToApiType(t) }.unarchive`, { roomId });
 	},
 	saveRoomSettings(rid, params) {
 		return call('saveRoomSettings', rid, params);
 	},
-	saveUserProfile(params, customFields) {
-		return call('saveUserProfile', params, customFields);
+	saveUserProfile(data) {
+		return SDK.api.post('users.updateOwnBasicInfo', { data });
 	},
 	saveUserPreferences(params) {
 		return call('saveUserPreferences', params);
@@ -719,9 +598,6 @@ const RocketChat = {
 	saveNotificationSettings(roomId, notifications) {
 		return SDK.api.post('rooms.saveNotification', { roomId, notifications });
 	},
-	messageSearch(text, rid, limit) {
-		return call('messageSearch', text, rid, limit);
-	},
 	addUsersToRoom(rid) {
 		let { users } = reduxStore.getState().selectedUsers;
 		users = users.map(u => u.name);
@@ -756,8 +632,8 @@ const RocketChat = {
 	getAvatarSuggestion() {
 		return call('getAvatarSuggestion');
 	},
-	resetAvatar() {
-		return call('resetAvatar');
+	resetAvatar(userId) {
+		return SDK.api.post('users.resetAvatar', { userId });
 	},
 	setAvatarFromService({ data, contentType = '', service = null }) {
 		return call('setAvatarFromService', data, contentType, service);
@@ -804,6 +680,30 @@ const RocketChat = {
 			c: 'channels', d: 'im', p: 'groups'
 		};
 		return types[t];
+	},
+	getFiles(roomId, type, offset) {
+		return SDK.api.get(`${ this.roomTypeToApiType(type) }.files`, {
+			roomId,
+			offset,
+			sort: { uploadedAt: -1 },
+			fields: {
+				name: 1, description: 1, size: 1, type: 1, uploadedAt: 1, url: 1, userId: 1
+			}
+		});
+	},
+	getMessages(roomId, type, query, offset) {
+		return SDK.api.get(`${ this.roomTypeToApiType(type) }.messages`, {
+			roomId,
+			query,
+			offset,
+			sort: { ts: -1 }
+		});
+	},
+	searchMessages(roomId, searchText) {
+		return SDK.api.get('chat.search', {
+			roomId,
+			searchText
+		});
 	}
 };
 
diff --git a/app/reducers/index.js b/app/reducers/index.js
index 86b6bcaa7..0eae9c996 100644
--- a/app/reducers/index.js
+++ b/app/reducers/index.js
@@ -12,11 +12,7 @@ import app from './app';
 import customEmojis from './customEmojis';
 import activeUsers from './activeUsers';
 import roles from './roles';
-import starredMessages from './starredMessages';
-import pinnedMessages from './pinnedMessages';
-import mentionedMessages from './mentionedMessages';
 import snippetedMessages from './snippetedMessages';
-import roomFiles from './roomFiles';
 import sortPreferences from './sortPreferences';
 
 export default combineReducers({
@@ -33,10 +29,6 @@ export default combineReducers({
 	customEmojis,
 	activeUsers,
 	roles,
-	starredMessages,
-	pinnedMessages,
-	mentionedMessages,
 	snippetedMessages,
-	roomFiles,
 	sortPreferences
 });
diff --git a/app/reducers/mentionedMessages.js b/app/reducers/mentionedMessages.js
deleted file mode 100644
index f8c445dd9..000000000
--- a/app/reducers/mentionedMessages.js
+++ /dev/null
@@ -1,30 +0,0 @@
-import { MENTIONED_MESSAGES } from '../actions/actionsTypes';
-
-const initialState = {
-	messages: [],
-	ready: false
-};
-
-export default function server(state = initialState, action) {
-	switch (action.type) {
-		case MENTIONED_MESSAGES.OPEN:
-			return {
-				...state,
-				ready: false
-			};
-		case MENTIONED_MESSAGES.READY:
-			return {
-				...state,
-				ready: true
-			};
-		case MENTIONED_MESSAGES.MESSAGES_RECEIVED:
-			return {
-				...state,
-				messages: [...state.messages, ...action.messages]
-			};
-		case MENTIONED_MESSAGES.CLOSE:
-			return initialState;
-		default:
-			return state;
-	}
-}
diff --git a/app/reducers/pinnedMessages.js b/app/reducers/pinnedMessages.js
deleted file mode 100644
index d912e5b7a..000000000
--- a/app/reducers/pinnedMessages.js
+++ /dev/null
@@ -1,37 +0,0 @@
-import { PINNED_MESSAGES } from '../actions/actionsTypes';
-
-const initialState = {
-	messages: [],
-	isOpen: false,
-	ready: false
-};
-
-export default function server(state = initialState, action) {
-	switch (action.type) {
-		case PINNED_MESSAGES.OPEN:
-			return {
-				...state,
-				isOpen: true,
-				ready: false
-			};
-		case PINNED_MESSAGES.READY:
-			return {
-				...state,
-				ready: true
-			};
-		case PINNED_MESSAGES.MESSAGES_RECEIVED:
-			return {
-				...state,
-				messages: [...state.messages, ...action.messages]
-			};
-		case PINNED_MESSAGES.MESSAGE_UNPINNED:
-			return {
-				...state,
-				messages: state.messages.filter(message => message._id !== action.messageId)
-			};
-		case PINNED_MESSAGES.CLOSE:
-			return initialState;
-		default:
-			return state;
-	}
-}
diff --git a/app/reducers/roomFiles.js b/app/reducers/roomFiles.js
deleted file mode 100644
index 911f295a7..000000000
--- a/app/reducers/roomFiles.js
+++ /dev/null
@@ -1,30 +0,0 @@
-import { ROOM_FILES } from '../actions/actionsTypes';
-
-const initialState = {
-	messages: [],
-	ready: false
-};
-
-export default function server(state = initialState, action) {
-	switch (action.type) {
-		case ROOM_FILES.OPEN:
-			return {
-				...state,
-				ready: false
-			};
-		case ROOM_FILES.READY:
-			return {
-				...state,
-				ready: true
-			};
-		case ROOM_FILES.MESSAGES_RECEIVED:
-			return {
-				...state,
-				messages: [...state.messages, ...action.messages]
-			};
-		case ROOM_FILES.CLOSE:
-			return initialState;
-		default:
-			return state;
-	}
-}
diff --git a/app/reducers/starredMessages.js b/app/reducers/starredMessages.js
deleted file mode 100644
index b96fbe87c..000000000
--- a/app/reducers/starredMessages.js
+++ /dev/null
@@ -1,37 +0,0 @@
-import { STARRED_MESSAGES } from '../actions/actionsTypes';
-
-const initialState = {
-	messages: [],
-	isOpen: false,
-	ready: false
-};
-
-export default function server(state = initialState, action) {
-	switch (action.type) {
-		case STARRED_MESSAGES.OPEN:
-			return {
-				...state,
-				isOpen: true,
-				ready: false
-			};
-		case STARRED_MESSAGES.READY:
-			return {
-				...state,
-				ready: true
-			};
-		case STARRED_MESSAGES.MESSAGES_RECEIVED:
-			return {
-				...state,
-				messages: [...state.messages, ...action.messages]
-			};
-		case STARRED_MESSAGES.MESSAGE_UNSTARRED:
-			return {
-				...state,
-				messages: state.messages.filter(message => message._id !== action.messageId)
-			};
-		case STARRED_MESSAGES.CLOSE:
-			return initialState;
-		default:
-			return state;
-	}
-}
diff --git a/app/sagas/index.js b/app/sagas/index.js
index d0e0d675d..b85e72291 100644
--- a/app/sagas/index.js
+++ b/app/sagas/index.js
@@ -6,11 +6,7 @@ import selectServer from './selectServer';
 import createChannel from './createChannel';
 import init from './init';
 import state from './state';
-import starredMessages from './starredMessages';
-import pinnedMessages from './pinnedMessages';
-import mentionedMessages from './mentionedMessages';
 import snippetedMessages from './snippetedMessages';
-import roomFiles from './roomFiles';
 import deepLinking from './deepLinking';
 
 const root = function* root() {
@@ -22,11 +18,7 @@ const root = function* root() {
 		messages(),
 		selectServer(),
 		state(),
-		starredMessages(),
-		pinnedMessages(),
-		mentionedMessages(),
 		snippetedMessages(),
-		roomFiles(),
 		deepLinking()
 	]);
 };
diff --git a/app/sagas/login.js b/app/sagas/login.js
index 6dad0566c..1937f06b1 100644
--- a/app/sagas/login.js
+++ b/app/sagas/login.js
@@ -33,7 +33,8 @@ const handleLoginRequest = function* handleLoginRequest({ credentials }) {
 				username: data.me.username,
 				name: data.me.name,
 				language: data.me.language,
-				status: data.me.status
+				status: data.me.status,
+				customFields: data.me.customFields
 			};
 			return yield put(loginSuccess(user));
 		}
diff --git a/app/sagas/mentionedMessages.js b/app/sagas/mentionedMessages.js
deleted file mode 100644
index 6543a15cc..000000000
--- a/app/sagas/mentionedMessages.js
+++ /dev/null
@@ -1,41 +0,0 @@
-import { put, takeLatest } from 'redux-saga/effects';
-
-import * as types from '../actions/actionsTypes';
-import RocketChat from '../lib/rocketchat';
-import { readyMentionedMessages } from '../actions/mentionedMessages';
-import log from '../utils/log';
-
-let sub;
-let newSub;
-
-const openMentionedMessagesRoom = function* openMentionedMessagesRoom({ rid, limit }) {
-	try {
-		newSub = yield RocketChat.subscribe('mentionedMessages', rid, limit);
-		yield put(readyMentionedMessages());
-		if (sub) {
-			sub.unsubscribe().catch(err => console.warn(err));
-		}
-		sub = newSub;
-	} catch (e) {
-		log('openMentionedMessagesRoom', e);
-	}
-};
-
-const closeMentionedMessagesRoom = function* closeMentionedMessagesRoom() {
-	try {
-		if (sub) {
-			yield sub.unsubscribe();
-		}
-		if (newSub) {
-			yield newSub.unsubscribe();
-		}
-	} catch (e) {
-		log('closeMentionedMessagesRoom', e);
-	}
-};
-
-const root = function* root() {
-	yield takeLatest(types.MENTIONED_MESSAGES.OPEN, openMentionedMessagesRoom);
-	yield takeLatest(types.MENTIONED_MESSAGES.CLOSE, closeMentionedMessagesRoom);
-};
-export default root;
diff --git a/app/sagas/pinnedMessages.js b/app/sagas/pinnedMessages.js
deleted file mode 100644
index b14007f83..000000000
--- a/app/sagas/pinnedMessages.js
+++ /dev/null
@@ -1,41 +0,0 @@
-import { put, takeLatest } from 'redux-saga/effects';
-
-import * as types from '../actions/actionsTypes';
-import RocketChat from '../lib/rocketchat';
-import { readyPinnedMessages } from '../actions/pinnedMessages';
-import log from '../utils/log';
-
-let sub;
-let newSub;
-
-const openPinnedMessagesRoom = function* openPinnedMessagesRoom({ rid, limit }) {
-	try {
-		newSub = yield RocketChat.subscribe('pinnedMessages', rid, limit);
-		yield put(readyPinnedMessages());
-		if (sub) {
-			sub.unsubscribe().catch(err => console.warn(err));
-		}
-		sub = newSub;
-	} catch (e) {
-		log('openPinnedMessagesRoom', e);
-	}
-};
-
-const closePinnedMessagesRoom = function* closePinnedMessagesRoom() {
-	try {
-		if (sub) {
-			yield sub.unsubscribe();
-		}
-		if (newSub) {
-			yield newSub.unsubscribe();
-		}
-	} catch (e) {
-		log('closePinnedMessagesRoom', e);
-	}
-};
-
-const root = function* root() {
-	yield takeLatest(types.PINNED_MESSAGES.OPEN, openPinnedMessagesRoom);
-	yield takeLatest(types.PINNED_MESSAGES.CLOSE, closePinnedMessagesRoom);
-};
-export default root;
diff --git a/app/sagas/roomFiles.js b/app/sagas/roomFiles.js
deleted file mode 100644
index 42a01988d..000000000
--- a/app/sagas/roomFiles.js
+++ /dev/null
@@ -1,43 +0,0 @@
-import { put, takeLatest } from 'redux-saga/effects';
-
-import * as types from '../actions/actionsTypes';
-import RocketChat from '../lib/rocketchat';
-import { readyRoomFiles } from '../actions/roomFiles';
-import log from '../utils/log';
-
-let sub;
-let newSub;
-
-const openRoomFiles = function* openRoomFiles({ rid, limit }) {
-	try {
-		sub = yield RocketChat.subscribe('roomFiles', rid, limit);
-		yield put(readyRoomFiles());
-		if (sub) {
-			sub.unsubscribe().catch(err => console.warn(err));
-		}
-		sub = newSub;
-	} catch (e) {
-		log('openRoomFiles', e);
-	}
-};
-
-const closeRoomFiles = function* closeRoomFiles() {
-	try {
-		// yield sub.unsubscribe(sub);
-		// sub = null;
-		if (sub) {
-			yield sub.unsubscribe();
-		}
-		if (newSub) {
-			yield newSub.unsubscribe();
-		}
-	} catch (e) {
-		log('closeRoomFiles', e);
-	}
-};
-
-const root = function* root() {
-	yield takeLatest(types.ROOM_FILES.OPEN, openRoomFiles);
-	yield takeLatest(types.ROOM_FILES.CLOSE, closeRoomFiles);
-};
-export default root;
diff --git a/app/sagas/rooms.js b/app/sagas/rooms.js
index 6c1df3a89..defc7c563 100644
--- a/app/sagas/rooms.js
+++ b/app/sagas/rooms.js
@@ -13,8 +13,6 @@ import database from '../lib/realm';
 import log from '../utils/log';
 import I18n from '../i18n';
 
-const eraseRoom = rid => RocketChat.eraseRoom(rid);
-
 let sub;
 let thread;
 
@@ -120,25 +118,13 @@ const watchuserTyping = function* watchuserTyping({ status }) {
 	}
 };
 
-const goRoomsListAndDelete = function* goRoomsListAndDelete(rid) {
-	yield Navigation.popToRoot('RoomsListView');
-	try {
-		database.write(() => {
-			const messages = database.objects('messages').filtered('rid = $0', rid);
-			database.delete(messages);
-			const subscription = database.objects('subscriptions').filtered('rid = $0', rid);
-			database.delete(subscription);
-		});
-	} catch (error) {
-		console.warn('goRoomsListAndDelete', error);
-	}
-};
-
 const handleLeaveRoom = function* handleLeaveRoom({ rid, t }) {
 	try {
 		sub.stop();
-		yield RocketChat.leaveRoom(rid, t);
-		yield goRoomsListAndDelete(rid);
+		const result = yield RocketChat.leaveRoom(rid, t);
+		if (result.success) {
+			yield Navigation.popToRoot('RoomsListView');
+		}
 	} catch (e) {
 		if (e.data && e.data.errorType === 'error-you-are-last-owner') {
 			Alert.alert(I18n.t('Oops'), I18n.t(e.data.errorType));
@@ -148,11 +134,13 @@ const handleLeaveRoom = function* handleLeaveRoom({ rid, t }) {
 	}
 };
 
-const handleEraseRoom = function* handleEraseRoom({ rid }) {
+const handleEraseRoom = function* handleEraseRoom({ rid, t }) {
 	try {
 		sub.stop();
-		yield eraseRoom(rid);
-		yield goRoomsListAndDelete(rid, 'erase');
+		const result = yield RocketChat.eraseRoom(rid, t);
+		if (result.success) {
+			yield Navigation.popToRoot('RoomsListView');
+		}
 	} catch (e) {
 		Alert.alert(I18n.t('Oops'), I18n.t('There_was_an_error_while_action', { action: I18n.t('erasing_room') }));
 	}
diff --git a/app/sagas/starredMessages.js b/app/sagas/starredMessages.js
deleted file mode 100644
index dcba28958..000000000
--- a/app/sagas/starredMessages.js
+++ /dev/null
@@ -1,41 +0,0 @@
-import { put, takeLatest } from 'redux-saga/effects';
-
-import * as types from '../actions/actionsTypes';
-import RocketChat from '../lib/rocketchat';
-import { readyStarredMessages } from '../actions/starredMessages';
-import log from '../utils/log';
-
-let sub;
-let newSub;
-
-const openStarredMessagesRoom = function* openStarredMessagesRoom({ rid, limit }) {
-	try {
-		newSub = yield RocketChat.subscribe('starredMessages', rid, limit);
-		yield put(readyStarredMessages());
-		if (sub) {
-			sub.unsubscribe().catch(err => console.warn(err));
-		}
-		sub = newSub;
-	} catch (e) {
-		log('openStarredMessagesRoom', e);
-	}
-};
-
-const closeStarredMessagesRoom = function* closeStarredMessagesRoom() {
-	try {
-		if (sub) {
-			yield sub.unsubscribe();
-		}
-		if (newSub) {
-			yield newSub.unsubscribe();
-		}
-	} catch (e) {
-		log('closeStarredMessagesRoom', e);
-	}
-};
-
-const root = function* root() {
-	yield takeLatest(types.STARRED_MESSAGES.OPEN, openStarredMessagesRoom);
-	yield takeLatest(types.STARRED_MESSAGES.CLOSE, closeStarredMessagesRoom);
-};
-export default root;
diff --git a/app/views/MentionedMessagesView/index.js b/app/views/MentionedMessagesView/index.js
index ef461b23e..524b69b4e 100644
--- a/app/views/MentionedMessagesView/index.js
+++ b/app/views/MentionedMessagesView/index.js
@@ -3,26 +3,25 @@ import PropTypes from 'prop-types';
 import { FlatList, View, Text } from 'react-native';
 import { connect } from 'react-redux';
 import SafeAreaView from 'react-native-safe-area-view';
+import equal from 'deep-equal';
 
-import { openMentionedMessages as openMentionedMessagesAction, closeMentionedMessages as closeMentionedMessagesAction } from '../../actions/mentionedMessages';
 import LoggedView from '../View';
 import styles from './styles';
-import Message from '../../containers/message';
+import Message from '../../containers/message/Message';
 import RCActivityIndicator from '../../containers/ActivityIndicator';
 import I18n from '../../i18n';
 import { DEFAULT_HEADER } from '../../constants/headerOptions';
+import RocketChat from '../../lib/rocketchat';
+import database from '../../lib/realm';
 
 @connect(state => ({
-	messages: state.mentionedMessages.messages,
-	ready: state.mentionedMessages.ready,
+	baseUrl: state.settings.Site_Url || state.server ? state.server.server : '',
+	customEmojis: state.customEmojis,
 	user: {
 		id: state.login.user && state.login.user.id,
 		username: state.login.user && state.login.user.username,
 		token: state.login.user && state.login.user.token
 	}
-}), dispatch => ({
-	openMentionedMessages: (rid, limit) => dispatch(openMentionedMessagesAction(rid, limit)),
-	closeMentionedMessages: () => dispatch(closeMentionedMessagesAction())
 }))
 /** @extends React.Component */
 export default class MentionedMessagesView extends LoggedView {
@@ -41,53 +40,57 @@ export default class MentionedMessagesView extends LoggedView {
 
 	static propTypes = {
 		rid: PropTypes.string,
-		messages: PropTypes.array,
-		ready: PropTypes.bool,
 		user: PropTypes.object,
-		openMentionedMessages: PropTypes.func,
-		closeMentionedMessages: PropTypes.func
+		baseUrl: PropTypes.string,
+		customEmojis: PropTypes.object
 	}
 
 	constructor(props) {
-		super('MentionedMessagesView', props);
+		super('StarredMessagesView', props);
+		this.rooms = database.objects('subscriptions').filtered('rid = $0', props.rid);
 		this.state = {
-			loading: true,
-			loadingMore: false
+			loading: false,
+			room: this.rooms[0],
+			messages: []
 		};
 	}
 
 	componentDidMount() {
-		this.limit = 20;
 		this.load();
 	}
 
-	componentWillReceiveProps(nextProps) {
-		const { ready } = this.props;
-		if (nextProps.ready && nextProps.ready !== ready) {
-			this.setState({ loading: false, loadingMore: false });
-		}
-	}
-
-	componentWillUnmount() {
-		const { closeMentionedMessages } = this.props;
-		closeMentionedMessages();
-	}
-
-	load = () => {
-		const { openMentionedMessages, rid } = this.props;
-		openMentionedMessages(rid, this.limit);
+	shouldComponentUpdate(nextProps, nextState) {
+		return !equal(this.state, nextState);
 	}
 
-	moreData = () => {
-		const { loadingMore } = this.state;
-		const { messages } = this.props;
-		if (messages.length < this.limit) {
+	load = async() => {
+		const {
+			messages, total, loading, room
+		} = this.state;
+		const { user } = this.props;
+		if (messages.length === total || loading) {
 			return;
 		}
-		if (!loadingMore) {
-			this.setState({ loadingMore: true });
-			this.limit += 20;
-			this.load();
+
+		this.setState({ loading: true });
+
+		try {
+			const result = await RocketChat.getMessages(
+				room.rid,
+				room.t,
+				{ 'mentions._id': { $in: [user.id] } },
+				messages.length
+			);
+			if (result.success) {
+				this.setState(prevState => ({
+					messages: [...prevState.messages, ...result.messages],
+					total: result.total,
+					loading: false
+				}));
+			}
+		} catch (error) {
+			this.setState({ loading: false });
+			console.log('MentionedMessagesView -> load -> catch -> error', error);
 		}
 	}
 
@@ -98,23 +101,28 @@ export default class MentionedMessagesView extends LoggedView {
 	)
 
 	renderItem = ({ item }) => {
-		const { user } = this.props;
+		const { user, customEmojis, baseUrl } = this.props;
 		return (
 			<Message
-				item={item}
 				style={styles.message}
-				reactions={item.reactions}
+				customEmojis={customEmojis}
+				baseUrl={baseUrl}
 				user={user}
-				customTimeFormat='MMMM Do YYYY, h:mm:ss a'
+				author={item.u}
+				ts={item.ts}
+				msg={item.msg}
+				attachments={item.attachments || []}
+				timeFormat='MMM Do YYYY, h:mm:ss a'
+				edited={!!item.editedAt}
+				header
 			/>
 		);
 	}
 
 	render() {
-		const { loading, loadingMore } = this.state;
-		const { messages, ready } = this.props;
+		const { messages, loading } = this.state;
 
-		if (ready && messages.length === 0) {
+		if (!loading && messages.length === 0) {
 			return this.renderEmpty();
 		}
 
@@ -125,9 +133,8 @@ export default class MentionedMessagesView extends LoggedView {
 					renderItem={this.renderItem}
 					style={styles.list}
 					keyExtractor={item => item._id}
-					onEndReached={this.moreData}
-					ListHeaderComponent={loading ? <RCActivityIndicator /> : null}
-					ListFooterComponent={loadingMore ? <RCActivityIndicator /> : null}
+					onEndReached={this.load}
+					ListFooterComponent={loading ? <RCActivityIndicator /> : null}
 				/>
 			</SafeAreaView>
 		);
diff --git a/app/views/PinnedMessagesView/index.js b/app/views/PinnedMessagesView/index.js
index daba4ae39..544ce1caf 100644
--- a/app/views/PinnedMessagesView/index.js
+++ b/app/views/PinnedMessagesView/index.js
@@ -4,32 +4,29 @@ import { FlatList, View, Text } from 'react-native';
 import { connect } from 'react-redux';
 import ActionSheet from 'react-native-actionsheet';
 import SafeAreaView from 'react-native-safe-area-view';
+import equal from 'deep-equal';
 
-import { openPinnedMessages as openPinnedMessagesAction, closePinnedMessages as closePinnedMessagesAction } from '../../actions/pinnedMessages';
-import { togglePinRequest as togglePinRequestAction } from '../../actions/messages';
 import LoggedView from '../View';
 import styles from './styles';
-import Message from '../../containers/message';
+import Message from '../../containers/message/Message';
 import RCActivityIndicator from '../../containers/ActivityIndicator';
 import I18n from '../../i18n';
 import { DEFAULT_HEADER } from '../../constants/headerOptions';
+import RocketChat from '../../lib/rocketchat';
+import database from '../../lib/realm';
 
 const PIN_INDEX = 0;
 const CANCEL_INDEX = 1;
 const options = [I18n.t('Unpin'), I18n.t('Cancel')];
 
 @connect(state => ({
-	messages: state.pinnedMessages.messages,
-	ready: state.pinnedMessages.ready,
+	baseUrl: state.settings.Site_Url || state.server ? state.server.server : '',
+	customEmojis: state.customEmojis,
 	user: {
 		id: state.login.user && state.login.user.id,
 		username: state.login.user && state.login.user.username,
 		token: state.login.user && state.login.user.token
 	}
-}), dispatch => ({
-	openPinnedMessages: (rid, limit) => dispatch(openPinnedMessagesAction(rid, limit)),
-	closePinnedMessages: () => dispatch(closePinnedMessagesAction()),
-	togglePinRequest: message => dispatch(togglePinRequestAction(message))
 }))
 /** @extends React.Component */
 export default class PinnedMessagesView extends LoggedView {
@@ -48,38 +45,27 @@ export default class PinnedMessagesView extends LoggedView {
 
 	static propTypes = {
 		rid: PropTypes.string,
-		messages: PropTypes.array,
-		ready: PropTypes.bool,
 		user: PropTypes.object,
-		openPinnedMessages: PropTypes.func,
-		closePinnedMessages: PropTypes.func,
-		togglePinRequest: PropTypes.func
+		baseUrl: PropTypes.string,
+		customEmojis: PropTypes.object
 	}
 
 	constructor(props) {
 		super('PinnedMessagesView', props);
+		this.rooms = database.objects('subscriptions').filtered('rid = $0', props.rid);
 		this.state = {
-			message: {},
-			loading: true,
-			loadingMore: false
+			loading: false,
+			room: this.rooms[0],
+			messages: []
 		};
 	}
 
 	componentDidMount() {
-		this.limit = 20;
 		this.load();
 	}
 
-	componentWillReceiveProps(nextProps) {
-		const { ready } = this.props;
-		if (nextProps.ready && nextProps.ready !== ready) {
-			this.setState({ loading: false, loadingMore: false });
-		}
-	}
-
-	componentWillUnmount() {
-		const { closePinnedMessages } = this.props;
-		closePinnedMessages();
+	shouldComponentUpdate(nextProps, nextState) {
+		return !equal(this.state, nextState);
 	}
 
 	onLongPress = (message) => {
@@ -90,33 +76,51 @@ export default class PinnedMessagesView extends LoggedView {
 	}
 
 	handleActionPress = (actionIndex) => {
-		const { message } = this.state;
-		const { togglePinRequest } = this.props;
-
 		switch (actionIndex) {
 			case PIN_INDEX:
-				togglePinRequest(message);
+				this.unPin();
 				break;
 			default:
 				break;
 		}
 	}
 
-	load = () => {
-		const { openPinnedMessages, rid } = this.props;
-		openPinnedMessages(rid, this.limit);
+	unPin = async() => {
+		const { message } = this.state;
+		try {
+			const result = await RocketChat.togglePinMessage(message);
+			if (result.success) {
+				this.setState(prevState => ({
+					messages: prevState.messages.filter(item => item._id !== message._id)
+				}));
+			}
+		} catch (error) {
+			console.log('PinnedMessagesView -> unPin -> catch -> error', error);
+		}
 	}
 
-	moreData = () => {
-		const { loadingMore } = this.state;
-		const { messages } = this.props;
-		if (messages.length < this.limit) {
+	load = async() => {
+		const {
+			messages, total, loading, room
+		} = this.state;
+		if (messages.length === total || loading) {
 			return;
 		}
-		if (!loadingMore) {
-			this.setState({ loadingMore: true });
-			this.limit += 20;
-			this.load();
+
+		this.setState({ loading: true });
+
+		try {
+			const result = await RocketChat.getMessages(room.rid, room.t, { pinned: true }, messages.length);
+			if (result.success) {
+				this.setState(prevState => ({
+					messages: [...prevState.messages, ...result.messages],
+					total: result.total,
+					loading: false
+				}));
+			}
+		} catch (error) {
+			this.setState({ loading: false });
+			console.log('PinnedMessagesView -> catch -> error', error);
 		}
 	}
 
@@ -127,24 +131,29 @@ export default class PinnedMessagesView extends LoggedView {
 	)
 
 	renderItem = ({ item }) => {
-		const { user } = this.props;
+		const { user, customEmojis, baseUrl } = this.props;
 		return (
 			<Message
-				item={item}
 				style={styles.message}
-				reactions={item.reactions}
+				customEmojis={customEmojis}
+				baseUrl={baseUrl}
 				user={user}
-				customTimeFormat='MMMM Do YYYY, h:mm:ss a'
-				onLongPress={this.onLongPress}
+				author={item.u}
+				ts={item.ts}
+				msg={item.msg}
+				attachments={item.attachments || []}
+				timeFormat='MMM Do YYYY, h:mm:ss a'
+				header
+				edited={!!item.editedAt}
+				onLongPress={() => this.onLongPress(item)}
 			/>
 		);
 	}
 
 	render() {
-		const { loading, loadingMore } = this.state;
-		const { messages, ready } = this.props;
+		const { messages, loading } = this.state;
 
-		if (ready && messages.length === 0) {
+		if (!loading && messages.length === 0) {
 			return this.renderEmpty();
 		}
 
@@ -155,9 +164,8 @@ export default class PinnedMessagesView extends LoggedView {
 					renderItem={this.renderItem}
 					style={styles.list}
 					keyExtractor={item => item._id}
-					onEndReached={this.moreData}
-					ListHeaderComponent={loading ? <RCActivityIndicator /> : null}
-					ListFooterComponent={loadingMore ? <RCActivityIndicator /> : null}
+					onEndReached={this.load}
+					ListFooterComponent={loading ? <RCActivityIndicator /> : null}
 				/>
 				<ActionSheet
 					ref={o => this.actionSheet = o}
diff --git a/app/views/ProfileView/index.js b/app/views/ProfileView/index.js
index c688327d0..527727447 100644
--- a/app/views/ProfileView/index.js
+++ b/app/views/ProfileView/index.js
@@ -20,7 +20,6 @@ import scrollPersistTaps from '../../utils/scrollPersistTaps';
 import { showErrorAlert, showToast } from '../../utils/info';
 import RocketChat from '../../lib/rocketchat';
 import RCTextInput from '../../containers/TextInput';
-import Loading from '../../containers/Loading';
 import log from '../../utils/log';
 import I18n from '../../i18n';
 import Button from '../../containers/Button';
@@ -29,9 +28,11 @@ import Touch from '../../utils/touch';
 import Drawer from '../../Drawer';
 import { DEFAULT_HEADER } from '../../constants/headerOptions';
 import { appStart as appStartAction } from '../../actions';
+import { setUser as setUserAction } from '../../actions/login';
 
 @connect(state => ({
 	user: {
+		id: state.login.user && state.login.user.id,
 		name: state.login.user && state.login.user.name,
 		username: state.login.user && state.login.user.username,
 		customFields: state.login.user && state.login.user.customFields,
@@ -40,7 +41,8 @@ import { appStart as appStartAction } from '../../actions';
 	Accounts_CustomFields: state.settings.Accounts_CustomFields,
 	baseUrl: state.settings.Site_Url || state.server ? state.server.server : ''
 }), dispatch => ({
-	appStart: () => dispatch(appStartAction())
+	appStart: () => dispatch(appStartAction()),
+	setUser: params => dispatch(setUserAction(params))
 }))
 /** @extends React.Component */
 export default class ProfileView extends LoggedView {
@@ -75,7 +77,8 @@ export default class ProfileView extends LoggedView {
 		componentId: PropTypes.string,
 		user: PropTypes.object,
 		Accounts_CustomFields: PropTypes.string,
-		appStart: PropTypes.func
+		appStart: PropTypes.func,
+		setUser: PropTypes.func
 	}
 
 	constructor(props) {
@@ -87,7 +90,7 @@ export default class ProfileView extends LoggedView {
 			username: null,
 			email: null,
 			newPassword: null,
-			typedPassword: null,
+			currentPassword: null,
 			avatarUrl: null,
 			avatar: {},
 			avatarSuggestions: {},
@@ -146,7 +149,7 @@ export default class ProfileView extends LoggedView {
 			username,
 			email: emails ? emails[0].address : null,
 			newPassword: null,
-			typedPassword: null,
+			currentPassword: null,
 			avatarUrl: null,
 			avatar: {},
 			customFields: customFields || {}
@@ -163,7 +166,7 @@ export default class ProfileView extends LoggedView {
 		const customFieldsKeys = Object.keys(customFields);
 		if (customFieldsKeys.length) {
 			customFieldsKeys.forEach((key) => {
-				if (user.customFields[key] !== customFields[key]) {
+				if (!user.customFields || user.customFields[key] !== customFields[key]) {
 					customFieldsChanged = true;
 				}
 			});
@@ -183,13 +186,8 @@ export default class ProfileView extends LoggedView {
 	}
 
 	handleError = (e, func, action) => {
-		if (e && e.error && e.error !== 500) {
-			if (e.details && e.details.timeToReset) {
-				return showErrorAlert(I18n.t('error-too-many-requests', {
-					seconds: parseInt(e.details.timeToReset / 1000, 10)
-				}));
-			}
-			return showErrorAlert(I18n.t(e.error, e.details));
+		if (e.data && e.data.errorType === 'error-too-many-requests') {
+			return showErrorAlert(e.data.error);
 		}
 		showErrorAlert(I18n.t('There_was_an_error_while_action', { action: I18n.t(action) }));
 		log(func, e);
@@ -205,14 +203,14 @@ export default class ProfileView extends LoggedView {
 		this.setState({ saving: true, showPasswordAlert: false });
 
 		const {
-			name, username, email, newPassword, typedPassword, avatar, customFields
+			name, username, email, newPassword, currentPassword, avatar, customFields
 		} = this.state;
-		const { user } = this.props;
+		const { user, setUser } = this.props;
 		const params = {};
 
 		// Name
 		if (user.name !== name) {
-			params.realname = name;
+			params.name = name;
 		}
 
 		// Username
@@ -230,13 +228,13 @@ export default class ProfileView extends LoggedView {
 			params.newPassword = newPassword;
 		}
 
-		// typedPassword
-		if (typedPassword) {
-			params.typedPassword = SHA256(typedPassword);
+		// currentPassword
+		if (currentPassword) {
+			params.currentPassword = SHA256(currentPassword);
 		}
 
 		const requirePassword = !!params.email || newPassword;
-		if (requirePassword && !params.typedPassword) {
+		if (requirePassword && !params.currentPassword) {
 			return this.setState({ showPasswordAlert: true, saving: false });
 		}
 
@@ -245,28 +243,32 @@ export default class ProfileView extends LoggedView {
 				try {
 					await RocketChat.setAvatarFromService(avatar);
 				} catch (e) {
-					this.setState({ saving: false, typedPassword: null });
-					return setTimeout(() => this.handleError(e, 'setAvatarFromService', 'changing_avatar'), 300);
+					this.setState({ saving: false, currentPassword: null });
+					return this.handleError(e, 'setAvatarFromService', 'changing_avatar');
 				}
 			}
 
-			await RocketChat.saveUserProfile(params, customFields);
-			this.setState({ saving: false });
-			setTimeout(() => {
+			params.customFields = customFields;
+
+			const result = await RocketChat.saveUserProfile(params);
+			if (result.success) {
+				if (params.customFields) {
+					setUser({ customFields });
+				}
+				this.setState({ saving: false });
 				showToast(I18n.t('Profile_saved_successfully'));
 				this.init();
-			}, 300);
+			}
 		} catch (e) {
-			this.setState({ saving: false, typedPassword: null });
-			setTimeout(() => {
-				this.handleError(e, 'saveUserProfile', 'saving_profile');
-			}, 300);
+			this.setState({ saving: false, currentPassword: null });
+			this.handleError(e, 'saveUserProfile', 'saving_profile');
 		}
 	}
 
 	resetAvatar = async() => {
 		try {
-			await RocketChat.resetAvatar();
+			const { user } = this.props;
+			await RocketChat.resetAvatar(user.id);
 			showToast(I18n.t('Avatar_changed_successfully'));
 			this.init();
 		} catch (e) {
@@ -353,53 +355,57 @@ export default class ProfileView extends LoggedView {
 		if (!Accounts_CustomFields) {
 			return null;
 		}
-		const parsedCustomFields = JSON.parse(Accounts_CustomFields);
-		return Object.keys(parsedCustomFields).map((key, index, array) => {
-			if (parsedCustomFields[key].type === 'select') {
-				const options = parsedCustomFields[key].options.map(option => ({ label: option, value: option }));
+		try {
+			const parsedCustomFields = JSON.parse(Accounts_CustomFields);
+			return Object.keys(parsedCustomFields).map((key, index, array) => {
+				if (parsedCustomFields[key].type === 'select') {
+					const options = parsedCustomFields[key].options.map(option => ({ label: option, value: option }));
+					return (
+						<RNPickerSelect
+							key={key}
+							items={options}
+							onValueChange={(value) => {
+								const newValue = {};
+								newValue[key] = value;
+								this.setState({ customFields: { ...customFields, ...newValue } });
+							}}
+							value={customFields[key]}
+						>
+							<RCTextInput
+								inputRef={(e) => { this[key] = e; }}
+								label={key}
+								placeholder={key}
+								value={customFields[key]}
+								testID='settings-view-language'
+							/>
+						</RNPickerSelect>
+					);
+				}
+
 				return (
-					<RNPickerSelect
+					<RCTextInput
+						inputRef={(e) => { this[key] = e; }}
 						key={key}
-						items={options}
-						onValueChange={(value) => {
+						label={key}
+						placeholder={key}
+						value={customFields[key]}
+						onChangeText={(value) => {
 							const newValue = {};
 							newValue[key] = value;
 							this.setState({ customFields: { ...customFields, ...newValue } });
 						}}
-						value={customFields[key]}
-					>
-						<RCTextInput
-							inputRef={(e) => { this[key] = e; }}
-							label={key}
-							placeholder={key}
-							value={customFields[key]}
-							testID='settings-view-language'
-						/>
-					</RNPickerSelect>
+						onSubmitEditing={() => {
+							if (array.length - 1 > index) {
+								return this[array[index + 1]].focus();
+							}
+							this.avatarUrl.focus();
+						}}
+					/>
 				);
-			}
-
-			return (
-				<RCTextInput
-					inputRef={(e) => { this[key] = e; }}
-					key={key}
-					label={key}
-					placeholder={key}
-					value={customFields[key]}
-					onChangeText={(value) => {
-						const newValue = {};
-						newValue[key] = value;
-						this.setState({ customFields: { ...customFields, ...newValue } });
-					}}
-					onSubmitEditing={() => {
-						if (array.length - 1 > index) {
-							return this[array[index + 1]].focus();
-						}
-						this.avatarUrl.focus();
-					}}
-				/>
-			);
-		});
+			});
+		} catch (error) {
+			return null;
+		}
 	}
 
 	render() {
@@ -480,16 +486,14 @@ export default class ProfileView extends LoggedView {
 							testID='profile-view-avatar-url'
 						/>
 						{this.renderAvatarButtons()}
-						<View style={sharedStyles.alignItemsFlexStart}>
-							<Button
-								title={I18n.t('Save_Changes')}
-								type='primary'
-								onPress={this.submit}
-								disabled={!this.formIsChanged()}
-								testID='profile-view-submit'
-							/>
-						</View>
-						<Loading visible={saving} />
+						<Button
+							title={I18n.t('Save_Changes')}
+							type='primary'
+							onPress={this.submit}
+							disabled={!this.formIsChanged()}
+							testID='profile-view-submit'
+							loading={saving}
+						/>
 						<Dialog.Container visible={showPasswordAlert}>
 							<Dialog.Title>
 								{I18n.t('Please_enter_your_password')}
@@ -498,7 +502,7 @@ export default class ProfileView extends LoggedView {
 								{I18n.t('For_your_security_you_must_enter_your_current_password_to_continue')}
 							</Dialog.Description>
 							<Dialog.Input
-								onChangeText={value => this.setState({ typedPassword: value })}
+								onChangeText={value => this.setState({ currentPassword: value })}
 								secureTextEntry
 								testID='profile-view-typed-password'
 								style={styles.dialogInput}
diff --git a/app/views/RoomActionsView/index.js b/app/views/RoomActionsView/index.js
index 329a91895..4a3a4c100 100644
--- a/app/views/RoomActionsView/index.js
+++ b/app/views/RoomActionsView/index.js
@@ -68,7 +68,9 @@ export default class RoomActionsView extends LoggedView {
 		this.state = {
 			room: this.rooms[0] || {},
 			membersCount: 0,
-			member: {}
+			member: {},
+			joined: false,
+			canViewMembers: false
 		};
 	}
 
@@ -86,6 +88,9 @@ export default class RoomActionsView extends LoggedView {
 			}
 		}
 
+		if (room.t === 'd') {
+			this.updateRoomMember();
+		}
 		this.rooms.addListener(this.updateRoom);
 	}
 
@@ -310,6 +315,20 @@ export default class RoomActionsView extends LoggedView {
 		this.setState({ room: this.rooms[0] || {} });
 	}
 
+	updateRoomMember = async() => {
+		const { room } = this.state;
+		const { rid } = room;
+		const { userId } = this.props;
+
+		try {
+			const member = await RocketChat.getRoomMember(rid, userId);
+			this.setState({ member });
+		} catch (e) {
+			log('RoomActions updateRoomMember', e);
+			return {};
+		}
+	}
+
 	toggleBlockUser = () => {
 		const { room } = this.state;
 		const { rid, blocker } = room;
diff --git a/app/views/RoomFilesView/index.js b/app/views/RoomFilesView/index.js
index be34d5057..354c772ca 100644
--- a/app/views/RoomFilesView/index.js
+++ b/app/views/RoomFilesView/index.js
@@ -3,26 +3,25 @@ import PropTypes from 'prop-types';
 import { FlatList, View, Text } from 'react-native';
 import { connect } from 'react-redux';
 import SafeAreaView from 'react-native-safe-area-view';
+import equal from 'deep-equal';
 
-import { openRoomFiles as openRoomFilesAction, closeRoomFiles as closeRoomFilesAction } from '../../actions/roomFiles';
 import LoggedView from '../View';
 import styles from './styles';
-import Message from '../../containers/message';
+import Message from '../../containers/message/Message';
 import RCActivityIndicator from '../../containers/ActivityIndicator';
 import I18n from '../../i18n';
 import { DEFAULT_HEADER } from '../../constants/headerOptions';
+import database from '../../lib/realm';
+import RocketChat from '../../lib/rocketchat';
 
 @connect(state => ({
-	messages: state.roomFiles.messages,
-	ready: state.roomFiles.ready,
+	baseUrl: state.settings.Site_Url || state.server ? state.server.server : '',
+	customEmojis: state.customEmojis,
 	user: {
 		id: state.login.user && state.login.user.id,
 		username: state.login.user && state.login.user.username,
 		token: state.login.user && state.login.user.token
 	}
-}), dispatch => ({
-	openRoomFiles: (rid, limit) => dispatch(openRoomFilesAction(rid, limit)),
-	closeRoomFiles: () => dispatch(closeRoomFilesAction())
 }))
 /** @extends React.Component */
 export default class RoomFilesView extends LoggedView {
@@ -41,53 +40,51 @@ export default class RoomFilesView extends LoggedView {
 
 	static propTypes = {
 		rid: PropTypes.string,
-		messages: PropTypes.array,
-		ready: PropTypes.bool,
 		user: PropTypes.object,
-		openRoomFiles: PropTypes.func,
-		closeRoomFiles: PropTypes.func
+		baseUrl: PropTypes.string,
+		customEmojis: PropTypes.object
 	}
 
 	constructor(props) {
 		super('RoomFilesView', props);
+		this.rooms = database.objects('subscriptions').filtered('rid = $0', props.rid);
 		this.state = {
-			loading: true,
-			loadingMore: false
+			loading: false,
+			room: this.rooms[0],
+			messages: []
 		};
 	}
 
 	componentDidMount() {
-		this.limit = 20;
 		this.load();
 	}
 
-	componentWillReceiveProps(nextProps) {
-		const { ready } = this.props;
-		if (nextProps.ready && nextProps.ready !== ready) {
-			this.setState({ loading: false, loadingMore: false });
-		}
-	}
-
-	componentWillUnmount() {
-		const { closeRoomFiles } = this.props;
-		closeRoomFiles();
+	shouldComponentUpdate(nextProps, nextState) {
+		return !equal(this.state, nextState);
 	}
 
-	load = () => {
-		const { openRoomFiles, rid } = this.props;
-		openRoomFiles(rid, this.limit);
-	}
-
-	moreData = () => {
-		const { loadingMore } = this.state;
-		const { messages } = this.props;
-		if (messages.length < this.limit) {
+	load = async() => {
+		const {
+			messages, total, loading, room
+		} = this.state;
+		if (messages.length === total || loading) {
 			return;
 		}
-		if (!loadingMore) {
-			this.setState({ loadingMore: true });
-			this.limit += 20;
-			this.load();
+
+		this.setState({ loading: true });
+
+		try {
+			const result = await RocketChat.getFiles(room.rid, room.t, messages.length);
+			if (result.success) {
+				this.setState(prevState => ({
+					messages: [...prevState.messages, ...result.files],
+					total: result.total,
+					loading: false
+				}));
+			}
+		} catch (error) {
+			this.setState({ loading: false });
+			console.log('RoomFilesView -> catch -> error', error);
 		}
 	}
 
@@ -98,26 +95,49 @@ export default class RoomFilesView extends LoggedView {
 	)
 
 	renderItem = ({ item }) => {
-		const { user } = this.props;
+		const { user, baseUrl, customEmojis } = this.props;
+
+		let url = {};
+		if (/image/.test(item.type)) {
+			url = { image_url: item.url };
+		} else if (/audio/.test(item.type)) {
+			url = { audio_url: item.url };
+		} else if (/video/.test(item.type)) {
+			url = { video_url: item.url };
+		} else {
+			url = {
+				title_link: item.url,
+				type: 'file'
+			};
+		}
 
 		return (
 			<Message
-				item={item}
 				style={styles.message}
-				reactions={item.reactions}
+				customEmojis={customEmojis}
+				baseUrl={baseUrl}
 				user={user}
-				customTimeFormat='MMMM Do YYYY, h:mm:ss a'
+				author={item.user}
+				ts={item.uploadedAt}
+				attachments={[{
+					title: item.name,
+					description: item.description,
+					...url
+				}]}
+				timeFormat='MMM Do YYYY, h:mm:ss a'
+				edited={!!item.editedAt}
+				header
 			/>
 		);
 	}
 
 	render() {
-		const { messages, ready } = this.props;
-		if (ready && messages.length === 0) {
+		const { messages, loading } = this.state;
+
+		if (!loading && messages.length === 0) {
 			return this.renderEmpty();
 		}
 
-		const { loading, loadingMore } = this.state;
 		return (
 			<SafeAreaView style={styles.list} testID='room-files-view' forceInset={{ bottom: 'never' }}>
 				<FlatList
@@ -125,9 +145,8 @@ export default class RoomFilesView extends LoggedView {
 					renderItem={this.renderItem}
 					style={styles.list}
 					keyExtractor={item => item._id}
-					onEndReached={this.moreData}
-					ListHeaderComponent={loading ? <RCActivityIndicator /> : null}
-					ListFooterComponent={loadingMore ? <RCActivityIndicator /> : null}
+					onEndReached={this.load}
+					ListFooterComponent={loading ? <RCActivityIndicator /> : null}
 				/>
 			</SafeAreaView>
 		);
diff --git a/app/views/RoomInfoEditView/index.js b/app/views/RoomInfoEditView/index.js
index 8c1c9daca..afc4a8b8a 100644
--- a/app/views/RoomInfoEditView/index.js
+++ b/app/views/RoomInfoEditView/index.js
@@ -39,7 +39,7 @@ const PERMISSIONS_ARRAY = [
 ];
 
 @connect(null, dispatch => ({
-	eraseRoom: rid => dispatch(eraseRoomAction(rid))
+	eraseRoom: (rid, t) => dispatch(eraseRoomAction(rid, t))
 }))
 /** @extends React.Component */
 export default class RoomInfoEditView extends LoggedView {
@@ -231,7 +231,7 @@ export default class RoomInfoEditView extends LoggedView {
 				{
 					text: I18n.t('Yes_action_it', { action: I18n.t('delete') }),
 					style: 'destructive',
-					onPress: () => eraseRoom(room.rid)
+					onPress: () => eraseRoom(room.rid, room.t)
 				}
 			],
 			{ cancelable: false }
@@ -240,7 +240,7 @@ export default class RoomInfoEditView extends LoggedView {
 
 	toggleArchive = () => {
 		const { room } = this.state;
-		const { rid, archived } = room;
+		const { rid, archived, t } = room;
 
 		const action = I18n.t(`${ archived ? 'un' : '' }archive`);
 		Alert.alert(
@@ -254,9 +254,9 @@ export default class RoomInfoEditView extends LoggedView {
 				{
 					text: I18n.t('Yes_action_it', { action }),
 					style: 'destructive',
-					onPress: () => {
+					onPress: async() => {
 						try {
-							RocketChat.toggleArchiveRoom(rid, !archived);
+							await RocketChat.toggleArchiveRoom(rid, t, !archived);
 						} catch (e) {
 							log('toggleArchive', e);
 						}
diff --git a/app/views/RoomMembersView/index.js b/app/views/RoomMembersView/index.js
index 744be6541..ad7b0e87c 100644
--- a/app/views/RoomMembersView/index.js
+++ b/app/views/RoomMembersView/index.js
@@ -81,8 +81,8 @@ export default class RoomMembersView extends LoggedView {
 		this.rooms.removeAllListeners();
 	}
 
-	navigationButtonPressed = async({ buttonId }) => {
-		const { rid, allUsers } = this.state;
+	navigationButtonPressed = ({ buttonId }) => {
+		const { allUsers } = this.state;
 		const { componentId } = this.props;
 
 		if (buttonId === 'toggleOnline') {
@@ -97,10 +97,7 @@ export default class RoomMembersView extends LoggedView {
 						}]
 					}
 				});
-				const allUsersFilter = !allUsers;
-				const membersResult = await RocketChat.getRoomMembers(rid, allUsersFilter);
-				const members = membersResult.records;
-				this.setState({ allUsers: allUsersFilter, members });
+				this.fetchMembers(!allUsers);
 			} catch (e) {
 				log('RoomMembers.onNavigationButtonPressed', e);
 			}
diff --git a/app/views/RoomView/index.js b/app/views/RoomView/index.js
index 748a6d4db..fd0ecc4c9 100644
--- a/app/views/RoomView/index.js
+++ b/app/views/RoomView/index.js
@@ -133,6 +133,12 @@ export default class RoomView extends LoggedView {
 			return true;
 		} else if (room.f !== nextState.room.f) {
 			return true;
+		} else if (room.blocked !== nextState.room.blocked) {
+			return true;
+		} else if (room.blocker !== nextState.room.blocker) {
+			return true;
+		} else if (room.archived !== nextState.room.archived) {
+			return true;
 		} else if (loaded !== nextState.loaded) {
 			return true;
 		} else if (joined !== nextState.joined) {
@@ -156,17 +162,21 @@ export default class RoomView extends LoggedView {
 		const { componentId, appState } = this.props;
 
 		if (prevState.room.f !== room.f) {
+			const rightButtons = [{
+				id: 'star',
+				testID: 'room-view-header-star',
+				icon: room.f ? iconsMap.star : iconsMap.starOutline
+			}];
+			if (room.t !== 'l') {
+				rightButtons.unshift({
+					id: 'more',
+					testID: 'room-view-header-actions',
+					icon: iconsMap.more
+				});
+			}
 			Navigation.mergeOptions(componentId, {
 				topBar: {
-					rightButtons: [{
-						id: 'more',
-						testID: 'room-view-header-actions',
-						icon: iconsMap.more
-					}, {
-						id: 'star',
-						testID: 'room-view-header-star',
-						icon: room.f ? iconsMap.star : iconsMap.starOutline
-					}]
+					rightButtons
 				}
 			});
 		} else if (appState === 'foreground' && appState !== prevProps.appState) {
@@ -375,14 +385,14 @@ export default class RoomView extends LoggedView {
 		}
 		if (room.archived || this.isReadOnly()) {
 			return (
-				<View style={styles.readOnly}>
+				<View style={styles.readOnly} key='room-view-read-only'>
 					<Text>{I18n.t('This_room_is_read_only')}</Text>
 				</View>
 			);
 		}
 		if (this.isBlocked()) {
 			return (
-				<View style={styles.blockedOrBlocker}>
+				<View style={styles.readOnly} key='room-view-block'>
 					<Text>{I18n.t('This_room_is_blocked')}</Text>
 				</View>
 			);
diff --git a/app/views/RoomView/styles.js b/app/views/RoomView/styles.js
index 6deca0888..e0eb7535d 100644
--- a/app/views/RoomView/styles.js
+++ b/app/views/RoomView/styles.js
@@ -32,10 +32,9 @@ export default StyleSheet.create({
 		color: '#ccc'
 	},
 	readOnly: {
-		padding: 10
-	},
-	blockedOrBlocker: {
-		padding: 10
+		justifyContent: 'flex-end',
+		alignItems: 'center',
+		marginVertical: 15
 	},
 	reactionPickerContainer: {
 		// width: width - 20,
diff --git a/app/views/SearchMessagesView/index.js b/app/views/SearchMessagesView/index.js
index ddb4cca00..74510939b 100644
--- a/app/views/SearchMessagesView/index.js
+++ b/app/views/SearchMessagesView/index.js
@@ -1,6 +1,6 @@
 import React from 'react';
 import PropTypes from 'prop-types';
-import { View, FlatList } from 'react-native';
+import { View, FlatList, Text } from 'react-native';
 import { connect } from 'react-redux';
 import SafeAreaView from 'react-native-safe-area-view';
 
@@ -11,20 +11,20 @@ import styles from './styles';
 import Markdown from '../../containers/message/Markdown';
 import debounce from '../../utils/debounce';
 import RocketChat from '../../lib/rocketchat';
-import buildMessage from '../../lib/methods/helpers/buildMessage';
-import Message from '../../containers/message';
+import Message from '../../containers/message/Message';
 import scrollPersistTaps from '../../utils/scrollPersistTaps';
-import log from '../../utils/log';
 import I18n from '../../i18n';
 import { DEFAULT_HEADER } from '../../constants/headerOptions';
+import database from '../../lib/realm';
 
 @connect(state => ({
+	baseUrl: state.settings.Site_Url || state.server ? state.server.server : '',
+	customEmojis: state.customEmojis,
 	user: {
 		id: state.login.user && state.login.user.id,
 		username: state.login.user && state.login.user.username,
 		token: state.login.user && state.login.user.token
-	},
-	baseUrl: state.settings.Site_Url || state.server ? state.server.server : ''
+	}
 }))
 /** @extends React.Component */
 export default class SearchMessagesView extends LoggedView {
@@ -43,18 +43,19 @@ export default class SearchMessagesView extends LoggedView {
 
 	static propTypes = {
 		rid: PropTypes.string,
-		componentId: PropTypes.string,
 		user: PropTypes.object,
-		baseUrl: PropTypes.string
+		baseUrl: PropTypes.string,
+		customEmojis: PropTypes.object
 	}
 
 	constructor(props) {
 		super('SearchMessagesView', props);
-		this.limit = 0;
+		this.rooms = database.objects('subscriptions').filtered('rid = $0', props.rid);
 		this.state = {
+			loading: false,
+			room: this.rooms[0],
 			messages: [],
-			searching: false,
-			loadingMore: false
+			searchText: ''
 		};
 	}
 
@@ -63,100 +64,88 @@ export default class SearchMessagesView extends LoggedView {
 	}
 
 	componentWillUnmount() {
-		this.onChangeSearch.stop();
+		this.search.stop();
 	}
 
-	onChangeSearch = debounce((search) => {
-		const { searching } = this.state;
-
-		this.searchText = search;
-		this.limit = 0;
-		if (!searching) {
-			this.setState({ searching: true });
-		}
-		this.search();
-	}, 1000)
-
-	search = async() => {
-		const { rid } = this.props;
+	// eslint-disable-next-line react/sort-comp
+	search = debounce(async(searchText) => {
+		const { room } = this.state;
+		this.setState({ searchText, loading: true, messages: [] });
 
-		if (this._cancel) {
-			this._cancel('cancel');
-		}
-		const cancel = new Promise((r, reject) => this._cancel = reject);
-		let messages = [];
 		try {
-			const result = await Promise.race([RocketChat.messageSearch(this.searchText, rid, this.limit), cancel]);
-			messages = result.message.docs.map(message => buildMessage(message));
-			this.setState({ messages, searching: false, loadingMore: false });
-		} catch (e) {
-			this._cancel = null;
-			if (e !== 'cancel') {
-				return this.setState({ searching: false, loadingMore: false });
+			const result = await RocketChat.searchMessages(room.rid, searchText);
+			if (result.success) {
+				this.setState({
+					messages: result.messages || [],
+					loading: false
+				});
 			}
-			log('SearchMessagesView.search', e);
+		} catch (error) {
+			this.setState({ loading: false });
+			console.log('SearchMessagesView -> search -> catch -> error', error);
 		}
-	}
+	}, 1000)
 
-	moreData = () => {
-		const { loadingMore, messages } = this.state;
-		if (messages.length < this.limit) {
-			return;
-		}
-		if (this.searchText && !loadingMore) {
-			this.setState({ loadingMore: true });
-			this.limit += 20;
-			this.search();
-		}
-	}
+	renderEmpty = () => (
+		<View style={styles.listEmptyContainer}>
+			<Text>{I18n.t('No_results_found')}</Text>
+		</View>
+	)
 
 	renderItem = ({ item }) => {
-		const { user } = this.props;
+		const { user, customEmojis, baseUrl } = this.props;
 		return (
 			<Message
-				item={item}
 				style={styles.message}
-				reactions={item.reactions}
+				customEmojis={customEmojis}
+				baseUrl={baseUrl}
 				user={user}
-				customTimeFormat='MMMM Do YYYY, h:mm:ss a'
-				onReactionPress={async(emoji) => {
-					try {
-						await RocketChat.setReaction(emoji, item._id);
-						this.search();
-						this.forceUpdate();
-					} catch (e) {
-						log('SearchMessagesView.onReactionPress', e);
-					}
-				}}
+				author={item.u}
+				ts={item.ts}
+				msg={item.msg}
+				attachments={item.attachments || []}
+				timeFormat='MMM Do YYYY, h:mm:ss a'
+				edited={!!item.editedAt}
+				header
+			/>
+		);
+	}
+
+	renderList = () => {
+		const { messages, loading, searchText } = this.state;
+
+		if (!loading && messages.length === 0 && searchText.length) {
+			return this.renderEmpty();
+		}
+
+		return (
+			<FlatList
+				data={messages}
+				renderItem={this.renderItem}
+				style={styles.list}
+				keyExtractor={item => item._id}
+				onEndReached={this.load}
+				ListFooterComponent={loading ? <RCActivityIndicator /> : null}
+				{...scrollPersistTaps}
 			/>
 		);
 	}
 
 	render() {
-		const { searching, loadingMore, messages } = this.state;
 		return (
 			<SafeAreaView style={styles.container} testID='search-messages-view' forceInset={{ bottom: 'never' }}>
 				<View style={styles.searchContainer}>
 					<RCTextInput
 						inputRef={(e) => { this.name = e; }}
 						label={I18n.t('Search')}
-						onChangeText={this.onChangeSearch}
+						onChangeText={this.search}
 						placeholder={I18n.t('Search_Messages')}
 						testID='search-message-view-input'
 					/>
 					<Markdown msg={I18n.t('You_can_search_using_RegExp_eg')} username='' baseUrl='' customEmojis={{}} />
 					<View style={styles.divider} />
 				</View>
-				<FlatList
-					data={messages}
-					renderItem={this.renderItem}
-					style={styles.list}
-					keyExtractor={item => item._id}
-					onEndReached={this.moreData}
-					ListHeaderComponent={searching ? <RCActivityIndicator /> : null}
-					ListFooterComponent={loadingMore ? <RCActivityIndicator /> : null}
-					{...scrollPersistTaps}
-				/>
+				{this.renderList()}
 			</SafeAreaView>
 		);
 	}
diff --git a/app/views/SearchMessagesView/styles.js b/app/views/SearchMessagesView/styles.js
index 12ef0daa6..09e8163ba 100644
--- a/app/views/SearchMessagesView/styles.js
+++ b/app/views/SearchMessagesView/styles.js
@@ -17,9 +17,9 @@ export default StyleSheet.create({
 		transform: [{ scaleY: 1 }]
 	},
 	divider: {
+		width: '100%',
 		height: StyleSheet.hairlineWidth,
-		borderColor: '#ddd',
-		borderBottomWidth: StyleSheet.hairlineWidth,
+		backgroundColor: '#E7EBF2',
 		marginVertical: 20
 	}
 });
diff --git a/app/views/SnippetedMessagesView/index.js b/app/views/SnippetedMessagesView/index.js
index decf4330d..556139cc1 100644
--- a/app/views/SnippetedMessagesView/index.js
+++ b/app/views/SnippetedMessagesView/index.js
@@ -105,7 +105,7 @@ export default class SnippetedMessagesView extends LoggedView {
 				style={styles.message}
 				reactions={item.reactions}
 				user={user}
-				customTimeFormat='MMMM Do YYYY, h:mm:ss a'
+				customTimeFormat='MMM Do YYYY, h:mm:ss a'
 			/>
 		);
 	}
diff --git a/app/views/StarredMessagesView/index.js b/app/views/StarredMessagesView/index.js
index c25b20c81..a51fd84f4 100644
--- a/app/views/StarredMessagesView/index.js
+++ b/app/views/StarredMessagesView/index.js
@@ -4,32 +4,29 @@ import { FlatList, View, Text } from 'react-native';
 import { connect } from 'react-redux';
 import ActionSheet from 'react-native-actionsheet';
 import SafeAreaView from 'react-native-safe-area-view';
+import equal from 'deep-equal';
 
-import { openStarredMessages as openStarredMessagesAction, closeStarredMessages as closeStarredMessagesAction } from '../../actions/starredMessages';
-import { toggleStarRequest as toggleStarRequestAction } from '../../actions/messages';
 import LoggedView from '../View';
 import styles from './styles';
-import Message from '../../containers/message';
+import Message from '../../containers/message/Message';
 import RCActivityIndicator from '../../containers/ActivityIndicator';
 import I18n from '../../i18n';
 import { DEFAULT_HEADER } from '../../constants/headerOptions';
+import RocketChat from '../../lib/rocketchat';
+import database from '../../lib/realm';
 
 const STAR_INDEX = 0;
 const CANCEL_INDEX = 1;
 const options = [I18n.t('Unstar'), I18n.t('Cancel')];
 
 @connect(state => ({
-	messages: state.starredMessages.messages,
-	ready: state.starredMessages.ready,
+	baseUrl: state.settings.Site_Url || state.server ? state.server.server : '',
+	customEmojis: state.customEmojis,
 	user: {
 		id: state.login.user && state.login.user.id,
 		username: state.login.user && state.login.user.username,
 		token: state.login.user && state.login.user.token
 	}
-}), dispatch => ({
-	openStarredMessages: (rid, limit) => dispatch(openStarredMessagesAction(rid, limit)),
-	closeStarredMessages: () => dispatch(closeStarredMessagesAction()),
-	toggleStarRequest: message => dispatch(toggleStarRequestAction(message))
 }))
 /** @extends React.Component */
 export default class StarredMessagesView extends LoggedView {
@@ -48,38 +45,27 @@ export default class StarredMessagesView extends LoggedView {
 
 	static propTypes = {
 		rid: PropTypes.string,
-		messages: PropTypes.array,
-		ready: PropTypes.bool,
 		user: PropTypes.object,
-		openStarredMessages: PropTypes.func,
-		closeStarredMessages: PropTypes.func,
-		toggleStarRequest: PropTypes.func
+		baseUrl: PropTypes.string,
+		customEmojis: PropTypes.object
 	}
 
 	constructor(props) {
 		super('StarredMessagesView', props);
+		this.rooms = database.objects('subscriptions').filtered('rid = $0', props.rid);
 		this.state = {
-			message: {},
-			loading: true,
-			loadingMore: false
+			loading: false,
+			room: this.rooms[0],
+			messages: []
 		};
 	}
 
 	componentDidMount() {
-		this.limit = 20;
 		this.load();
 	}
 
-	componentWillReceiveProps(nextProps) {
-		const { ready } = this.props;
-		if (nextProps.ready && nextProps.ready !== ready) {
-			this.setState({ loading: false, loadingMore: false });
-		}
-	}
-
-	componentWillUnmount() {
-		const { closeStarredMessages } = this.props;
-		closeStarredMessages();
+	shouldComponentUpdate(nextProps, nextState) {
+		return !equal(this.state, nextState);
 	}
 
 	onLongPress = (message) => {
@@ -90,33 +76,57 @@ export default class StarredMessagesView extends LoggedView {
 	}
 
 	handleActionPress = (actionIndex) => {
-		const { message } = this.state;
-		const { toggleStarRequest } = this.props;
-
 		switch (actionIndex) {
 			case STAR_INDEX:
-				toggleStarRequest(message);
+				this.unStar();
 				break;
 			default:
 				break;
 		}
 	}
 
-	load = () => {
-		const { rid, openStarredMessages } = this.props;
-		openStarredMessages(rid, this.limit);
+	unStar = async() => {
+		const { message } = this.state;
+		try {
+			const result = await RocketChat.toggleStarMessage(message);
+			if (result.success) {
+				this.setState(prevState => ({
+					messages: prevState.messages.filter(item => item._id !== message._id)
+				}));
+			}
+		} catch (error) {
+			console.log('StarredMessagesView -> unStar -> catch -> error', error);
+		}
 	}
 
-	moreData = () => {
-		const { loadingMore } = this.state;
-		const { messages } = this.props;
-		if (messages.length < this.limit) {
+	load = async() => {
+		const {
+			messages, total, loading, room
+		} = this.state;
+		const { user } = this.props;
+		if (messages.length === total || loading) {
 			return;
 		}
-		if (!loadingMore) {
-			this.setState({ loadingMore: true });
-			this.limit += 20;
-			this.load();
+
+		this.setState({ loading: true });
+
+		try {
+			const result = await RocketChat.getMessages(
+				room.rid,
+				room.t,
+				{ 'starred._id': { $in: [user.id] } },
+				messages.length
+			);
+			if (result.success) {
+				this.setState(prevState => ({
+					messages: [...prevState.messages, ...result.messages],
+					total: result.total,
+					loading: false
+				}));
+			}
+		} catch (error) {
+			this.setState({ loading: false });
+			console.log('StarredMessagesView -> load -> catch -> error', error);
 		}
 	}
 
@@ -127,24 +137,29 @@ export default class StarredMessagesView extends LoggedView {
 	)
 
 	renderItem = ({ item }) => {
-		const { user } = this.props;
+		const { user, customEmojis, baseUrl } = this.props;
 		return (
 			<Message
-				item={item}
 				style={styles.message}
-				reactions={item.reactions}
+				customEmojis={customEmojis}
+				baseUrl={baseUrl}
 				user={user}
-				customTimeFormat='MMMM Do YYYY, h:mm:ss a'
-				onLongPress={this.onLongPress}
+				author={item.u}
+				ts={item.ts}
+				msg={item.msg}
+				attachments={item.attachments || []}
+				timeFormat='MMM Do YYYY, h:mm:ss a'
+				edited={!!item.editedAt}
+				header
+				onLongPress={() => this.onLongPress(item)}
 			/>
 		);
 	}
 
 	render() {
-		const { loading, loadingMore } = this.state;
-		const { messages, ready } = this.props;
+		const { messages, loading } = this.state;
 
-		if (ready && messages.length === 0) {
+		if (!loading && messages.length === 0) {
 			return this.renderEmpty();
 		}
 
@@ -155,9 +170,8 @@ export default class StarredMessagesView extends LoggedView {
 					renderItem={this.renderItem}
 					style={styles.list}
 					keyExtractor={item => item._id}
-					onEndReached={this.moreData}
-					ListHeaderComponent={loading ? <RCActivityIndicator /> : null}
-					ListFooterComponent={loadingMore ? <RCActivityIndicator /> : null}
+					onEndReached={this.load}
+					ListFooterComponent={loading ? <RCActivityIndicator /> : null}
 				/>
 				<ActionSheet
 					ref={o => this.actionSheet = o}
-- 
GitLab