Files
mattermost-mobile/app/app.js

321 lines
10 KiB
JavaScript

// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
/* eslint-disable global-require*/
import {AsyncStorage, Linking, NativeModules, Platform, Text} from 'react-native';
import {setGenericPassword, getGenericPassword, resetGenericPassword} from 'react-native-keychain';
import {loadMe} from 'mattermost-redux/actions/users';
import {Client4} from 'mattermost-redux/client';
import EventEmitter from 'mattermost-redux/utils/event_emitter';
import {setDeepLinkURL} from 'app/actions/views/root';
import {ViewTypes} from 'app/constants';
import tracker from 'app/utils/time_tracker';
import {getCurrentLocale} from 'app/selectors/i18n';
import {getTranslations as getLocalTranslations} from 'app/i18n';
import {store, handleManagedConfig} from 'app/mattermost';
import avoidNativeBridge from 'app/utils/avoid_native_bridge';
const {Initialization} = NativeModules;
const TOOLBAR_BACKGROUND = 'TOOLBAR_BACKGROUND';
const TOOLBAR_TEXT_COLOR = 'TOOLBAR_TEXT_COLOR';
const APP_BACKGROUND = 'APP_BACKGROUND';
export default class App {
constructor() {
// Usage: app.js
this.shouldRelaunchWhenActive = false;
this.inBackgroundSince = null;
// Usage: screen/entry.js
this.startAppFromPushNotification = false;
this.isNotificationsConfigured = false;
this.allowOtherServers = true;
this.appStarted = false;
this.emmEnabled = false;
this.performingEMMAuthentication = false;
this.translations = null;
this.toolbarBackground = null;
this.toolbarTextColor = null;
this.appBackground = null;
// Usage utils/push_notifications.js
this.replyNotificationData = null;
this.deviceToken = null;
// Usage credentials
this.currentUserId = null;
this.token = null;
this.url = null;
// Load polyfill for iOS 9
if (Platform.OS === 'ios') {
const majorVersionIOS = parseInt(Platform.Version, 10);
if (majorVersionIOS < 10) {
require('@babel/polyfill');
}
}
// Usage deeplinking
Linking.addEventListener('url', this.handleDeepLink);
this.setFontFamily();
this.getStartupThemes();
this.getAppCredentials();
}
setFontFamily = () => {
// Set a global font for Android
if (Platform.OS === 'android') {
const defaultFontFamily = {
style: {
fontFamily: 'Roboto',
},
};
const TextRender = Text.render;
const initialDefaultProps = Text.defaultProps;
Text.defaultProps = {
...initialDefaultProps,
...defaultFontFamily,
};
Text.render = function render(props, ...args) {
const oldProps = props;
let newProps = {...props, style: [defaultFontFamily.style, props.style]};
try {
return Reflect.apply(TextRender, this, [newProps, ...args]);
} finally {
newProps = oldProps;
}
};
}
};
getTranslations = () => {
if (this.translations) {
return this.translations;
}
const state = store.getState();
const locale = getCurrentLocale(state);
this.translations = getLocalTranslations(locale);
return this.translations;
};
getAppCredentials = async () => {
try {
const credentials = await avoidNativeBridge(
() => {
return Initialization.credentialsExist;
},
() => {
return Initialization.credentials;
},
() => {
this.waitForRehydration = true;
return getGenericPassword();
}
);
if (credentials) {
const usernameParsed = credentials.username.split(',');
const passwordParsed = credentials.password.split(',');
// username == deviceToken, currentUserId
// password == token, url
if (usernameParsed.length === 2 && passwordParsed.length === 2) {
const [deviceToken, currentUserId] = usernameParsed;
const [token, url] = passwordParsed;
// if for any case the url and the token aren't valid proceed with re-hydration
if (url && url !== 'undefined' && token && token !== 'undefined') {
this.deviceToken = deviceToken;
this.currentUserId = currentUserId;
this.token = token;
this.url = url;
Client4.setUrl(url);
Client4.setToken(token);
} else {
this.waitForRehydration = true;
}
}
} else {
this.waitForRehydration = false;
}
} catch (error) {
return null;
}
return null;
};
getStartupThemes = async () => {
try {
const [
toolbarBackground,
toolbarTextColor,
appBackground,
] = await avoidNativeBridge(
() => {
return Initialization.themesExist;
},
() => {
return [
Initialization.toolbarBackground,
Initialization.toolbarTextColor,
Initialization.appBackground,
];
},
() => {
return Promise.all([
AsyncStorage.getItem(TOOLBAR_BACKGROUND),
AsyncStorage.getItem(TOOLBAR_TEXT_COLOR),
AsyncStorage.getItem(APP_BACKGROUND),
]);
}
);
if (toolbarBackground) {
this.toolbarBackground = toolbarBackground;
this.toolbarTextColor = toolbarTextColor;
this.appBackground = appBackground;
}
} catch (error) {
return null;
}
return null;
};
setPerformingEMMAuthentication = (authenticating) => {
this.performingEMMAuthentication = authenticating;
};
setAppCredentials = (deviceToken, currentUserId, token, url) => {
if (!currentUserId) {
return;
}
const username = `${deviceToken}, ${currentUserId}`;
const password = `${token},${url}`;
if (this.waitForRehydration) {
this.waitForRehydration = false;
this.token = token;
this.url = url;
}
// Only save to keychain if the url and token are set
if (url && token) {
try {
setGenericPassword(username, password);
} catch (e) {
console.warn('could not set credentials', e); //eslint-disable-line no-console
}
}
};
setStartupThemes = (toolbarBackground, toolbarTextColor, appBackground) => {
AsyncStorage.setItem(TOOLBAR_BACKGROUND, toolbarBackground);
AsyncStorage.setItem(TOOLBAR_TEXT_COLOR, toolbarTextColor);
AsyncStorage.setItem(APP_BACKGROUND, appBackground);
};
setStartAppFromPushNotification = (startAppFromPushNotification) => {
this.startAppFromPushNotification = startAppFromPushNotification;
};
setIsNotificationsConfigured = (isNotificationsConfigured) => {
this.isNotificationsConfigured = isNotificationsConfigured;
};
setAllowOtherServers = (allowOtherServers) => {
this.allowOtherServers = allowOtherServers;
};
setAppStarted = (appStarted) => {
this.appStarted = appStarted;
};
setEMMEnabled = (emmEnabled) => {
this.emmEnabled = emmEnabled;
};
setDeviceToken = (deviceToken) => {
this.deviceToken = deviceToken;
};
setReplyNotificationData = (replyNotificationData) => {
this.replyNotificationData = replyNotificationData;
};
setInBackgroundSince = (inBackgroundSince) => {
this.inBackgroundSince = inBackgroundSince;
};
setShouldRelaunchWhenActive = (shouldRelaunchWhenActive) => {
this.shouldRelaunchWhenActive = shouldRelaunchWhenActive;
};
clearNativeCache = () => {
resetGenericPassword();
AsyncStorage.multiRemove([
TOOLBAR_BACKGROUND,
TOOLBAR_TEXT_COLOR,
APP_BACKGROUND,
]);
};
handleDeepLink = (event) => {
const {url} = event;
store.dispatch(setDeepLinkURL(url));
}
launchApp = async () => {
const shouldStart = await handleManagedConfig();
if (shouldStart) {
this.startApp();
}
};
startApp = () => {
if (this.appStarted || this.waitForRehydration) {
return;
}
const {dispatch} = store;
Linking.getInitialURL().then((url) => {
dispatch(setDeepLinkURL(url));
});
let screen = 'SelectServer';
if (this.token && this.url) {
screen = 'Channel';
tracker.initialLoad = Date.now();
try {
dispatch(loadMe());
} catch (e) {
// Fall through since we should have a previous version of the current user because we have a token
console.warn('Failed to load current user when starting on Channel screen', e); // eslint-disable-line no-console
}
}
switch (screen) {
case 'SelectServer':
EventEmitter.emit(ViewTypes.LAUNCH_LOGIN, true);
break;
case 'Channel':
EventEmitter.emit(ViewTypes.LAUNCH_CHANNEL, true);
break;
}
this.setStartAppFromPushNotification(false);
this.setAppStarted(true);
}
}