From e66dbd8ca3cd24e58c59efebe231fac711e5da35 Mon Sep 17 00:00:00 2001
From: Diego Mello <diegolmello@gmail.com>
Date: Tue, 27 Nov 2018 17:40:53 -0200
Subject: [PATCH] [FIX] Android stuck on splash screen after hardware back
 button is pressed (#550)

* [FIX] Android stuck on splash screen after hardware button is pressed

* Fix empty user at asyncstorage

* Remove unused subscribe
---
 app/lib/rocketchat.js             |  1 -
 app/sagas/login.js                |  6 ++----
 app/views/OnboardingView/index.js | 17 ++++++++++++++---
 app/views/ProfileView/index.js    | 19 +++++++++++++++++--
 app/views/RoomsListView/index.js  | 24 ++++++++++++++++++------
 app/views/SettingsView/index.js   | 22 +++++++++++++++++++---
 package-lock.json                 |  3 ++-
 7 files changed, 72 insertions(+), 20 deletions(-)

diff --git a/app/lib/rocketchat.js b/app/lib/rocketchat.js
index a03230199..ea98fe248 100644
--- a/app/lib/rocketchat.js
+++ b/app/lib/rocketchat.js
@@ -192,7 +192,6 @@ const RocketChat = {
 
 			SDK.driver.on('connected', () => {
 				reduxStore.dispatch(connectSuccess());
-				SDK.driver.subscribe('meteor.loginServiceConfiguration');
 				SDK.driver.subscribe('activeUsers');
 				SDK.driver.subscribe('roles');
 				RocketChat.getSettings();
diff --git a/app/sagas/login.js b/app/sagas/login.js
index b5981cf3b..480482643 100644
--- a/app/sagas/login.js
+++ b/app/sagas/login.js
@@ -105,14 +105,12 @@ const handleForgotPasswordRequest = function* handleForgotPasswordRequest({ emai
 const handleSetUser = function* handleSetUser() {
 	yield delay(2000);
 	const [server, user] = yield all([select(getServer), select(getUser)]);
-	if (user) {
-		// TODO: temporary... remove in future releases
-		// delete user.user;
+	if (user && user.id) {
 		if (user.language) {
 			I18n.locale = user.language;
 		}
+		yield AsyncStorage.setItem(`${ RocketChat.TOKEN_KEY }-${ server }`, JSON.stringify(user));
 	}
-	yield AsyncStorage.setItem(`${ RocketChat.TOKEN_KEY }-${ server }`, JSON.stringify(user));
 };
 
 const root = function* root() {
diff --git a/app/views/OnboardingView/index.js b/app/views/OnboardingView/index.js
index e74938b89..63eab53d4 100644
--- a/app/views/OnboardingView/index.js
+++ b/app/views/OnboardingView/index.js
@@ -1,6 +1,6 @@
 import React from 'react';
 import {
-	View, Text, Image, TouchableOpacity
+	View, Text, Image, TouchableOpacity, BackHandler
 } from 'react-native';
 import PropTypes from 'prop-types';
 import Icon from 'react-native-vector-icons/MaterialIcons';
@@ -10,6 +10,7 @@ import SafeAreaView from 'react-native-safe-area-view';
 import { gestureHandlerRootHOC } from 'react-native-gesture-handler';
 
 import { selectServerRequest, serverInitAdd, serverFinishAdd } from '../../actions/server';
+import { appStart as appStartAction } from '../../actions';
 import I18n from '../../i18n';
 import openLink from '../../utils/openLink';
 import Button from './Button';
@@ -28,7 +29,8 @@ let NewServerView = null;
 }), dispatch => ({
 	initAdd: () => dispatch(serverInitAdd()),
 	finishAdd: () => dispatch(serverFinishAdd()),
-	selectServer: server => dispatch(selectServerRequest(server))
+	selectServer: server => dispatch(selectServerRequest(server)),
+	appStart: () => dispatch(appStartAction())
 }))
 /** @extends React.Component */
 export default class OnboardingView extends LoggedView {
@@ -49,11 +51,13 @@ export default class OnboardingView extends LoggedView {
 		selectServer: PropTypes.func.isRequired,
 		currentServer: PropTypes.string,
 		initAdd: PropTypes.func,
-		finishAdd: PropTypes.func
+		finishAdd: PropTypes.func,
+		appStart: PropTypes.func
 	}
 
 	constructor(props) {
 		super('OnboardingView', props);
+		BackHandler.addEventListener('hardwareBackPress', this.handleBackPress);
 	}
 
 	componentDidMount() {
@@ -75,6 +79,13 @@ export default class OnboardingView extends LoggedView {
 			finishAdd();
 		}
 		EventEmitter.removeListener('NewServer', this.handleNewServerEvent);
+		BackHandler.removeEventListener('hardwareBackPress', this.handleBackPress);
+	}
+
+	handleBackPress = () => {
+		const { appStart } = this.props;
+		appStart('background');
+		return false;
 	}
 
 	close = () => {
diff --git a/app/views/ProfileView/index.js b/app/views/ProfileView/index.js
index e3ee4edd1..c688327d0 100644
--- a/app/views/ProfileView/index.js
+++ b/app/views/ProfileView/index.js
@@ -1,7 +1,7 @@
 import React from 'react';
 import PropTypes from 'prop-types';
 import {
-	View, ScrollView, Keyboard, Dimensions
+	View, ScrollView, Keyboard, Dimensions, BackHandler
 } from 'react-native';
 import { connect } from 'react-redux';
 import Dialog from 'react-native-dialog';
@@ -28,6 +28,7 @@ import Avatar from '../../containers/Avatar';
 import Touch from '../../utils/touch';
 import Drawer from '../../Drawer';
 import { DEFAULT_HEADER } from '../../constants/headerOptions';
+import { appStart as appStartAction } from '../../actions';
 
 @connect(state => ({
 	user: {
@@ -38,6 +39,8 @@ import { DEFAULT_HEADER } from '../../constants/headerOptions';
 	},
 	Accounts_CustomFields: state.settings.Accounts_CustomFields,
 	baseUrl: state.settings.Site_Url || state.server ? state.server.server : ''
+}), dispatch => ({
+	appStart: () => dispatch(appStartAction())
 }))
 /** @extends React.Component */
 export default class ProfileView extends LoggedView {
@@ -71,7 +74,8 @@ export default class ProfileView extends LoggedView {
 		baseUrl: PropTypes.string,
 		componentId: PropTypes.string,
 		user: PropTypes.object,
-		Accounts_CustomFields: PropTypes.string
+		Accounts_CustomFields: PropTypes.string,
+		appStart: PropTypes.func
 	}
 
 	constructor(props) {
@@ -90,6 +94,7 @@ export default class ProfileView extends LoggedView {
 			customFields: {}
 		};
 		Navigation.events().bindComponent(this);
+		BackHandler.addEventListener('hardwareBackPress', this.handleBackPress);
 	}
 
 	async componentDidMount() {
@@ -110,12 +115,22 @@ export default class ProfileView extends LoggedView {
 		}
 	}
 
+	componentWillUnmount() {
+		BackHandler.removeEventListener('hardwareBackPress', this.handleBackPress);
+	}
+
 	navigationButtonPressed = ({ buttonId }) => {
 		if (buttonId === 'settings') {
 			Drawer.toggle();
 		}
 	}
 
+	handleBackPress = () => {
+		const { appStart } = this.props;
+		appStart('background');
+		return false;
+	}
+
 	setAvatar = (avatar) => {
 		this.setState({ avatar });
 	}
diff --git a/app/views/RoomsListView/index.js b/app/views/RoomsListView/index.js
index 9a5e44e85..ee77977c4 100644
--- a/app/views/RoomsListView/index.js
+++ b/app/views/RoomsListView/index.js
@@ -22,6 +22,7 @@ import SortDropdown from './SortDropdown';
 import ServerDropdown from './ServerDropdown';
 import Touch from '../../utils/touch';
 import { toggleSortDropdown as toggleSortDropdownAction, openSearchHeader as openSearchHeaderAction, closeSearchHeader as closeSearchHeaderAction } from '../../actions/rooms';
+import { appStart as appStartAction } from '../../actions';
 import store from '../../lib/createStore';
 import Drawer from '../../Drawer';
 import { DEFAULT_HEADER } from '../../constants/headerOptions';
@@ -69,7 +70,8 @@ let NewMessageView = null;
 }), dispatch => ({
 	toggleSortDropdown: () => dispatch(toggleSortDropdownAction()),
 	openSearchHeader: () => dispatch(openSearchHeaderAction()),
-	closeSearchHeader: () => dispatch(closeSearchHeaderAction())
+	closeSearchHeader: () => dispatch(closeSearchHeaderAction()),
+	appStart: () => dispatch(appStartAction())
 }))
 /** @extends React.Component */
 export default class RoomsListView extends LoggedView {
@@ -114,7 +116,8 @@ export default class RoomsListView extends LoggedView {
 		useRealName: PropTypes.bool,
 		toggleSortDropdown: PropTypes.func,
 		openSearchHeader: PropTypes.func,
-		closeSearchHeader: PropTypes.func
+		closeSearchHeader: PropTypes.func,
+		appStart: PropTypes.func
 	}
 
 	constructor(props) {
@@ -122,6 +125,7 @@ export default class RoomsListView extends LoggedView {
 
 		this.data = [];
 		this.state = {
+			searching: false,
 			search: [],
 			loading: true,
 			chats: [],
@@ -133,6 +137,7 @@ export default class RoomsListView extends LoggedView {
 			livechat: []
 		};
 		Navigation.events().bindComponent(this);
+		BackHandler.addEventListener('hardwareBackPress', this.handleBackPress);
 	}
 
 	componentDidMount() {
@@ -180,6 +185,7 @@ export default class RoomsListView extends LoggedView {
 		this.removeListener(this.privateGroup);
 		this.removeListener(this.direct);
 		this.removeListener(this.livechat);
+		BackHandler.removeEventListener('hardwareBackPress', this.handleBackPress);
 
 		if (this.timeout) {
 			clearTimeout(this.timeout);
@@ -336,6 +342,7 @@ export default class RoomsListView extends LoggedView {
 
 	initSearchingAndroid = () => {
 		const { openSearchHeader } = this.props;
+		this.setState({ searching: true });
 		openSearchHeader();
 		Navigation.mergeOptions('RoomsListView', {
 			topBar: {
@@ -347,12 +354,12 @@ export default class RoomsListView extends LoggedView {
 				rightButtons: []
 			}
 		});
-		BackHandler.addEventListener('hardwareBackPress', this.handleBackPress);
 	}
 
 	cancelSearchingAndroid = () => {
 		if (Platform.OS === 'android') {
 			const { closeSearchHeader } = this.props;
+			this.setState({ searching: false });
 			closeSearchHeader();
 			Navigation.mergeOptions('RoomsListView', {
 				topBar: {
@@ -362,7 +369,6 @@ export default class RoomsListView extends LoggedView {
 			});
 			this.internalSetState({ search: [] });
 			Keyboard.dismiss();
-			BackHandler.removeEventListener('hardwareBackPress', this.handleBackPress);
 		}
 	}
 
@@ -370,8 +376,14 @@ export default class RoomsListView extends LoggedView {
 	hasActiveDB = () => database && database.databases && database.databases.activeDB;
 
 	handleBackPress = () => {
-		this.cancelSearchingAndroid();
-		return true;
+		const { searching } = this.state;
+		const { appStart } = this.props;
+		if (searching) {
+			this.cancelSearchingAndroid();
+			return true;
+		}
+		appStart('background');
+		return false;
 	}
 
 	_isUnread = item => item.unread > 0 || item.alert
diff --git a/app/views/SettingsView/index.js b/app/views/SettingsView/index.js
index d6698e31b..10a29fb4b 100644
--- a/app/views/SettingsView/index.js
+++ b/app/views/SettingsView/index.js
@@ -1,6 +1,8 @@
 import React from 'react';
 import PropTypes from 'prop-types';
-import { View, ScrollView, Dimensions } from 'react-native';
+import {
+	View, ScrollView, Dimensions, BackHandler
+} from 'react-native';
 import RNPickerSelect from 'react-native-picker-select';
 import { connect } from 'react-redux';
 import { Navigation } from 'react-native-navigation';
@@ -18,13 +20,15 @@ import Loading from '../../containers/Loading';
 import { showErrorAlert, showToast } from '../../utils/info';
 import log from '../../utils/log';
 import { setUser as setUserAction } from '../../actions/login';
+import { appStart as appStartAction } from '../../actions';
 import Drawer from '../../Drawer';
 import { DEFAULT_HEADER } from '../../constants/headerOptions';
 
 @connect(state => ({
 	userLanguage: state.login.user && state.login.user.language
 }), dispatch => ({
-	setUser: params => dispatch(setUserAction(params))
+	setUser: params => dispatch(setUserAction(params)),
+	appStart: () => dispatch(appStartAction())
 }))
 /** @extends React.Component */
 export default class SettingsView extends LoggedView {
@@ -57,7 +61,8 @@ export default class SettingsView extends LoggedView {
 	static propTypes = {
 		componentId: PropTypes.string,
 		userLanguage: PropTypes.string,
-		setUser: PropTypes.func
+		setUser: PropTypes.func,
+		appStart: PropTypes.func
 	}
 
 	constructor(props) {
@@ -81,6 +86,11 @@ export default class SettingsView extends LoggedView {
 			saving: false
 		};
 		Navigation.events().bindComponent(this);
+		BackHandler.addEventListener('hardwareBackPress', this.handleBackPress);
+	}
+
+	componentWillUnmount() {
+		BackHandler.removeEventListener('hardwareBackPress', this.handleBackPress);
 	}
 
 	navigationButtonPressed = ({ buttonId }) => {
@@ -89,6 +99,12 @@ export default class SettingsView extends LoggedView {
 		}
 	}
 
+	handleBackPress = () => {
+		const { appStart } = this.props;
+		appStart('background');
+		return false;
+	}
+
 	getLabel = (language) => {
 		const { languages } = this.state;
 		const l = languages.find(i => i.value === language);
diff --git a/package-lock.json b/package-lock.json
index 0164c19d4..3c27dc22d 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -18454,7 +18454,8 @@
     },
     "react-native-scrollable-tab-view": {
       "version": "0.10.0",
-      "resolved": "git+https://github.com/skv-headless/react-native-scrollable-tab-view.git#2419c25a03f0fb346af8ce2c39fca869f259e716",
+      "resolved": "https://registry.npmjs.org/react-native-scrollable-tab-view/-/react-native-scrollable-tab-view-0.10.0.tgz",
+      "integrity": "sha512-7FWw9X2hLozWqpGJTAU/p7ONdTTO635bbAZ5AUPDrB4JwaLbhNV6ePjsNUjsCaopgCwz/EdmH0hTCPeja9dh4w==",
       "requires": {
         "create-react-class": "^15.6.2",
         "prop-types": "^15.6.0",
-- 
GitLab