[FIX] Deep linking between multiple logged servers (#730)

This commit is contained in:
Diego Mello 2019-03-18 15:52:38 -03:00 committed by GitHub
parent b8eb75748b
commit 477311f84a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 86 additions and 84 deletions

View File

@ -6,6 +6,7 @@ import { Provider } from 'react-redux';
import { useScreens } from 'react-native-screens'; // eslint-disable-line import/no-unresolved
import { Linking } from 'react-native';
import { appInit } from './actions';
import { deepLinkingOpen } from './actions/deepLinking';
import OnboardingView from './views/OnboardingView';
import NewServerView from './views/NewServerView';
@ -39,30 +40,25 @@ import OAuthView from './views/OAuthView';
import SetUsernameView from './views/SetUsernameView';
import { HEADER_BACKGROUND, HEADER_TITLE, HEADER_BACK } from './constants/colors';
import parseQuery from './lib/methods/helpers/parseQuery';
import { initializePushNotifications } from './push';
import { initializePushNotifications, onNotification } from './push';
import store from './lib/createStore';
useScreens();
initializePushNotifications();
const handleOpenURL = ({ url }) => {
const parseDeepLinking = (url) => {
if (url) {
url = url.replace(/rocketchat:\/\/|https:\/\/go.rocket.chat\//, '');
const regex = /^(room|auth)\?/;
if (url.match(regex)) {
url = url.replace(regex, '');
const params = parseQuery(url);
store.dispatch(deepLinkingOpen(params));
url = url.replace(regex, '').trim();
if (url) {
return parseQuery(url);
}
}
}
return null;
};
Linking
.getInitialURL()
.then(url => handleOpenURL({ url }))
.catch(e => console.warn(e));
Linking.addEventListener('url', handleOpenURL);
const defaultHeader = {
headerStyle: {
backgroundColor: HEADER_BACKGROUND
@ -184,7 +180,41 @@ const App = createAppContainer(createSwitchNavigator(
}
));
export default () => (
export default class Root extends React.Component {
constructor(props) {
super(props);
this.init();
}
componentDidMount() {
this.listenerTimeout = setTimeout(() => {
Linking.addEventListener('url', ({ url }) => {
const parsedDeepLinkingURL = parseDeepLinking(url);
if (parsedDeepLinkingURL) {
store.dispatch(deepLinkingOpen(parsedDeepLinkingURL));
}
});
}, 5000);
}
componentWillUnmount() {
clearTimeout(this.listenerTimeout);
}
init = async() => {
const [notification, deepLinking] = await Promise.all([initializePushNotifications(), Linking.getInitialURL()]);
const parsedDeepLinkingURL = parseDeepLinking(deepLinking);
if (notification) {
onNotification(notification);
} else if (parsedDeepLinkingURL) {
store.dispatch(deepLinkingOpen(parsedDeepLinkingURL));
} else {
store.dispatch(appInit());
}
}
render() {
return (
<Provider store={store}>
<App
ref={(navigatorRef) => {
@ -192,4 +222,6 @@ export default () => (
}}
/>
</Provider>
);
);
}
}

View File

@ -4,7 +4,7 @@ import PushNotification from './push';
import store from '../lib/createStore';
import { deepLinkingOpen } from '../actions/deepLinking';
const onNotification = (notification) => {
export const onNotification = (notification) => {
if (notification) {
const data = notification.getData();
if (data) {
@ -31,13 +31,11 @@ const onNotification = (notification) => {
}
};
const getDeviceToken = () => PushNotification.getDeviceToken();
const setBadgeCount = count => PushNotification.setBadgeCount(count);
const initializePushNotifications = () => {
PushNotification.configure({
export const getDeviceToken = () => PushNotification.getDeviceToken();
export const setBadgeCount = count => PushNotification.setBadgeCount(count);
export const initializePushNotifications = () => {
setBadgeCount();
return PushNotification.configure({
onNotification
});
setBadgeCount();
};
export { initializePushNotifications, getDeviceToken, setBadgeCount };

View File

@ -25,12 +25,7 @@ class PushNotification {
this.onRegister = params.onRegister;
this.onNotification = params.onNotification;
NotificationsAndroid.refreshToken();
PendingNotifications.getInitialNotification()
.then((notification) => {
this.onNotification(notification);
})
.catch(e => console.warn(e));
return PendingNotifications.getInitialNotification();
}
}

View File

@ -30,6 +30,7 @@ class PushNotification {
this.onNotification = params.onNotification;
NotificationsIOS.consumeBackgroundQueue();
return Promise.resolve();
}
}
export default new PushNotification();

View File

@ -1,7 +1,7 @@
import { AsyncStorage } from 'react-native';
import { delay } from 'redux-saga';
import {
takeLatest, take, select, put, all, race
takeLatest, take, select, put, all
} from 'redux-saga/effects';
import Navigation from '../lib/Navigation';
@ -10,28 +10,25 @@ import { selectServerRequest } from '../actions/server';
import database from '../lib/realm';
import RocketChat from '../lib/rocketchat';
import EventEmitter from '../utils/events';
import { appStart } from '../actions';
const roomTypes = {
channel: 'c', direct: 'd', group: 'p'
};
const navigate = function* navigate({ params }) {
yield put(appStart('inside'));
if (params.rid) {
const canOpenRoom = yield RocketChat.canOpenRoom(params);
if (canOpenRoom) {
const [type, name] = params.path.split('/');
yield Navigation.navigate('RoomsListView');
Navigation.navigate('RoomView', { rid: params.rid, name, t: roomTypes[type] });
}
}
};
const handleOpen = function* handleOpen({ params }) {
const isReady = yield select(state => state.app.ready);
if (!isReady) {
yield take(types.APP.READY);
}
if (!params.host) {
return;
}
@ -54,29 +51,28 @@ const handleOpen = function* handleOpen({ params }) {
// if deep link is from same server
if (server === host) {
if (user) {
yield race({
typing: take(types.SERVER.SELECT_SUCCESS),
timeout: delay(3000)
});
yield navigate({ params });
const connected = yield select(state => state.server.connected);
if (!connected) {
yield put(selectServerRequest(host));
yield take(types.SERVER.SELECT_SUCCESS);
}
yield navigate({ params });
} else {
yield put(appStart('outside'));
}
} else {
// search if deep link's server already exists
const servers = yield database.databases.serversDB.objects('servers').filtered('id = $0', host); // TODO: need better test
if (servers.length && user) {
yield put(selectServerRequest(host));
yield take(types.SERVER.SELECT_SUCCESS);
yield navigate({ params });
} else {
// if deep link is from a different server
const result = yield RocketChat.testServer(server);
if (!result.success) {
return;
}
// search if deep link's server already exists
const servers = yield database.databases.serversDB.objects('servers').filtered('id = $0', host); // TODO: need better test
if (servers.length && user) {
yield put(selectServerRequest(host));
yield race({
typing: take(types.SERVER.SELECT_SUCCESS),
timeout: delay(3000)
});
yield navigate({ params });
} else {
Navigation.navigate('OnboardingView', { previousServer: server });
yield delay(1000);
EventEmitter.emit('NewServer', { server: host });

View File

@ -24,6 +24,7 @@ const handleSelectServer = function* handleSelectServer({ server }) {
yield put(actions.appStart('inside'));
} else {
RocketChat.connect({ server });
yield put(actions.appStart('outside'));
}
const settings = database.objects('settings');

View File

@ -1,11 +1,8 @@
import React from 'react';
import { StyleSheet, Image } from 'react-native';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
import StatusBar from '../containers/StatusBar';
import { isAndroid } from '../utils/deviceInfo';
import { appInit as appInitAction } from '../actions';
const styles = StyleSheet.create({
image: {
@ -14,25 +11,9 @@ const styles = StyleSheet.create({
}
});
@connect(null, dispatch => ({
appInit: () => dispatch(appInitAction())
}))
export default class Loading extends React.PureComponent {
static propTypes = {
appInit: PropTypes.func
}
constructor(props) {
super(props);
props.appInit();
}
render() {
return (
export default React.memo(() => (
<React.Fragment>
<StatusBar />
{isAndroid ? <Image source={{ uri: 'launch_screen' }} style={styles.image} /> : null}
</React.Fragment>
);
}
}
));

View File

@ -1606,7 +1606,6 @@
);
PRODUCT_BUNDLE_IDENTIFIER = chat.rocket.reactnative;
PRODUCT_NAME = RocketChatRN;
PROVISIONING_PROFILE = "573947ae-c3f2-425e-aa82-0181297becf9";
PROVISIONING_PROFILE_SPECIFIER = "match Development chat.rocket.reactnative";
VERSIONING_SYSTEM = "apple-generic";
};
@ -1653,8 +1652,7 @@
);
PRODUCT_BUNDLE_IDENTIFIER = chat.rocket.reactnative;
PRODUCT_NAME = RocketChatRN;
PROVISIONING_PROFILE = "c630cec9-82b4-44ed-a9c1-922232f9dd1f";
PROVISIONING_PROFILE_SPECIFIER = "match AppStore chat.rocket.reactnative";
PROVISIONING_PROFILE_SPECIFIER = "match AppStore chat.rocket.reactnative 1552925104";
VERSIONING_SYSTEM = "apple-generic";
};
name = Release;