mattermost-mobile/app/init/global_event_handler.js
Miguel Alatzar 1efb01deda
[MM-16593] Upgrade to RN 0.61.2 (#3455)
* [MM-16593] [MM-17175] [MM-17164] [MM-17189] [MM-17181] Android - Upgrade to RN 0.60 (#3145)

* Upgrade to react-native 0.60

* Use @sentry/react-native

* Manually link @sentry/react-native

* Address review comments

* Jetify after install

* Call jetify from node_modules

* [MM-17785] iOS - Upgrade to RN 0.60 (#3153)

* Upgrade to react-native 0.60

* Use @sentry/react-native

* Manually link @sentry/react-native

* Address review comments

* Jetify after install

* Call jetify from node_modules

* Get app building for iOS

* Revert react-native-image-picker upgrade

* Minor version upgrade of react-native-image-picker

* [MM-17142] Convert all string refs to callbacks (#3217)

* Replace string refs

* Fix tests

* Don't use inline functions

* Fix mattermost-redux reversion from master merge

* [MM-18336] Upload Sentry debug symbols only when SENTRY_ENABLED is true (#3227)

* Upgrade @sentry/react-native

* Run Sentry gradle tasks only when enabled

* Upgrade @sentry/react-native and remove extra Sentry build phase

* [MM-17144] Use Hermes (#3226)

* Replace string refs

* Fix tests

* Don't use inline functions

* Fix mattermost-redux reversion from master merge

* Use Hermes

* bundleCommand ram-bundle no longer needed

* Require harmony-reflect only for Android

* Fix failing test

* Path react-native's splitLayoutProps (#3337)

* [MM-18867] [MM-17186] [MM-18866] [MM-19447] [MM-18967] Upgrade to RN 0.61.2 (#3423)

* Upgrade to RN 0.61.2

* Update rn-fetch-blob commit hash

* Update react-native-keyboard-tracking-view commit hash

* Use react-native-youtube with AVPlayer fix

* Fix jest mocks

* Use updated document picker API

* Remove unnecessary linking

* Revert "MM-17759 Add code highlighting (#3072)"

This reverts commit 26b999e885.

* Fix share extension

* Revert "Revert "MM-17759 Add code highlighting (#3072)""

This reverts commit 52aca776b12dee3abe8646d0c90480f8528e86c1.

* Address PR reviews

* Rename patch to match version

* Update react-native-youtube patch

* Update dependencies

* Fix RNDocViewer reference

* Update tests and revert to redux-persist 4.10.2

* Revert "Revert "Revert "MM-17759 Add code highlighting (#3072)"""

This reverts commit 5ef383be2619b1be6167c23f128ecb4b4ad25df9.

* Android fixes after dep upgrades

* Use fresco 2.0.0

* Use mattermost forks

* Use React-Core in Mattermost.scheme instead of react

* Remove packager (#3452)

* Remove Pods from source control

* Fix unit tests

* Add new line before entering the keystore in gradle.properties

* set ios as working directory for cocoapods

* Cache cocoapods on circleCI builds

* set ios as working dir

* fix cocoapods cache key

* Unify fastlane and npm dependencies command

* Use package-lock.json checksum for npm cache

* Fix package.json and use the checksum as the cache key

* Fix package.json and use the checksum as the cache key

* changes to circleci.yaml fastlane and removing pods from git

* Fix Mattermost.xcodeproj

* Update coocoapods to 1.7.5 and fix xcode header search paths

* Update package-lock.json

* Remove unused tooltip component

* Fix incorrect ref

* Disable Hermes (#3460)

* Revert "Remove packager (#3452)"

This reverts commit b2a79e184b3242124dfdb91ae095f6ce3f4eb986.

* Disable Hermes :'(

* Update preloaded modules

* Fix packages moduleNames and modulePaths, update snapshots and update mm-redux (ts version)

* remove document picker from modulePaths

* Fix package-lock.json

* Add eslint disable rules
2019-10-28 15:04:24 -07:00

283 lines
10 KiB
JavaScript

// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {Alert, AppState, Dimensions, Linking, NativeModules, Platform} from 'react-native';
import DeviceInfo from 'react-native-device-info';
import semver from 'semver';
import {setAppState, setServerVersion} from 'mattermost-redux/actions/general';
import {loadMe, logout} from 'mattermost-redux/actions/users';
import {autoUpdateTimezone} from 'mattermost-redux/actions/timezone';
import {close as closeWebSocket} from 'mattermost-redux/actions/websocket';
import {Client4} from 'mattermost-redux/client';
import {General} from 'mattermost-redux/constants';
import EventEmitter from 'mattermost-redux/utils/event_emitter';
import {getCurrentChannelId} from 'mattermost-redux/selectors/entities/channels';
import {getCurrentUserId} from 'mattermost-redux/selectors/entities/users';
import {isTimezoneEnabled} from 'mattermost-redux/selectors/entities/timezone';
import {setDeviceDimensions, setDeviceOrientation, setDeviceAsTablet, setStatusBarHeight} from 'app/actions/device';
import {selectDefaultChannel} from 'app/actions/views/channel';
import {showOverlay} from 'app/actions/navigation';
import {loadConfigAndLicense, setDeepLinkURL, startDataCleanup} from 'app/actions/views/root';
import {NavigationTypes, ViewTypes} from 'app/constants';
import {getTranslations, resetMomentLocale} from 'app/i18n';
import mattermostManaged from 'app/mattermost_managed';
import PushNotifications from 'app/push_notifications';
import {getCurrentLocale} from 'app/selectors/i18n';
import {t} from 'app/utils/i18n';
import {deleteFileCache} from 'app/utils/file';
import {getDeviceTimezoneAsync} from 'app/utils/timezone';
import LocalConfig from 'assets/config';
import {getAppCredentials, removeAppCredentials} from './credentials';
import emmProvider from './emm_provider';
const {StatusBarManager} = NativeModules;
const PROMPT_IN_APP_PIN_CODE_AFTER = 5 * 1000;
class GlobalEventHandler {
constructor() {
EventEmitter.on(NavigationTypes.NAVIGATION_RESET, this.onLogout);
EventEmitter.on(NavigationTypes.RESTART_APP, this.onRestartApp);
EventEmitter.on(General.SERVER_VERSION_CHANGED, this.onServerVersionChanged);
EventEmitter.on(General.CONFIG_CHANGED, this.onServerConfigChanged);
EventEmitter.on(General.SWITCH_TO_DEFAULT_CHANNEL, this.onSwitchToDefaultChannel);
Dimensions.addEventListener('change', this.onOrientationChange);
AppState.addEventListener('change', this.onAppStateChange);
Linking.addEventListener('url', this.onDeepLink);
}
appActive = async () => {
this.turnOnInAppNotificationHandling();
this.setUserTimezone();
// if the app is being controlled by an EMM provider
if (emmProvider.enabled && emmProvider.inAppPinCode) {
const authExpired = (Date.now() - emmProvider.inBackgroundSince) >= PROMPT_IN_APP_PIN_CODE_AFTER;
// Once the app becomes active we check if the device needs to have a passcode set
const prompt = emmProvider.inBackgroundSince && authExpired; // if more than 5 minutes have passed prompt for passcode
await emmProvider.handleAuthentication(this.store, prompt);
}
emmProvider.inBackgroundSince = null; /* eslint-disable-line require-atomic-updates */
};
appInactive = () => {
this.turnOffInAppNotificationHandling();
const {dispatch} = this.store;
// When the app is sent to the background we set the time when that happens
// and perform a data clean up to improve on performance
emmProvider.inBackgroundSince = Date.now();
dispatch(startDataCleanup());
};
configure = (opts) => {
this.store = opts.store;
this.launchApp = opts.launchApp;
// onAppStateChange may be called by the AppState listener before we
// configure the global event handler so we manually call it here
this.onAppStateChange('active');
const window = Dimensions.get('window');
this.onOrientationChange({window});
this.StatusBarSizeIOS = require('react-native-status-bar-size');
if (Platform.OS === 'ios') {
this.StatusBarSizeIOS.addEventListener('willChange', this.onStatusBarHeightChange);
StatusBarManager.getHeight(
(data) => {
this.onStatusBarHeightChange(data.height);
}
);
}
this.JavascriptAndNativeErrorHandler = require('app/utils/error_handling').default;
this.JavascriptAndNativeErrorHandler.initializeErrorHandling(this.store);
mattermostManaged.addEventListener('managedConfigDidChange', this.onManagedConfigurationChange);
};
configureAnalytics = (config) => {
const initAnalytics = require('app/utils/segment').init;
if (!__DEV__ && config && config.DiagnosticsEnabled === 'true' && config.DiagnosticId && LocalConfig.SegmentApiKey) {
initAnalytics(config);
} else {
global.analytics = null;
}
};
onAppStateChange = (appState) => {
const isActive = appState === 'active';
const isBackground = appState === 'background';
if (this.store) {
this.store.dispatch(setAppState(isActive));
if (isActive && (!emmProvider.enabled || emmProvider.previousAppState === 'background')) {
this.appActive();
} else if (isBackground) {
this.appInactive();
}
}
emmProvider.previousAppState = appState;
};
onDeepLink = (event) => {
const {url} = event;
this.store.dispatch(setDeepLinkURL(url));
};
onManagedConfigurationChange = () => {
emmProvider.handleManagedConfig(this.store, true);
};
onServerConfigChanged = (config) => {
this.configureAnalytics(config);
};
onLogout = async () => {
this.store.dispatch(closeWebSocket(false));
this.store.dispatch(setServerVersion(''));
deleteFileCache();
removeAppCredentials();
resetMomentLocale();
PushNotifications.clearNotifications();
if (this.launchApp) {
this.launchApp();
}
};
onOrientationChange = (dimensions) => {
if (this.store) {
const {dispatch} = this.store;
if (DeviceInfo.isTablet()) {
dispatch(setDeviceAsTablet());
}
const {height, width} = dimensions.window;
const orientation = height > width ? 'PORTRAIT' : 'LANDSCAPE';
dispatch(setDeviceOrientation(orientation));
dispatch(setDeviceDimensions(height, width));
}
};
onRestartApp = async () => {
await this.store.dispatch(loadConfigAndLicense());
await this.store.dispatch(loadMe());
const window = Dimensions.get('window');
this.onOrientationChange({window});
if (Platform.OS === 'ios') {
StatusBarManager.getHeight(
(data) => {
this.onStatusBarHeightChange(data.height);
}
);
}
if (this.launchApp) {
const credentials = await getAppCredentials();
this.launchApp(credentials);
}
};
onServerVersionChanged = async (serverVersion) => {
const {dispatch, getState} = this.store;
const state = getState();
const version = serverVersion.match(/^[0-9]*.[0-9]*.[0-9]*(-[a-zA-Z0-9.-]*)?/g)[0];
const locale = getCurrentLocale(state);
const translations = getTranslations(locale);
if (serverVersion) {
if (semver.valid(version) && semver.lt(version, LocalConfig.MinServerVersion)) {
Alert.alert(
translations[t('mobile.server_upgrade.title')],
translations[t('mobile.server_upgrade.description')],
[{
text: translations[t('mobile.server_upgrade.button')],
onPress: this.serverUpgradeNeeded,
}],
{cancelable: false}
);
} else if (state.entities.users && state.entities.users.currentUserId) {
dispatch(setServerVersion(serverVersion));
const data = await dispatch(loadConfigAndLicense());
this.configureAnalytics(data.config);
}
}
};
onStatusBarHeightChange = (nextStatusBarHeight) => {
this.store.dispatch(setStatusBarHeight(nextStatusBarHeight));
};
onSwitchToDefaultChannel = (teamId) => {
this.store.dispatch(selectDefaultChannel(teamId));
};
serverUpgradeNeeded = async () => {
const {dispatch} = this.store;
dispatch(setServerVersion(''));
Client4.serverVersion = '';
const credentials = await getAppCredentials();
if (credentials) {
dispatch(logout());
}
};
turnOnInAppNotificationHandling = () => {
EventEmitter.on(ViewTypes.NOTIFICATION_IN_APP, this.handleInAppNotification);
}
turnOffInAppNotificationHandling = () => {
EventEmitter.off(ViewTypes.NOTIFICATION_IN_APP, this.handleInAppNotification);
}
handleInAppNotification = (notification) => {
const {data} = notification;
const {getState} = this.store;
const state = getState();
const currentChannelId = getCurrentChannelId(state);
if (data && data.channel_id !== currentChannelId) {
const screen = 'Notification';
const passProps = {
notification,
};
EventEmitter.emit(NavigationTypes.NAVIGATION_SHOW_OVERLAY);
showOverlay(screen, passProps);
}
};
setUserTimezone = async () => {
const {dispatch, getState} = this.store;
const state = getState();
const currentUserId = getCurrentUserId(state);
const enableTimezone = isTimezoneEnabled(state);
if (enableTimezone && currentUserId) {
const timezone = await getDeviceTimezoneAsync();
dispatch(autoUpdateTimezone(timezone));
}
};
}
export default new GlobalEventHandler();