From 28628b4dba5fcfc024d5902dea62be9d232bc62b Mon Sep 17 00:00:00 2001
From: Diego Mello <diegolmello@gmail.com>
Date: Wed, 15 May 2019 16:33:30 -0300
Subject: [PATCH] Switch toast lib (#898)

* removed toast from ios

* changed showToast to showAlert

* removed from android

* fix lint

* conflict resolved

* fixed lint

* Fix toast position

* Change toast style

* Use followMessage from rest

* Temporary disable some visual toast tests

* Unnecessary lib version change
---
 android/app/build.gradle                      |  1 -
 .../rocket/reactnative/MainApplication.java   |  2 -
 android/settings.gradle                       |  2 -
 app/constants/colors.js                       |  1 +
 app/containers/MessageActions.js              | 11 ++--
 app/lib/rocketchat.js                         |  4 +-
 app/utils/info.js                             | 32 ++++++++++--
 app/views/ProfileView/index.js                |  7 +--
 app/views/RoomInfoEditView/index.js           |  5 +-
 app/views/RoomMembersView/index.js            |  5 +-
 app/views/RoomView/Header/RightButtons.js     | 23 ++++-----
 app/views/RoomView/index.js                   | 28 +++++++++-
 app/views/SettingsView/index.js               |  5 +-
 e2e/08-room.spec.js                           |  6 ++-
 e2e/09-roomactions.spec.js                    | 12 ++---
 e2e/10-roominfo.spec.js                       | 36 ++++++-------
 e2e/13-profile.spec.js                        | 12 ++---
 ios/RocketChatRN.xcodeproj/project.pbxproj    | 51 -------------------
 package.json                                  |  2 +-
 yarn.lock                                     | 12 +++--
 20 files changed, 128 insertions(+), 129 deletions(-)

diff --git a/android/app/build.gradle b/android/app/build.gradle
index 7aec3e8d7..820495363 100644
--- a/android/app/build.gradle
+++ b/android/app/build.gradle
@@ -214,7 +214,6 @@ dependencies {
     implementation project(':react-native-video')
     implementation project(':react-native-vector-icons')
     implementation project(':rn-fetch-blob')
-    implementation project(':react-native-toast')
     implementation project(':react-native-fast-image')
     implementation project(':realm')
     implementation project(':reactnativenotifications')
diff --git a/android/app/src/main/java/chat/rocket/reactnative/MainApplication.java b/android/app/src/main/java/chat/rocket/reactnative/MainApplication.java
index 8f47d95e5..61ff18c2d 100644
--- a/android/app/src/main/java/chat/rocket/reactnative/MainApplication.java
+++ b/android/app/src/main/java/chat/rocket/reactnative/MainApplication.java
@@ -17,7 +17,6 @@ import com.brentvatne.react.ReactVideoPackage;
 import com.crashlytics.android.Crashlytics;
 import com.dylanvann.fastimage.FastImageViewPackage;
 import com.oblador.vectoricons.VectorIconsPackage;
-import com.remobile.toast.RCTToastPackage;
 import com.rnim.rn.audio.ReactNativeAudioPackage;
 import com.smixx.fabric.FabricPackage;
 import com.wix.reactnativekeyboardinput.KeyboardInputPackage;
@@ -63,7 +62,6 @@ public class MainApplication extends Application implements ReactApplication, IN
 					new RNFetchBlobPackage(),
 					new RealmReactPackage(),
 					new ReactVideoPackage(),
-					new RCTToastPackage(),
 					new ReactNativeAudioPackage(),
 					new KeyboardInputPackage(MainApplication.this),
 					new RocketChatNativePackage(),
diff --git a/android/settings.gradle b/android/settings.gradle
index 5cd7ee60c..d21bc637b 100644
--- a/android/settings.gradle
+++ b/android/settings.gradle
@@ -11,8 +11,6 @@ include ':react-native-device-info'
 project(':react-native-device-info').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-device-info/android')
 include ':react-native-gesture-handler'
 project(':react-native-gesture-handler').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-gesture-handler/android')
-include ':react-native-toast'
-project(':react-native-toast').projectDir = new File(rootProject.projectDir, '../node_modules/@remobile/react-native-toast/android')
 include ':rn-fetch-blob'
 project(':rn-fetch-blob').projectDir = new File(rootProject.projectDir, '../node_modules/rn-fetch-blob/android')
 include ':react-native-image-crop-picker'
diff --git a/app/constants/colors.js b/app/constants/colors.js
index 78dfda526..57d5a0f92 100644
--- a/app/constants/colors.js
+++ b/app/constants/colors.js
@@ -12,6 +12,7 @@ export const COLOR_SEPARATOR = '#A7A7AA';
 export const COLOR_BACKGROUND_CONTAINER = '#f3f4f5';
 export const COLOR_BORDER = '#e1e5e8';
 export const COLOR_UNREAD = '#e1e5e8';
+export const COLOR_TOAST = '#0C0D0F';
 export const STATUS_COLORS = {
 	online: '#2de0a5',
 	busy: COLOR_DANGER,
diff --git a/app/containers/MessageActions.js b/app/containers/MessageActions.js
index e2d347afd..2f5d79236 100644
--- a/app/containers/MessageActions.js
+++ b/app/containers/MessageActions.js
@@ -4,7 +4,6 @@ import { Alert, Clipboard, Share } from 'react-native';
 import { connect } from 'react-redux';
 import ActionSheet from 'react-native-action-sheet';
 import * as moment from 'moment';
-
 import {
 	actionsHide as actionsHideAction,
 	deleteRequest as deleteRequestAction,
@@ -14,7 +13,6 @@ import {
 	toggleReactionPicker as toggleReactionPickerAction,
 	toggleStarRequest as toggleStarRequestAction
 } from '../actions/messages';
-import { showToast } from '../utils/info';
 import { vibrate } from '../utils/vibration';
 import RocketChat from '../lib/rocketchat';
 import I18n from '../i18n';
@@ -44,6 +42,7 @@ export default class MessageActions extends React.Component {
 		actionsHide: PropTypes.func.isRequired,
 		room: PropTypes.object.isRequired,
 		actionMessage: PropTypes.object,
+		toast: PropTypes.element,
 		// user: PropTypes.object.isRequired,
 		deleteRequest: PropTypes.func.isRequired,
 		editInit: PropTypes.func.isRequired,
@@ -253,9 +252,9 @@ export default class MessageActions extends React.Component {
 	}
 
 	handleCopy = async() => {
-		const { actionMessage } = this.props;
+		const { actionMessage, toast } = this.props;
 		await Clipboard.setString(actionMessage.msg);
-		showToast(I18n.t('Copied_to_clipboard'));
+		toast.show(I18n.t('Copied_to_clipboard'));
 	}
 
 	handleShare = async() => {
@@ -272,10 +271,10 @@ export default class MessageActions extends React.Component {
 	}
 
 	handlePermalink = async() => {
-		const { actionMessage } = this.props;
+		const { actionMessage, toast } = this.props;
 		const permalink = await this.getPermalink(actionMessage);
 		Clipboard.setString(permalink);
-		showToast(I18n.t('Permalink_copied_to_clipboard'));
+		toast.show(I18n.t('Permalink_copied_to_clipboard'));
 	}
 
 	handlePin = () => {
diff --git a/app/lib/rocketchat.js b/app/lib/rocketchat.js
index a7990d1c4..99893500c 100644
--- a/app/lib/rocketchat.js
+++ b/app/lib/rocketchat.js
@@ -769,9 +769,9 @@ const RocketChat = {
 	toggleFollowMessage(mid, follow) {
 		// RC 1.0
 		if (follow) {
-			return this.sdk.methodCall('followMessage', { mid });
+			return this.sdk.post('chat.followMessage', { mid });
 		}
-		return this.sdk.methodCall('unfollowMessage', { mid });
+		return this.sdk.post('chat.unfollowMessage', { mid });
 	},
 	getThreadsList({ rid, count, offset }) {
 		// RC 1.0
diff --git a/app/utils/info.js b/app/utils/info.js
index e380ba8d8..90f774532 100644
--- a/app/utils/info.js
+++ b/app/utils/info.js
@@ -1,6 +1,32 @@
-import { Alert } from 'react-native';
-import Toast from '@remobile/react-native-toast';
+import React from 'react';
+import { Alert, StyleSheet } from 'react-native';
+import EasyToast from 'react-native-easy-toast';
 
-export const showToast = (message: string) => Toast.showLongCenter(message, Toast.SHORT);
+import { COLOR_TOAST, COLOR_WHITE } from '../constants/colors';
+import { isNotch } from './deviceInfo';
+import sharedStyles from '../views/Styles';
 
+const styles = StyleSheet.create({
+	toast: {
+		backgroundColor: COLOR_TOAST
+	},
+	text: {
+		...sharedStyles.textRegular,
+		color: COLOR_WHITE,
+		fontSize: 14
+	}
+});
+
+const positionValue = isNotch ? 230 : 200;
+
+export const Toast = React.forwardRef((props, ref) => (
+	<EasyToast
+		{...props}
+		ref={ref}
+		positionValue={positionValue}
+		style={styles.toast}
+		textStyle={styles.text}
+		opacity={0.8}
+	/>
+));
 export const showErrorAlert = (message: string, title: string) => Alert.alert(title, message, [{ text: 'OK', onPress: () => {} }], { cancelable: true });
diff --git a/app/views/ProfileView/index.js b/app/views/ProfileView/index.js
index c7b98c87b..ef7dce971 100644
--- a/app/views/ProfileView/index.js
+++ b/app/views/ProfileView/index.js
@@ -14,7 +14,7 @@ import KeyboardView from '../../presentation/KeyboardView';
 import sharedStyles from '../Styles';
 import styles from './styles';
 import scrollPersistTaps from '../../utils/scrollPersistTaps';
-import { showErrorAlert, showToast } from '../../utils/info';
+import { showErrorAlert, Toast } from '../../utils/info';
 import RocketChat from '../../lib/rocketchat';
 import RCTextInput from '../../containers/TextInput';
 import log from '../../utils/log';
@@ -223,7 +223,7 @@ export default class ProfileView extends LoggedView {
 					setUser({ customFields });
 				}
 				this.setState({ saving: false });
-				showToast(I18n.t('Profile_saved_successfully'));
+				this.toast.show(I18n.t('Profile_saved_successfully'));
 				this.init();
 			}
 		} catch (e) {
@@ -236,7 +236,7 @@ export default class ProfileView extends LoggedView {
 		try {
 			const { user } = this.props;
 			await RocketChat.resetAvatar(user.id);
-			showToast(I18n.t('Avatar_changed_successfully'));
+			this.toast.show(I18n.t('Avatar_changed_successfully'));
 			this.init();
 		} catch (e) {
 			this.handleError(e, 'resetAvatar', 'changing_avatar');
@@ -387,6 +387,7 @@ export default class ProfileView extends LoggedView {
 				keyboardVerticalOffset={128}
 			>
 				<StatusBar />
+				<Toast ref={toast => this.toast = toast} />
 				<ScrollView
 					contentContainerStyle={sharedStyles.containerScrollView}
 					testID='profile-view-list'
diff --git a/app/views/RoomInfoEditView/index.js b/app/views/RoomInfoEditView/index.js
index 7447d4fa2..81bd84283 100644
--- a/app/views/RoomInfoEditView/index.js
+++ b/app/views/RoomInfoEditView/index.js
@@ -13,7 +13,7 @@ import KeyboardView from '../../presentation/KeyboardView';
 import sharedStyles from '../Styles';
 import styles from './styles';
 import scrollPersistTaps from '../../utils/scrollPersistTaps';
-import { showErrorAlert, showToast } from '../../utils/info';
+import { showErrorAlert, Toast } from '../../utils/info';
 import database, { safeAddListener } from '../../lib/realm';
 import RocketChat from '../../lib/rocketchat';
 import RCTextInput from '../../containers/TextInput';
@@ -217,7 +217,7 @@ export default class RoomInfoEditView extends LoggedView {
 			if (error) {
 				showErrorAlert(I18n.t('There_was_an_error_while_action', { action: I18n.t('saving_settings') }));
 			} else {
-				showToast(I18n.t('Settings_succesfully_changed'));
+				this.toast.show(I18n.t('Settings_succesfully_changed'));
 			}
 		}, 100);
 	}
@@ -430,6 +430,7 @@ export default class RoomInfoEditView extends LoggedView {
 							<Text style={[sharedStyles.button_inverted, styles.colorDanger]} accessibilityTraits='button'>{I18n.t('DELETE')}</Text>
 						</TouchableOpacity>
 						<Loading visible={saving} />
+						<Toast ref={toast => this.toast = toast} />
 					</SafeAreaView>
 				</ScrollView>
 			</KeyboardView>
diff --git a/app/views/RoomMembersView/index.js b/app/views/RoomMembersView/index.js
index cf26f641b..9301f43a1 100644
--- a/app/views/RoomMembersView/index.js
+++ b/app/views/RoomMembersView/index.js
@@ -12,7 +12,7 @@ import UserItem from '../../presentation/UserItem';
 import scrollPersistTaps from '../../utils/scrollPersistTaps';
 import RocketChat from '../../lib/rocketchat';
 import database, { safeAddListener } from '../../lib/realm';
-import { showToast } from '../../utils/info';
+import { Toast } from '../../utils/info';
 import log from '../../utils/log';
 import { vibrate } from '../../utils/vibration';
 import I18n from '../../i18n';
@@ -234,7 +234,7 @@ export default class RoomMembersView extends LoggedView {
 		const { rid, userLongPressed } = this.state;
 		try {
 			await RocketChat.toggleMuteUserInRoom(rid, userLongPressed.username, !userLongPressed.muted);
-			showToast(I18n.t('User_has_been_key', { key: userLongPressed.muted ? I18n.t('unmuted') : I18n.t('muted') }));
+			this.toast.show(I18n.t('User_has_been_key', { key: userLongPressed.muted ? I18n.t('unmuted') : I18n.t('muted') }));
 		} catch (e) {
 			log('handleMute', e);
 		}
@@ -301,6 +301,7 @@ export default class RoomMembersView extends LoggedView {
 					windowSize={10}
 					{...scrollPersistTaps}
 				/>
+				<Toast ref={toast => this.toast = toast} />
 			</SafeAreaView>
 		);
 	}
diff --git a/app/views/RoomView/Header/RightButtons.js b/app/views/RoomView/Header/RightButtons.js
index db19f9683..54ec54f7e 100644
--- a/app/views/RoomView/Header/RightButtons.js
+++ b/app/views/RoomView/Header/RightButtons.js
@@ -5,9 +5,6 @@ import { connect } from 'react-redux';
 
 import { CustomHeaderButtons, Item } from '../../../containers/HeaderButton';
 import database, { safeAddListener } from '../../../lib/realm';
-import RocketChat from '../../../lib/rocketchat';
-import log from '../../../utils/log';
-import { showToast } from '../../../utils/info';
 
 const styles = StyleSheet.create({
 	more: {
@@ -33,7 +30,8 @@ class RightButtonsContainer extends React.PureComponent {
 		rid: PropTypes.string,
 		t: PropTypes.string,
 		tmid: PropTypes.string,
-		navigation: PropTypes.object
+		navigation: PropTypes.object,
+		toggleFollowThread: PropTypes.func
 	};
 
 	constructor(props) {
@@ -41,13 +39,16 @@ class RightButtonsContainer extends React.PureComponent {
 		if (props.tmid) {
 			// FIXME: it may be empty if the thread header isn't fetched yet
 			this.thread = database.objectForPrimaryKey('messages', props.tmid);
-			safeAddListener(this.thread, this.updateThread);
 		}
 		this.state = {
 			isFollowingThread: true
 		};
 	}
 
+	componentDidMount() {
+		safeAddListener(this.thread, this.updateThread);
+	}
+
 	componentWillUnmount() {
 		if (this.thread && this.thread.removeAllListeners) {
 			this.thread.removeAllListeners();
@@ -71,15 +72,11 @@ class RightButtonsContainer extends React.PureComponent {
 		navigation.navigate('RoomActionsView', { rid, t });
 	}
 
-	toggleFollowThread = async() => {
+	toggleFollowThread = () => {
 		const { isFollowingThread } = this.state;
-		const { tmid } = this.props;
-		try {
-			await RocketChat.toggleFollowMessage(tmid, !isFollowingThread);
-			showToast(isFollowingThread ? 'Unfollowed thread' : 'Following thread');
-		} catch (e) {
-			console.log('TCL: RightButtonsContainer -> toggleFollowThread -> e', e);
-			log('toggleFollowThread', e);
+		const { toggleFollowThread } = this.props;
+		if (toggleFollowThread) {
+			toggleFollowThread(isFollowingThread);
 		}
 	}
 
diff --git a/app/views/RoomView/index.js b/app/views/RoomView/index.js
index 80bc5bb86..1cf18488b 100644
--- a/app/views/RoomView/index.js
+++ b/app/views/RoomView/index.js
@@ -37,6 +37,7 @@ import Separator from './Separator';
 import { COLOR_WHITE } from '../../constants/colors';
 import debounce from '../../utils/debounce';
 import buildMessage from '../../lib/methods/helpers/buildMessage';
+import { Toast } from '../../utils/info';
 
 @connect(state => ({
 	user: {
@@ -66,6 +67,7 @@ export default class RoomView extends LoggedView {
 		const title = navigation.getParam('name');
 		const t = navigation.getParam('t');
 		const tmid = navigation.getParam('tmid');
+		const toggleFollowThread = navigation.getParam('toggleFollowThread', () => {});
 		return {
 			headerTitleContainerStyle: styles.headerTitleContainerStyle,
 			headerTitle: (
@@ -78,7 +80,15 @@ export default class RoomView extends LoggedView {
 					widthOffset={tmid ? 95 : 130}
 				/>
 			),
-			headerRight: <RightButtons rid={rid} tmid={tmid} t={t} navigation={navigation} />
+			headerRight: (
+				<RightButtons
+					rid={rid}
+					tmid={tmid}
+					t={t}
+					navigation={navigation}
+					toggleFollowThread={toggleFollowThread}
+				/>
+			)
 		};
 	}
 
@@ -133,6 +143,9 @@ export default class RoomView extends LoggedView {
 			if (room._id && !this.tmid) {
 				navigation.setParams({ name: this.getRoomTitle(room), t: room.t });
 			}
+			if (this.tmid) {
+				navigation.setParams({ toggleFollowThread: this.toggleFollowThread });
+			}
 
 			if (isAuthenticated) {
 				this.init();
@@ -408,6 +421,16 @@ export default class RoomView extends LoggedView {
 		}
 	}
 
+	toggleFollowThread = async(isFollowingThread) => {
+		try {
+			await RocketChat.toggleFollowMessage(this.tmid, !isFollowingThread);
+			this.toast.show(isFollowingThread ? 'Unfollowed thread' : 'Following thread');
+		} catch (e) {
+			console.log('TCL: RightButtonsContainer -> toggleFollowThread -> e', e);
+			log('toggleFollowThread', e);
+		}
+	}
+
 	renderItem = (item, previousItem) => {
 		const { room, lastOpen } = this.state;
 		const { user, navigation } = this.props;
@@ -515,7 +538,7 @@ export default class RoomView extends LoggedView {
 		return (
 			<React.Fragment>
 				{room._id && showActions
-					? <MessageActions room={room} tmid={this.tmid} user={user} />
+					? <MessageActions room={room} tmid={this.tmid} user={user} toast={this.toast} />
 					: null
 				}
 				{showErrorActions ? <MessageErrorActions /> : null}
@@ -536,6 +559,7 @@ export default class RoomView extends LoggedView {
 				{this.renderActions()}
 				<ReactionPicker onEmojiSelected={this.onReactionPress} />
 				<UploadProgress rid={this.rid} />
+				<Toast ref={toast => this.toast = toast} />
 			</SafeAreaView>
 		);
 	}
diff --git a/app/views/SettingsView/index.js b/app/views/SettingsView/index.js
index 75c853f11..50a073668 100644
--- a/app/views/SettingsView/index.js
+++ b/app/views/SettingsView/index.js
@@ -14,7 +14,7 @@ import scrollPersistTaps from '../../utils/scrollPersistTaps';
 import I18n from '../../i18n';
 import Button from '../../containers/Button';
 import Loading from '../../containers/Loading';
-import { showErrorAlert, showToast } from '../../utils/info';
+import { showErrorAlert, Toast } from '../../utils/info';
 import log from '../../utils/log';
 import { setUser as setUserAction } from '../../actions/login';
 import { DrawerButton } from '../../containers/HeaderButton';
@@ -122,7 +122,7 @@ export default class SettingsView extends LoggedView {
 
 			this.setState({ saving: false });
 			setTimeout(() => {
-				showToast(I18n.t('Preferences_saved'));
+				this.toast.show(I18n.t('Preferences_saved'));
 			}, 300);
 		} catch (e) {
 			this.setState({ saving: false });
@@ -175,6 +175,7 @@ export default class SettingsView extends LoggedView {
 							/>
 						</View>
 						<Loading visible={saving} />
+						<Toast ref={toast => this.toast = toast} />
 					</SafeAreaView>
 				</ScrollView>
 			</KeyboardView>
diff --git a/e2e/08-room.spec.js b/e2e/08-room.spec.js
index d383f6fc6..17865003d 100644
--- a/e2e/08-room.spec.js
+++ b/e2e/08-room.spec.js
@@ -170,7 +170,8 @@ describe('Room screen', () => {
 				await waitFor(element(by.text('Message actions'))).toBeVisible().withTimeout(5000);
 				await expect(element(by.text('Message actions'))).toBeVisible();
 				await element(by.text('Permalink')).tap();
-				await expect(element(by.text('Permalink copied to clipboard!'))).toBeVisible();
+				// await expect(element(by.text('Permalink copied to clipboard!'))).toBeVisible();
+				await waitFor(element(by.text('Permalink copied to clipboard!'))).toBeVisible().withTimeout(5000);
 				await waitFor(element(by.text('Permalink copied to clipboard!'))).toBeNotVisible().withTimeout(5000);
 				
 				// TODO: test clipboard
@@ -181,7 +182,8 @@ describe('Room screen', () => {
 				await waitFor(element(by.text('Message actions'))).toBeVisible().withTimeout(5000);
 				await expect(element(by.text('Message actions'))).toBeVisible();
 				await element(by.text('Copy')).tap();
-				await expect(element(by.text('Copied to clipboard!'))).toBeVisible();
+				// await expect(element(by.text('Copied to clipboard!'))).toBeVisible();
+				await waitFor(element(by.text('Copied to clipboard!'))).toBeVisible().withTimeout(5000);
 				await waitFor(element(by.text('Copied to clipboard!'))).toBeNotVisible().withTimeout(5000);
 				// TODO: test clipboard
 			});
diff --git a/e2e/09-roomactions.spec.js b/e2e/09-roomactions.spec.js
index 0a13e63b6..956407798 100644
--- a/e2e/09-roomactions.spec.js
+++ b/e2e/09-roomactions.spec.js
@@ -337,17 +337,17 @@ describe('Room actions screen', () => {
 					await waitFor(element(by.text('Mute'))).toBeVisible().withTimeout(5000);
 					await expect(element(by.text('Mute'))).toBeVisible();
 					await element(by.text('Mute')).tap();
-					await waitFor(element(by.text('User has been muted!'))).toBeVisible().withTimeout(60000);
-					await expect(element(by.text('User has been muted!'))).toBeVisible();
-					await waitFor(element(by.text('User has been muted!'))).toBeNotVisible().withTimeout(60000);
+					await waitFor(element(by.text('User has been muted!'))).toBeVisible().withTimeout(10000);
+					// await expect(element(by.text('User has been muted!'))).toBeVisible();
+					await waitFor(element(by.text('User has been muted!'))).toBeNotVisible().withTimeout(10000);
 					await expect(element(by.text('User has been muted!'))).toBeNotVisible();
 					await element(by.id(`room-members-view-item-${ data.alternateUser }`)).longPress();
 					await waitFor(element(by.text('Unmute'))).toBeVisible().withTimeout(2000);
 					await expect(element(by.text('Unmute'))).toBeVisible();
 					await element(by.text('Unmute')).tap();
-					await waitFor(element(by.text('User has been unmuted!'))).toBeVisible().withTimeout(60000);
-					await expect(element(by.text('User has been unmuted!'))).toBeVisible();
-					await waitFor(element(by.text('User has been unmuted!'))).toBeNotVisible().withTimeout(5000);
+					await waitFor(element(by.text('User has been unmuted!'))).toBeVisible().withTimeout(10000);
+					// await expect(element(by.text('User has been unmuted!'))).toBeVisible();
+					await waitFor(element(by.text('User has been unmuted!'))).toBeNotVisible().withTimeout(10000);
 					await expect(element(by.text('User has been unmuted!'))).toBeNotVisible();
 				});
 
diff --git a/e2e/10-roominfo.spec.js b/e2e/10-roominfo.spec.js
index 6e22bfa33..752c6c0bb 100644
--- a/e2e/10-roominfo.spec.js
+++ b/e2e/10-roominfo.spec.js
@@ -157,8 +157,8 @@ describe('Room info screen', () => {
 				await element(by.id('room-info-edit-view-name')).replaceText(`${ room }new`);
 				await element(by.id('room-info-edit-view-list')).swipe('up');
 				await element(by.id('room-info-edit-view-submit')).tap();
-				await waitFor(element(by.text('Settings succesfully changed!'))).toBeVisible().withTimeout(60000);
-				await expect(element(by.text('Settings succesfully changed!'))).toBeVisible();
+				await waitFor(element(by.text('Settings succesfully changed!'))).toBeVisible().withTimeout(10000);
+				// await expect(element(by.text('Settings succesfully changed!'))).toBeVisible();
 				await waitFor(element(by.text('Settings succesfully changed!'))).toBeNotVisible().withTimeout(10000);
 				await expect(element(by.text('Settings succesfully changed!'))).toBeNotVisible();
 				await tapBack();
@@ -171,8 +171,8 @@ describe('Room info screen', () => {
 				await element(by.id('room-info-edit-view-name')).replaceText(`${ room }`);
 				await element(by.id('room-info-edit-view-list')).swipe('up');
 				await element(by.id('room-info-edit-view-submit')).tap();
-				await waitFor(element(by.text('Settings succesfully changed!'))).toBeVisible().withTimeout(60000);
-				await expect(element(by.text('Settings succesfully changed!'))).toBeVisible();
+				await waitFor(element(by.text('Settings succesfully changed!'))).toBeVisible().withTimeout(10000);
+				// await expect(element(by.text('Settings succesfully changed!'))).toBeVisible();
 				await waitFor(element(by.text('Settings succesfully changed!'))).toBeNotVisible().withTimeout(10000);
 				await expect(element(by.text('Settings succesfully changed!'))).toBeNotVisible();
 				await element(by.id('room-info-edit-view-list')).swipe('down');
@@ -205,8 +205,8 @@ describe('Room info screen', () => {
 				await element(by.id('room-info-edit-view-description')).replaceText('new description');
 				await element(by.id('room-info-edit-view-list')).swipe('up');
 				await element(by.id('room-info-edit-view-submit')).tap();
-				await waitFor(element(by.text('Settings succesfully changed!'))).toBeVisible().withTimeout(60000);
-				await expect(element(by.text('Settings succesfully changed!'))).toBeVisible();
+				await waitFor(element(by.text('Settings succesfully changed!'))).toBeVisible().withTimeout(10000);
+				// await expect(element(by.text('Settings succesfully changed!'))).toBeVisible();
 				await waitFor(element(by.text('Settings succesfully changed!'))).toBeNotVisible().withTimeout(10000);
 				await expect(element(by.text('Settings succesfully changed!'))).toBeNotVisible();
 				await tapBack();
@@ -222,8 +222,8 @@ describe('Room info screen', () => {
 				await element(by.id('room-info-edit-view-topic')).replaceText('new topic');
 				await element(by.id('room-info-edit-view-list')).swipe('up');
 				await element(by.id('room-info-edit-view-submit')).tap();
-				await waitFor(element(by.text('Settings succesfully changed!'))).toBeVisible().withTimeout(60000);
-				await expect(element(by.text('Settings succesfully changed!'))).toBeVisible();
+				await waitFor(element(by.text('Settings succesfully changed!'))).toBeVisible().withTimeout(10000);
+				// await expect(element(by.text('Settings succesfully changed!'))).toBeVisible();
 				await waitFor(element(by.text('Settings succesfully changed!'))).toBeNotVisible().withTimeout(10000);
 				await expect(element(by.text('Settings succesfully changed!'))).toBeNotVisible();
 				await tapBack();
@@ -239,8 +239,8 @@ describe('Room info screen', () => {
 				await element(by.id('room-info-edit-view-announcement')).replaceText('new announcement');
 				await element(by.id('room-info-edit-view-list')).swipe('up');
 				await element(by.id('room-info-edit-view-submit')).tap();
-				await waitFor(element(by.text('Settings succesfully changed!'))).toBeVisible().withTimeout(60000);
-				await expect(element(by.text('Settings succesfully changed!'))).toBeVisible();
+				await waitFor(element(by.text('Settings succesfully changed!'))).toBeVisible().withTimeout(10000);
+				// await expect(element(by.text('Settings succesfully changed!'))).toBeVisible();
 				await waitFor(element(by.text('Settings succesfully changed!'))).toBeNotVisible().withTimeout(10000);
 				await expect(element(by.text('Settings succesfully changed!'))).toBeNotVisible();
 				await tapBack();
@@ -256,8 +256,8 @@ describe('Room info screen', () => {
 				await element(by.id('room-info-edit-view-list')).swipe('up');
 				await element(by.id('room-info-edit-view-password')).replaceText('password');
 				await element(by.id('room-info-edit-view-submit')).tap();
-				await waitFor(element(by.text('Settings succesfully changed!'))).toBeVisible().withTimeout(60000);
-				await expect(element(by.text('Settings succesfully changed!'))).toBeVisible();
+				await waitFor(element(by.text('Settings succesfully changed!'))).toBeVisible().withTimeout(10000);
+				// await expect(element(by.text('Settings succesfully changed!'))).toBeVisible();
 				await waitFor(element(by.text('Settings succesfully changed!'))).toBeNotVisible().withTimeout(10000);
 				await expect(element(by.text('Settings succesfully changed!'))).toBeNotVisible();
 			});
@@ -265,14 +265,14 @@ describe('Room info screen', () => {
 			it('should change room type', async() => {
 				await element(by.id('room-info-edit-view-t')).tap();
 				await element(by.id('room-info-edit-view-submit')).tap();
-				await waitFor(element(by.text('Settings succesfully changed!'))).toBeVisible().withTimeout(60000);
-				await expect(element(by.text('Settings succesfully changed!'))).toBeVisible();
+				await waitFor(element(by.text('Settings succesfully changed!'))).toBeVisible().withTimeout(10000);
+				// await expect(element(by.text('Settings succesfully changed!'))).toBeVisible();
 				await waitFor(element(by.text('Settings succesfully changed!'))).toBeNotVisible().withTimeout(10000);
 				await expect(element(by.text('Settings succesfully changed!'))).toBeNotVisible();
 				await element(by.id('room-info-edit-view-t')).tap();
 				await element(by.id('room-info-edit-view-submit')).tap();
-				await waitFor(element(by.text('Settings succesfully changed!'))).toBeVisible().withTimeout(60000);
-				await expect(element(by.text('Settings succesfully changed!'))).toBeVisible();
+				await waitFor(element(by.text('Settings succesfully changed!'))).toBeVisible().withTimeout(10000);
+				// await expect(element(by.text('Settings succesfully changed!'))).toBeVisible();
 				await waitFor(element(by.text('Settings succesfully changed!'))).toBeNotVisible().withTimeout(10000);
 				await expect(element(by.text('Settings succesfully changed!'))).toBeNotVisible();
 			});
@@ -283,8 +283,8 @@ describe('Room info screen', () => {
 				await expect(element(by.id('room-info-edit-view-react-when-ro'))).toBeVisible();
 				await element(by.id('room-info-edit-view-react-when-ro')).tap();
 				await element(by.id('room-info-edit-view-submit')).tap();
-				await waitFor(element(by.text('Settings succesfully changed!'))).toBeVisible().withTimeout(60000);
-				await expect(element(by.text('Settings succesfully changed!'))).toBeVisible();
+				await waitFor(element(by.text('Settings succesfully changed!'))).toBeVisible().withTimeout(10000);
+				// await expect(element(by.text('Settings succesfully changed!'))).toBeVisible();
 				await waitFor(element(by.text('Settings succesfully changed!'))).toBeNotVisible().withTimeout(10000);
 				await expect(element(by.text('Settings succesfully changed!'))).toBeNotVisible();
 				// TODO: test if it's possible to react
diff --git a/e2e/13-profile.spec.js b/e2e/13-profile.spec.js
index 3d8625461..ca4bc9169 100644
--- a/e2e/13-profile.spec.js
+++ b/e2e/13-profile.spec.js
@@ -79,8 +79,8 @@ describe('Profile screen', () => {
 			await element(by.id('profile-view-username')).replaceText(`${ data.user }new`);
 			await element(by.id('profile-view-list')).swipe('up');
 			await element(by.id('profile-view-submit')).tap();
-			await waitFor(element(by.text('Profile saved successfully!'))).toBeVisible().withTimeout(60000);
-			await expect(element(by.text('Profile saved successfully!'))).toBeVisible();
+			await waitFor(element(by.text('Profile saved successfully!'))).toBeVisible().withTimeout(10000);
+			// await expect(element(by.text('Profile saved successfully!'))).toBeVisible();
 			await waitFor(element(by.text('Profile saved successfully!'))).toBeNotVisible().withTimeout(10000);
 			await expect(element(by.text('Profile saved successfully!'))).toBeNotVisible();
 		});
@@ -93,8 +93,8 @@ describe('Profile screen', () => {
 			await expect(element(by.id('profile-view-typed-password'))).toBeVisible();
 			await element(by.id('profile-view-typed-password')).replaceText(`${ data.password }`);
 			await element(by.text('Save')).tap();
-			await waitFor(element(by.text('Profile saved successfully!'))).toBeVisible().withTimeout(60000);
-			await expect(element(by.text('Profile saved successfully!'))).toBeVisible();
+			await waitFor(element(by.text('Profile saved successfully!'))).toBeVisible().withTimeout(10000);
+			// await expect(element(by.text('Profile saved successfully!'))).toBeVisible();
 			await waitFor(element(by.text('Profile saved successfully!'))).toBeNotVisible().withTimeout(10000);
 			await expect(element(by.text('Profile saved successfully!'))).toBeNotVisible();
 		});
@@ -102,8 +102,8 @@ describe('Profile screen', () => {
 		it('should reset avatar', async() => {
 			await element(by.id('profile-view-list')).swipe('up');
 			await element(by.id('profile-view-reset-avatar')).tap();
-			await waitFor(element(by.text('Avatar changed successfully!'))).toBeVisible().withTimeout(60000);
-			await expect(element(by.text('Avatar changed successfully!'))).toBeVisible();
+			await waitFor(element(by.text('Avatar changed successfully!'))).toBeVisible().withTimeout(10000);
+			// await expect(element(by.text('Avatar changed successfully!'))).toBeVisible();
 			await waitFor(element(by.text('Avatar changed successfully!'))).toBeNotVisible().withTimeout(10000);
 			await expect(element(by.text('Avatar changed successfully!'))).toBeNotVisible();
 		});
diff --git a/ios/RocketChatRN.xcodeproj/project.pbxproj b/ios/RocketChatRN.xcodeproj/project.pbxproj
index 30f09980a..4967a0a5d 100644
--- a/ios/RocketChatRN.xcodeproj/project.pbxproj
+++ b/ios/RocketChatRN.xcodeproj/project.pbxproj
@@ -34,7 +34,6 @@
 		7A55F1C52236D541005109A0 /* custom.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 7A55F1C42236D541005109A0 /* custom.ttf */; };
 		7A8DEB5A20ED0BEC00C5DCE4 /* libRNNotifications.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7A8DEB5220ED0BDE00C5DCE4 /* libRNNotifications.a */; };
 		7ACD4897222860DE00442C55 /* JavaScriptCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7ACD4853222860DE00442C55 /* JavaScriptCore.framework */; };
-		7AFB806E205AE65700D004E7 /* libRCTToast.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7AFB804C205AE63100D004E7 /* libRCTToast.a */; };
 		832341BD1AAA6AB300B99B32 /* libRCTText.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 832341B51AAA6A8300B99B32 /* libRCTText.a */; };
 		8ECBD927DDAC4987B98E102E /* libRCTVideo.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 20CE3E407E0D4D9E8C9885F2 /* libRCTVideo.a */; };
 		95E57ADEB9A0487791D2C50E /* libRNGestureHandler.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 58E5009FCA8D40E59303C3DD /* libRNGestureHandler.a */; };
@@ -257,13 +256,6 @@
 			remoteGlobalIDString = 39DF4FE71E00394E00F5B4B2;
 			remoteInfo = RCTCustomInputController;
 		};
-		7A55F1B92236D50F005109A0 /* PBXContainerItemProxy */ = {
-			isa = PBXContainerItemProxy;
-			containerPortal = B1A58A7ACB0E4453A44AEC38 /* RNGestureHandler.xcodeproj */;
-			proxyType = 2;
-			remoteGlobalIDString = B5C32A36220C603B000FFB8D;
-			remoteInfo = "RNGestureHandler-tvOS";
-		};
 		7A770EC120BECDC7001AD51A /* PBXContainerItemProxy */ = {
 			isa = PBXContainerItemProxy;
 			containerPortal = 1845C223DA364898A8400573 /* FastImage.xcodeproj */;
@@ -362,13 +354,6 @@
 			remoteGlobalIDString = 134814201AA4EA6300B7C361;
 			remoteInfo = RNGestureHandler;
 		};
-		7AFB804B205AE63100D004E7 /* PBXContainerItemProxy */ = {
-			isa = PBXContainerItemProxy;
-			containerPortal = 7AFB8035205AE63000D004E7 /* RCTToast.xcodeproj */;
-			proxyType = 2;
-			remoteGlobalIDString = 327633421BFAAD7E004DA88E;
-			remoteInfo = RCTToast;
-		};
 		832341B41AAA6A8300B99B32 /* PBXContainerItemProxy */ = {
 			isa = PBXContainerItemProxy;
 			containerPortal = 832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */;
@@ -504,7 +489,6 @@
 		7A55F1C42236D541005109A0 /* custom.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = custom.ttf; sourceTree = "<group>"; };
 		7A8DEB1B20ED0BDE00C5DCE4 /* RNNotifications.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RNNotifications.xcodeproj; path = "../node_modules/react-native-notifications/RNNotifications/RNNotifications.xcodeproj"; sourceTree = "<group>"; };
 		7ACD4853222860DE00442C55 /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; };
-		7AFB8035205AE63000D004E7 /* RCTToast.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTToast.xcodeproj; path = "../node_modules/@remobile/react-native-toast/ios/RCTToast.xcodeproj"; sourceTree = "<group>"; };
 		832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTText.xcodeproj; path = "../node_modules/react-native/Libraries/Text/RCTText.xcodeproj"; sourceTree = "<group>"; };
 		921481B47B50490CA761932E /* libRNI18n.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libRNI18n.a; sourceTree = "<group>"; };
 		ACD75701AFD1CB848CAB0CB3 /* Pods-RocketChatRN.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RocketChatRN.debug.xcconfig"; path = "Pods/Target Support Files/Pods-RocketChatRN/Pods-RocketChatRN.debug.xcconfig"; sourceTree = "<group>"; };
@@ -530,7 +514,6 @@
 				7ACD4897222860DE00442C55 /* JavaScriptCore.framework in Frameworks */,
 				7A8DEB5A20ED0BEC00C5DCE4 /* libRNNotifications.a in Frameworks */,
 				7A2D202320726F1400D0AA04 /* libSMXCrashlytics.a in Frameworks */,
-				7AFB806E205AE65700D004E7 /* libRCTToast.a in Frameworks */,
 				B8971BB2202A093B0000D245 /* libKeyboardTrackingView.a in Frameworks */,
 				7A430E4F20238C46008F55BC /* libRCTCustomInputController.a in Frameworks */,
 				146834051AC3E58100842450 /* libReact.a in Frameworks */,
@@ -768,20 +751,11 @@
 			name = Products;
 			sourceTree = "<group>";
 		};
-		7AFB8036205AE63000D004E7 /* Products */ = {
-			isa = PBXGroup;
-			children = (
-				7AFB804C205AE63100D004E7 /* libRCTToast.a */,
-			);
-			name = Products;
-			sourceTree = "<group>";
-		};
 		832341AE1AAA6A7D00B99B32 /* Libraries */ = {
 			isa = PBXGroup;
 			children = (
 				7A8DEB1B20ED0BDE00C5DCE4 /* RNNotifications.xcodeproj */,
 				7A2D1FE620726EF600D0AA04 /* SMXCrashlytics.xcodeproj */,
-				7AFB8035205AE63000D004E7 /* RCTToast.xcodeproj */,
 				B8971BAC202A091D0000D245 /* KeyboardTrackingView.xcodeproj */,
 				7A430E1620238C01008F55BC /* RCTCustomInputController.xcodeproj */,
 				B88F58361FBF55E200B352B8 /* RCTPushNotification.xcodeproj */,
@@ -1029,10 +1003,6 @@
 					ProductGroup = 832341B11AAA6A8300B99B32 /* Products */;
 					ProjectRef = 832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */;
 				},
-				{
-					ProductGroup = 7AFB8036205AE63000D004E7 /* Products */;
-					ProjectRef = 7AFB8035205AE63000D004E7 /* RCTToast.xcodeproj */;
-				},
 				{
 					ProductGroup = 00C302E01ABCB9EE00DB3ED1 /* Products */;
 					ProjectRef = 00C302DF1ABCB9EE00DB3ED1 /* RCTVibration.xcodeproj */;
@@ -1304,13 +1274,6 @@
 			remoteRef = 7A430E1D20238C02008F55BC /* PBXContainerItemProxy */;
 			sourceTree = BUILT_PRODUCTS_DIR;
 		};
-		7A55F1BA2236D50F005109A0 /* libRNGestureHandler-tvOS.a */ = {
-			isa = PBXReferenceProxy;
-			fileType = archive.ar;
-			path = "libRNGestureHandler-tvOS.a";
-			remoteRef = 7A55F1B92236D50F005109A0 /* PBXContainerItemProxy */;
-			sourceTree = BUILT_PRODUCTS_DIR;
-		};
 		7A770EC220BECDC7001AD51A /* libFastImage.a */ = {
 			isa = PBXReferenceProxy;
 			fileType = archive.ar;
@@ -1374,13 +1337,6 @@
 			remoteRef = 7AA7B71B2229AE520039764A /* PBXContainerItemProxy */;
 			sourceTree = BUILT_PRODUCTS_DIR;
 		};
-		7A9B5BC9221F2D0900478E23 /* libRNVectorIcons-tvOS.a */ = {
-			isa = PBXReferenceProxy;
-			fileType = archive.ar;
-			path = "libRNVectorIcons-tvOS.a";
-			remoteRef = 7A9B5BC8221F2D0900478E23 /* PBXContainerItemProxy */;
-			sourceTree = BUILT_PRODUCTS_DIR;
-		};
 		7ACD4880222860DE00442C55 /* libjsi.a */ = {
 			isa = PBXReferenceProxy;
 			fileType = archive.ar;
@@ -1416,13 +1372,6 @@
 			remoteRef = 7AD44CF421518C610099D147 /* PBXContainerItemProxy */;
 			sourceTree = BUILT_PRODUCTS_DIR;
 		};
-		7AFB804C205AE63100D004E7 /* libRCTToast.a */ = {
-			isa = PBXReferenceProxy;
-			fileType = archive.ar;
-			path = libRCTToast.a;
-			remoteRef = 7AFB804B205AE63100D004E7 /* PBXContainerItemProxy */;
-			sourceTree = BUILT_PRODUCTS_DIR;
-		};
 		832341B51AAA6A8300B99B32 /* libRCTText.a */ = {
 			isa = PBXReferenceProxy;
 			fileType = archive.ar;
diff --git a/package.json b/package.json
index ab252fd32..631f9b984 100644
--- a/package.json
+++ b/package.json
@@ -19,7 +19,6 @@
     ]
   },
   "dependencies": {
-    "@remobile/react-native-toast": "^1.0.7",
     "@rocket.chat/sdk": "1.0.0-alpha.28",
     "deep-equal": "^1.0.1",
     "ejson": "^2.1.2",
@@ -38,6 +37,7 @@
     "react-native-console-time-polyfill": "^1.2.1",
     "react-native-device-info": "1.6.1",
     "react-native-dialog": "^5.6.0",
+    "react-native-easy-toast": "^1.2.0",
     "react-native-fabric": "github:corymsmith/react-native-fabric#523a4edab3b2bf55ea9eeea2cf0dde82c5c29dd4",
     "react-native-fast-image": "5.3.0",
     "react-native-gesture-handler": "^1.2.1",
diff --git a/yarn.lock b/yarn.lock
index 366da2be1..d3b2a4593 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1002,11 +1002,6 @@
     react-native-safe-area-view "^0.13.0"
     react-native-screens "^1.0.0 || ^1.0.0-alpha"
 
-"@remobile/react-native-toast@^1.0.7":
-  version "1.0.7"
-  resolved "https://registry.yarnpkg.com/@remobile/react-native-toast/-/react-native-toast-1.0.7.tgz#b2e3684cdb13e1c9d9b4ed08e667157d4ad0fab2"
-  integrity sha512-iOD1PRnTSVr9sDWQdesIpfRrwJhHfeEQe5BpalQxC5OhM9thpiE6cu2NlW1KBWl0RJG4ZiJaF1xLlCo9YxU6dA==
-
 "@rocket.chat/sdk@1.0.0-alpha.28":
   version "1.0.0-alpha.28"
   resolved "https://registry.yarnpkg.com/@rocket.chat/sdk/-/sdk-1.0.0-alpha.28.tgz#569f3c578c5c12ed54a9317d36fa8413208ce021"
@@ -10351,6 +10346,13 @@ react-native-dialog@^5.6.0:
     prop-types "^15.7.2"
     react-native-modal "^9.0.0"
 
+react-native-easy-toast@^1.2.0:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/react-native-easy-toast/-/react-native-easy-toast-1.2.0.tgz#0f70bcb99e3306cda4800c244bfb4a67d42276ed"
+  integrity sha512-UtpxnRn1ME+035Uey4VR+9K0P4aVoTcWNOx5QkioWBe3LBKMPb/kZjrQ1LtvWzOyeGP4TeTUTtMX3IOPWv5MtA==
+  dependencies:
+    prop-types "^15.5.10"
+
 "react-native-fabric@github:corymsmith/react-native-fabric#523a4edab3b2bf55ea9eeea2cf0dde82c5c29dd4":
   version "0.5.2"
   resolved "https://codeload.github.com/corymsmith/react-native-fabric/tar.gz/523a4edab3b2bf55ea9eeea2cf0dde82c5c29dd4"
-- 
GitLab