Rocket.Chat.ReactNative/app/index.js

754 lines
18 KiB
JavaScript
Raw Normal View History

2019-03-12 16:23:06 +00:00
import React from 'react';
import {
View, Linking, BackHandler, ScrollView
} from 'react-native';
import { createAppContainer, createSwitchNavigator } from 'react-navigation';
import { createStackNavigator } from 'react-navigation-stack';
import { createDrawerNavigator } from 'react-navigation-drawer';
2019-12-04 16:39:53 +00:00
import { AppearanceProvider } from 'react-native-appearance';
2019-03-12 16:23:06 +00:00
import { Provider } from 'react-redux';
import PropTypes from 'prop-types';
2019-12-04 16:39:53 +00:00
import RNUserDefaults from 'rn-user-defaults';
2019-11-25 20:01:17 +00:00
import Modal from 'react-native-modal';
import KeyCommands, { KeyCommandsEmitter } from 'react-native-keycommands';
2019-12-04 16:39:53 +00:00
import {
defaultTheme,
newThemeState,
subscribeTheme,
unsubscribeTheme
} from './utils/theme';
2019-11-25 20:01:17 +00:00
import EventEmitter from './utils/events';
import { appInit, appInitLocalSettings } from './actions';
import { deepLinkingOpen } from './actions/deepLinking';
import Navigation from './lib/Navigation';
2019-03-12 16:23:06 +00:00
import Sidebar from './views/SidebarView';
import parseQuery from './lib/methods/helpers/parseQuery';
import { initializePushNotifications, onNotification } from './notifications/push';
2019-03-12 16:23:06 +00:00
import store from './lib/createStore';
import NotificationBadge from './notifications/inApp';
2019-12-18 21:13:11 +00:00
import {
defaultHeader, onNavigationStateChange, cardStyle, getActiveRouteName
} from './utils/navigation';
import { loggerConfig, analytics } from './utils/log';
2019-07-23 14:02:57 +00:00
import Toast from './containers/Toast';
2019-12-04 16:39:53 +00:00
import { ThemeContext } from './theme';
import RocketChat, { THEME_PREFERENCES_KEY } from './lib/rocketchat';
2019-11-25 20:01:17 +00:00
import { MIN_WIDTH_SPLIT_LAYOUT } from './constants/tablet';
import {
isTablet, isSplited, isIOS, setWidth, supportSystemTheme, isAndroid
2019-11-25 20:01:17 +00:00
} from './utils/deviceInfo';
import { KEY_COMMAND } from './commands';
import Tablet, { initTabletNav } from './tablet';
import sharedStyles from './views/Styles';
import { SplitContext } from './split';
import TwoFactor from './containers/TwoFactor';
2017-08-21 00:11:46 +00:00
import RoomsListView from './views/RoomsListView';
import RoomView from './views/RoomView';
[NEW] Passcode and biometric unlock (#2059) * Update expo libs * Configure expo-local-authentication * ScreenLockedView * Authenticate server change * Auth on app resume * localAuthentication util * Add servers.lastLocalAuthenticatedSession column * Save last session date on background * Use our own version of app state redux * Fix libs * Remove inactive * ScreenLockConfigView * Apply on saved data * Auto lock option label * Starting passcode * Basic passcode flow working * Change passcode * Check if biometry is enrolled * Use fork * Migration * Patch expo-local-authentication * Use async storage * Styling * Timer * Refactor * Lock orientation portrait when not on tablet * share extension * Deep linking * Share extension * Refactoring passcode * use state * Stash * Refactor * Change passcode * Animate dots on error * Matching passcodes * Shake * Remove lib * Delete button * Fade animation on modal * Refactoring * ItemInfo * I18n * I18n * Remove unnecessary prop * Save biometry column * Raise time to lock to 30 seconds * Vibrate on wrong confirmation passcode * Reset attempts and save last authentication on local passcode confirmation * Remove inline style * Save last auth * Fix header blink * Change function name * Fix android modal * Fix vibration permission * PasscodeEnter calls biometry * Passcode on the state * Biometry button on PasscodeEnter * Show whole passcode * Secure passcode * Save passcode with promise to prevent empty passcodes and immediately lock * Patch expo-local-authentication * I18n * Fix biometry being called every time * Blur screen on app inactive * Revert "Blur screen on app inactive" This reverts commit a4ce812934adcf6cf87eb1a92aec9283e2f26753. * Remove immediately because of how Activities work on Android * Pods * New layout * stash * Layout refactored * Fix icons * Force set passcode from server * Lint * Improve permission message * Forced passcode subtitle * Disable based on admin's choice * Require local authentication on login success * Refactor * Update tests * Update react-native-device-info to fix notch * Lint * Fix modal * Fix icons * Fix min auto lock time * Review * keep enabled on mobile * fix forced by admin when enable unlock with passcode * use DEFAULT_AUTO_LOCK when manual enable screenLock * fix check has passcode * request biometry on first password * reset auto time lock when disabled on server Co-authored-by: Djorkaeff Alexandre <djorkaeff.unb@gmail.com>
2020-05-08 17:04:37 +00:00
import ScreenLockedView from './views/ScreenLockedView';
import ChangePasscodeView from './views/ChangePasscodeView';
2019-11-04 15:19:27 +00:00
if (isIOS) {
const RNScreens = require('react-native-screens');
RNScreens.useScreens();
}
const parseDeepLinking = (url) => {
if (url) {
url = url.replace(/rocketchat:\/\/|https:\/\/go.rocket.chat\//, '');
2020-01-28 13:22:35 +00:00
const regex = /^(room|auth|invite)\?/;
if (url.match(regex)) {
url = url.replace(regex, '').trim();
if (url) {
return parseQuery(url);
}
}
}
return null;
};
2019-03-12 16:23:06 +00:00
// Outside
const OutsideStack = createStackNavigator({
OnboardingView: {
2019-07-17 13:37:20 +00:00
getScreen: () => require('./views/OnboardingView').default,
2019-03-12 16:23:06 +00:00
header: null
},
2019-07-17 13:37:20 +00:00
NewServerView: {
getScreen: () => require('./views/NewServerView').default
},
WorkspaceView: {
getScreen: () => require('./views/WorkspaceView').default
2019-07-17 13:37:20 +00:00
},
LoginView: {
getScreen: () => require('./views/LoginView').default
},
ForgotPasswordView: {
getScreen: () => require('./views/ForgotPasswordView').default
},
RegisterView: {
getScreen: () => require('./views/RegisterView').default
},
LegalView: {
getScreen: () => require('./views/LegalView').default
}
2019-03-12 16:23:06 +00:00
}, {
2019-12-04 16:39:53 +00:00
defaultNavigationOptions: defaultHeader,
cardStyle
2019-03-12 16:23:06 +00:00
});
const AuthenticationWebViewStack = createStackNavigator({
AuthenticationWebView: {
getScreen: () => require('./views/AuthenticationWebView').default
2019-07-17 13:37:20 +00:00
}
2019-03-12 16:23:06 +00:00
}, {
2019-12-04 16:39:53 +00:00
defaultNavigationOptions: defaultHeader,
cardStyle
2019-03-12 16:23:06 +00:00
});
const OutsideStackModal = createStackNavigator({
OutsideStack,
AuthenticationWebViewStack
2019-03-12 16:23:06 +00:00
},
{
mode: 'modal',
2019-12-04 16:39:53 +00:00
headerMode: 'none',
cardStyle
2019-03-12 16:23:06 +00:00
});
2019-11-25 20:01:17 +00:00
const RoomRoutes = {
RoomView,
2019-11-25 20:01:17 +00:00
ThreadMessagesView: {
getScreen: () => require('./views/ThreadMessagesView').default
},
MarkdownTableView: {
getScreen: () => require('./views/MarkdownTableView').default
},
ReadReceiptsView: {
getScreen: () => require('./views/ReadReceiptView').default
}
};
2019-03-12 16:23:06 +00:00
// Inside
const ChatsStack = createStackNavigator({
RoomsListView,
2019-07-17 13:37:20 +00:00
RoomActionsView: {
getScreen: () => require('./views/RoomActionsView').default
},
RoomInfoView: {
getScreen: () => require('./views/RoomInfoView').default
},
RoomInfoEditView: {
getScreen: () => require('./views/RoomInfoEditView').default
},
RoomMembersView: {
getScreen: () => require('./views/RoomMembersView').default
},
SearchMessagesView: {
getScreen: () => require('./views/SearchMessagesView').default
},
SelectedUsersView: {
getScreen: () => require('./views/SelectedUsersView').default
},
2020-01-28 13:22:35 +00:00
InviteUsersView: {
getScreen: () => require('./views/InviteUsersView').default
},
InviteUsersEditView: {
getScreen: () => require('./views/InviteUsersEditView').default
},
2019-07-17 13:37:20 +00:00
MessagesView: {
getScreen: () => require('./views/MessagesView').default
},
AutoTranslateView: {
getScreen: () => require('./views/AutoTranslateView').default
},
DirectoryView: {
getScreen: () => require('./views/DirectoryView').default
},
NotificationPrefView: {
getScreen: () => require('./views/NotificationPreferencesView').default
2019-11-25 20:01:17 +00:00
},
[NEW] Livechat (#2004) * [WIP][NEW] Livechat info/actions * [IMPROVEMENT] RoomActionsView * [NEW] Visitor Navigation * [NEW] Get Department REST * [FIX] Borders * [IMPROVEMENT] Refactor RoomInfo View * [FIX] Error while navigate from mention -> roomInfo * [NEW] Livechat Fields * [NEW] Close Livechat * [WIP] Forward livechat * [NEW] Return inquiry * [WIP] Comment when close livechat * [WIP] Improve roomInfo * [IMPROVEMENT] Forward room * [FIX] Department picker * [FIX] Picker without results * [FIX] Superfluous argument * [FIX] Check permissions on RoomActionsView * [FIX] Livechat permissions * [WIP] Show edit to livechat * [I18N] Add pt-br translations * [WIP] Livechat Info * [IMPROVEMENT] Livechat info * [WIP] Livechat Edit * [WIP] Livechat edit * [WIP] Livechat Edit * [WIP] Livechat edit scroll * [FIX] Edit customFields * [FIX] Clean livechat customField * [FIX] Visitor Navigation * [NEW] Next input logic LivechatEdit * [FIX] Add livechat data to subscription * [FIX] Revert change * [NEW] Livechat user Status * [WIP] Livechat tags * [NEW] Edit livechat tags * [FIX] Prevent some crashes * [FIX] Forward * [FIX] Return Livechat error * [FIX] Prevent livechat info crash * [IMPROVEMENT] Use input style on forward chat * OnboardingSeparator -> OrSeparator * [FIX] Go to next input * [NEW] Added some icons * [NEW] Livechat close * [NEW] Forward Room Action * [FIX] Livechat edit style * [FIX] Change status logic * [CHORE] Remove unnecessary logic * [CHORE] Remove unnecessary code * [CHORE] Remove unecessary case * [FIX] Superfluous argument * [IMPROVEMENT] Submit livechat edit * [CHORE] Remove textInput type * [FIX] Livechat edit * [FIX] Livechat Edit * [FIX] Use same effect * [IMPROVEMENT] Tags input * [FIX] Add empty tag * Fix minor issues * Fix typo * insert livechat room data to our room object * review * add method calls server version Co-authored-by: Diego Mello <diegolmello@gmail.com>
2020-05-08 17:36:10 +00:00
VisitorNavigationView: {
getScreen: () => require('./views/VisitorNavigationView').default
},
ForwardLivechatView: {
getScreen: () => require('./views/ForwardLivechatView').default
},
LivechatEditView: {
getScreen: () => require('./views/LivechatEditView').default
},
PickerView: {
getScreen: () => require('./views/PickerView').default
},
2019-11-25 20:01:17 +00:00
...RoomRoutes
}, {
2019-12-04 16:39:53 +00:00
defaultNavigationOptions: defaultHeader,
cardStyle
2019-11-25 20:01:17 +00:00
});
// Inside
const RoomStack = createStackNavigator({
...RoomRoutes
2019-03-12 16:23:06 +00:00
}, {
2019-12-04 16:39:53 +00:00
defaultNavigationOptions: defaultHeader,
cardStyle
2019-03-12 16:23:06 +00:00
});
ChatsStack.navigationOptions = ({ navigation }) => {
let drawerLockMode = 'unlocked';
2019-11-25 20:01:17 +00:00
if (navigation.state.index > 0 || isSplited()) {
drawerLockMode = 'locked-closed';
}
return {
drawerLockMode
};
};
2019-03-12 16:23:06 +00:00
const ProfileStack = createStackNavigator({
2019-07-17 13:37:20 +00:00
ProfileView: {
getScreen: () => require('./views/ProfileView').default
}
2019-03-12 16:23:06 +00:00
}, {
2019-12-04 16:39:53 +00:00
defaultNavigationOptions: defaultHeader,
cardStyle
2019-03-12 16:23:06 +00:00
});
ProfileStack.navigationOptions = ({ navigation }) => {
let drawerLockMode = 'unlocked';
if (navigation.state.index > 0) {
drawerLockMode = 'locked-closed';
}
return {
drawerLockMode
};
};
2019-03-12 16:23:06 +00:00
const SettingsStack = createStackNavigator({
2019-07-17 13:37:20 +00:00
SettingsView: {
getScreen: () => require('./views/SettingsView').default
},
LanguageView: {
getScreen: () => require('./views/LanguageView').default
2019-12-04 16:39:53 +00:00
},
ThemeView: {
getScreen: () => require('./views/ThemeView').default
},
DefaultBrowserView: {
getScreen: () => require('./views/DefaultBrowserView').default
[NEW] Passcode and biometric unlock (#2059) * Update expo libs * Configure expo-local-authentication * ScreenLockedView * Authenticate server change * Auth on app resume * localAuthentication util * Add servers.lastLocalAuthenticatedSession column * Save last session date on background * Use our own version of app state redux * Fix libs * Remove inactive * ScreenLockConfigView * Apply on saved data * Auto lock option label * Starting passcode * Basic passcode flow working * Change passcode * Check if biometry is enrolled * Use fork * Migration * Patch expo-local-authentication * Use async storage * Styling * Timer * Refactor * Lock orientation portrait when not on tablet * share extension * Deep linking * Share extension * Refactoring passcode * use state * Stash * Refactor * Change passcode * Animate dots on error * Matching passcodes * Shake * Remove lib * Delete button * Fade animation on modal * Refactoring * ItemInfo * I18n * I18n * Remove unnecessary prop * Save biometry column * Raise time to lock to 30 seconds * Vibrate on wrong confirmation passcode * Reset attempts and save last authentication on local passcode confirmation * Remove inline style * Save last auth * Fix header blink * Change function name * Fix android modal * Fix vibration permission * PasscodeEnter calls biometry * Passcode on the state * Biometry button on PasscodeEnter * Show whole passcode * Secure passcode * Save passcode with promise to prevent empty passcodes and immediately lock * Patch expo-local-authentication * I18n * Fix biometry being called every time * Blur screen on app inactive * Revert "Blur screen on app inactive" This reverts commit a4ce812934adcf6cf87eb1a92aec9283e2f26753. * Remove immediately because of how Activities work on Android * Pods * New layout * stash * Layout refactored * Fix icons * Force set passcode from server * Lint * Improve permission message * Forced passcode subtitle * Disable based on admin's choice * Require local authentication on login success * Refactor * Update tests * Update react-native-device-info to fix notch * Lint * Fix modal * Fix icons * Fix min auto lock time * Review * keep enabled on mobile * fix forced by admin when enable unlock with passcode * use DEFAULT_AUTO_LOCK when manual enable screenLock * fix check has passcode * request biometry on first password * reset auto time lock when disabled on server Co-authored-by: Djorkaeff Alexandre <djorkaeff.unb@gmail.com>
2020-05-08 17:04:37 +00:00
},
ScreenLockConfigView: {
getScreen: () => require('./views/ScreenLockConfigView').default
2019-07-17 13:37:20 +00:00
}
2019-03-12 16:23:06 +00:00
}, {
2019-12-04 16:39:53 +00:00
defaultNavigationOptions: defaultHeader,
cardStyle
2019-03-12 16:23:06 +00:00
});
const AdminPanelStack = createStackNavigator({
2019-07-17 13:37:20 +00:00
AdminPanelView: {
getScreen: () => require('./views/AdminPanelView').default
}
}, {
2019-12-04 16:39:53 +00:00
defaultNavigationOptions: defaultHeader,
cardStyle
});
SettingsStack.navigationOptions = ({ navigation }) => {
let drawerLockMode = 'unlocked';
if (navigation.state.index > 0) {
drawerLockMode = 'locked-closed';
}
return {
drawerLockMode
};
};
2019-03-12 16:23:06 +00:00
const ChatsDrawer = createDrawerNavigator({
ChatsStack,
ProfileStack,
SettingsStack,
AdminPanelStack
2019-03-12 16:23:06 +00:00
}, {
contentComponent: Sidebar,
overlayColor: '#00000090'
2019-03-12 16:23:06 +00:00
});
const NewMessageStack = createStackNavigator({
2019-07-17 13:37:20 +00:00
NewMessageView: {
getScreen: () => require('./views/NewMessageView').default
},
SelectedUsersViewCreateChannel: {
getScreen: () => require('./views/SelectedUsersView').default
},
CreateChannelView: {
getScreen: () => require('./views/CreateChannelView').default
}
2019-03-12 16:23:06 +00:00
}, {
2019-12-04 16:39:53 +00:00
defaultNavigationOptions: defaultHeader,
cardStyle
2019-03-12 16:23:06 +00:00
});
2019-12-18 21:13:11 +00:00
const AttachmentStack = createStackNavigator({
AttachmentView: {
getScreen: () => require('./views/AttachmentView').default
}
}, {
defaultNavigationOptions: defaultHeader,
cardStyle
});
2020-02-11 14:01:35 +00:00
const ModalBlockStack = createStackNavigator({
ModalBlockView: {
getScreen: () => require('./views/ModalBlockView').default
}
}, {
mode: 'modal',
defaultNavigationOptions: defaultHeader,
cardStyle
});
const CreateDiscussionStack = createStackNavigator({
CreateDiscussionView: {
getScreen: () => require('./views/CreateDiscussionView').default
}
}, {
defaultNavigationOptions: defaultHeader,
cardStyle
});
const StatusStack = createStackNavigator({
StatusView: {
getScreen: () => require('./views/StatusView').default
}
}, {
defaultNavigationOptions: defaultHeader,
cardStyle
});
2019-03-12 16:23:06 +00:00
const InsideStackModal = createStackNavigator({
Main: ChatsDrawer,
NewMessageStack,
2019-12-18 21:13:11 +00:00
AttachmentStack,
2020-02-11 14:01:35 +00:00
ModalBlockStack,
StatusStack,
CreateDiscussionStack,
JitsiMeetView: {
getScreen: () => require('./views/JitsiMeetView').default
}
2019-03-12 16:23:06 +00:00
},
{
mode: 'modal',
2019-12-04 16:39:53 +00:00
headerMode: 'none',
cardStyle
2019-03-12 16:23:06 +00:00
});
const SetUsernameStack = createStackNavigator({
2019-07-17 13:37:20 +00:00
SetUsernameView: {
getScreen: () => require('./views/SetUsernameView').default
}
2019-12-04 16:39:53 +00:00
},
{
cardStyle
2019-03-12 16:23:06 +00:00
});
class CustomInsideStack extends React.Component {
static router = InsideStackModal.router;
static propTypes = {
2019-11-25 20:01:17 +00:00
navigation: PropTypes.object,
screenProps: PropTypes.object
}
render() {
2019-11-25 20:01:17 +00:00
const { navigation, screenProps } = this.props;
return (
<>
<InsideStackModal navigation={navigation} screenProps={screenProps} />
{ !isTablet ? <NotificationBadge navigation={navigation} /> : null }
{ !isTablet ? <Toast /> : null }
</>
);
}
}
class CustomRoomStack extends React.Component {
static router = RoomStack.router;
static propTypes = {
navigation: PropTypes.object,
screenProps: PropTypes.object
}
render() {
const { navigation, screenProps } = this.props;
return (
<>
2019-11-25 20:01:17 +00:00
<RoomStack navigation={navigation} screenProps={screenProps} />
2019-07-23 14:02:57 +00:00
<Toast />
</>
);
}
}
2019-11-25 20:01:17 +00:00
const MessagesStack = createStackNavigator({
NewMessageView: {
getScreen: () => require('./views/NewMessageView').default
},
SelectedUsersViewCreateChannel: {
getScreen: () => require('./views/SelectedUsersView').default
},
CreateChannelView: {
getScreen: () => require('./views/CreateChannelView').default
}
}, {
2019-12-04 16:39:53 +00:00
defaultNavigationOptions: defaultHeader,
cardStyle
2019-11-25 20:01:17 +00:00
});
const DirectoryStack = createStackNavigator({
DirectoryView: {
getScreen: () => require('./views/DirectoryView').default
}
}, {
2019-12-04 16:39:53 +00:00
defaultNavigationOptions: defaultHeader,
cardStyle
2019-11-25 20:01:17 +00:00
});
const SidebarStack = createStackNavigator({
SettingsView: {
getScreen: () => require('./views/SettingsView').default
},
ProfileView: {
getScreen: () => require('./views/ProfileView').default
},
AdminPanelView: {
getScreen: () => require('./views/AdminPanelView').default
},
StatusView: {
getScreen: () => require('./views/StatusView').default
2019-11-25 20:01:17 +00:00
}
}, {
2019-12-04 16:39:53 +00:00
defaultNavigationOptions: defaultHeader,
cardStyle
2019-11-25 20:01:17 +00:00
});
const RoomActionsStack = createStackNavigator({
RoomActionsView: {
getScreen: () => require('./views/RoomActionsView').default
},
RoomInfoView: {
getScreen: () => require('./views/RoomInfoView').default
},
RoomInfoEditView: {
getScreen: () => require('./views/RoomInfoEditView').default
},
RoomMembersView: {
getScreen: () => require('./views/RoomMembersView').default
},
SearchMessagesView: {
getScreen: () => require('./views/SearchMessagesView').default
},
SelectedUsersView: {
getScreen: () => require('./views/SelectedUsersView').default
},
MessagesView: {
getScreen: () => require('./views/MessagesView').default
},
AutoTranslateView: {
getScreen: () => require('./views/AutoTranslateView').default
},
ReadReceiptsView: {
getScreen: () => require('./views/ReadReceiptView').default
},
NotificationPrefView: {
getScreen: () => require('./views/NotificationPreferencesView').default
2019-12-18 21:13:11 +00:00
},
AttachmentView: {
getScreen: () => require('./views/AttachmentView').default
},
PickerView: {
getScreen: () => require('./views/PickerView').default
2019-11-25 20:01:17 +00:00
}
}, {
2019-12-04 16:39:53 +00:00
defaultNavigationOptions: defaultHeader,
cardStyle
2019-11-25 20:01:17 +00:00
});
const ModalSwitch = createSwitchNavigator({
MessagesStack,
DirectoryStack,
SidebarStack,
RoomActionsStack,
SettingsStack,
2020-02-11 14:01:35 +00:00
ModalBlockStack,
CreateDiscussionStack,
2019-11-25 20:01:17 +00:00
AuthLoading: () => null
},
{
initialRouteName: 'AuthLoading'
});
class CustomModalStack extends React.Component {
static router = ModalSwitch.router;
static propTypes = {
navigation: PropTypes.object,
showModal: PropTypes.bool,
closeModal: PropTypes.func,
screenProps: PropTypes.object
}
componentDidMount() {
this.backHandler = BackHandler.addEventListener('hardwareBackPress', this.closeModal);
}
componentWillUnmount() {
this.backHandler.remove();
}
closeModal = () => {
const { closeModal, navigation } = this.props;
const { state } = navigation;
if (state && state.routes[state.index] && state.routes[state.index].index === 0) {
closeModal();
return true;
}
if (state && state.routes[state.index] && state.routes[state.index].routes && state.routes[state.index].routes.length > 1) {
2020-02-11 14:01:35 +00:00
navigation.goBack();
}
2019-11-25 20:01:17 +00:00
return false;
}
render() {
const {
navigation, showModal, closeModal, screenProps
} = this.props;
2019-12-18 21:13:11 +00:00
const pageSheetViews = ['AttachmentView'];
const pageSheet = pageSheetViews.includes(getActiveRouteName(navigation.state));
const androidProps = isAndroid && !pageSheet && {
style: { marginBottom: 0 }
};
let content = (
<View style={[sharedStyles.modal, pageSheet ? sharedStyles.modalPageSheet : sharedStyles.modalFormSheet]}>
<ModalSwitch navigation={navigation} screenProps={{ ...screenProps, closeModal: this.closeModal }} />
</View>
);
if (isAndroid && !pageSheet) {
content = (
<ScrollView overScrollMode='never'>
{content}
</ScrollView>
);
}
2019-11-25 20:01:17 +00:00
return (
<Modal
useNativeDriver
coverScreen={false}
isVisible={showModal}
onBackdropPress={closeModal}
hideModalContentWhileAnimating
avoidKeyboard
{...androidProps}
2019-11-25 20:01:17 +00:00
>
{content}
2019-11-25 20:01:17 +00:00
</Modal>
);
}
}
class CustomNotificationStack extends React.Component {
static router = InsideStackModal.router;
static propTypes = {
2019-12-04 16:39:53 +00:00
navigation: PropTypes.object,
screenProps: PropTypes.object
2019-11-25 20:01:17 +00:00
}
render() {
2019-12-04 16:39:53 +00:00
const { navigation, screenProps } = this.props;
return <NotificationBadge navigation={navigation} screenProps={screenProps} />;
2019-11-25 20:01:17 +00:00
}
}
export const App = createAppContainer(createSwitchNavigator(
2019-03-12 16:23:06 +00:00
{
OutsideStack: OutsideStackModal,
InsideStack: CustomInsideStack,
2019-07-17 13:37:20 +00:00
AuthLoading: {
getScreen: () => require('./views/AuthLoadingView').default
},
2019-03-12 16:23:06 +00:00
SetUsernameStack
},
{
initialRouteName: 'AuthLoading'
}
2019-03-12 16:23:06 +00:00
));
2019-11-25 20:01:17 +00:00
export const RoomContainer = createAppContainer(CustomRoomStack);
export const ModalContainer = createAppContainer(CustomModalStack);
export const NotificationContainer = createAppContainer(CustomNotificationStack);
export default class Root extends React.Component {
constructor(props) {
super(props);
this.init();
this.initCrashReport();
2019-11-25 20:01:17 +00:00
this.state = {
split: false,
inside: false,
2019-12-04 16:39:53 +00:00
showModal: false,
theme: defaultTheme(),
themePreferences: {
currentTheme: supportSystemTheme() ? 'automatic' : 'light',
darkLevel: 'dark'
}
2019-11-25 20:01:17 +00:00
};
if (isTablet) {
this.initTablet();
}
}
componentDidMount() {
this.listenerTimeout = setTimeout(() => {
Linking.addEventListener('url', ({ url }) => {
const parsedDeepLinkingURL = parseDeepLinking(url);
if (parsedDeepLinkingURL) {
store.dispatch(deepLinkingOpen(parsedDeepLinkingURL));
}
});
}, 5000);
}
2019-11-25 20:01:17 +00:00
// eslint-disable-next-line no-unused-vars
componentDidUpdate(_, prevState) {
if (isTablet) {
const { split, inside } = this.state;
if (inside && split !== prevState.split) {
// Reset app on split mode changes
Navigation.navigate('RoomsListView');
this.closeModal();
}
}
}
componentWillUnmount() {
clearTimeout(this.listenerTimeout);
2019-12-04 16:39:53 +00:00
unsubscribeTheme();
2019-11-25 20:01:17 +00:00
if (this.onKeyCommands && this.onKeyCommands.remove) {
this.onKeyCommands.remove();
}
}
init = async() => {
2019-12-04 16:39:53 +00:00
RNUserDefaults.objectForKey(THEME_PREFERENCES_KEY).then(this.setTheme);
const [notification, deepLinking] = await Promise.all([initializePushNotifications(), Linking.getInitialURL()]);
const parsedDeepLinkingURL = parseDeepLinking(deepLinking);
store.dispatch(appInitLocalSettings());
if (notification) {
onNotification(notification);
} else if (parsedDeepLinkingURL) {
store.dispatch(deepLinkingOpen(parsedDeepLinkingURL));
} else {
store.dispatch(appInit());
}
}
2019-12-04 16:39:53 +00:00
setTheme = (newTheme = {}) => {
// change theme state
this.setState(prevState => newThemeState(prevState, newTheme), () => {
const { themePreferences } = this.state;
// subscribe to Appearance changes
subscribeTheme(themePreferences, this.setTheme);
});
}
2019-11-25 20:01:17 +00:00
initTablet = async() => {
initTabletNav(args => this.setState(args));
await KeyCommands.setKeyCommands([]);
this.onKeyCommands = KeyCommandsEmitter.addListener(
'onKeyCommand',
command => EventEmitter.emit(KEY_COMMAND, { event: command })
);
}
initCrashReport = () => {
RocketChat.getAllowCrashReport()
.then((allowCrashReport) => {
if (!allowCrashReport) {
loggerConfig.autoNotify = false;
loggerConfig.registerBeforeSendCallback(() => false);
analytics().setAnalyticsCollectionEnabled(false);
}
});
}
2019-11-25 20:01:17 +00:00
onLayout = ({ nativeEvent: { layout: { width } } }) => (isTablet ? this.setSplit(width) : null);
setSplit = (width) => {
this.setState({ split: width > MIN_WIDTH_SPLIT_LAYOUT });
setWidth(width);
}
closeModal = () => this.setState({ showModal: false });
render() {
2019-12-04 16:39:53 +00:00
const { split, themePreferences, theme } = this.state;
2019-11-25 20:01:17 +00:00
let content = (
<App
ref={(navigatorRef) => {
Navigation.setTopLevelNavigator(navigatorRef);
}}
2019-12-04 16:39:53 +00:00
screenProps={{ split, theme }}
2019-11-25 20:01:17 +00:00
onNavigationStateChange={onNavigationStateChange}
/>
);
if (isTablet) {
const { inside, showModal } = this.state;
content = (
<SplitContext.Provider value={{ split }}>
<Tablet
2019-12-04 16:39:53 +00:00
theme={theme}
2019-11-25 20:01:17 +00:00
tablet={split}
inside={inside}
showModal={showModal}
closeModal={this.closeModal}
onLayout={this.onLayout}
>
{content}
</Tablet>
</SplitContext.Provider>
);
}
return (
2019-12-04 16:39:53 +00:00
<AppearanceProvider>
<Provider store={store}>
<ThemeContext.Provider
value={{
theme,
themePreferences,
setTheme: this.setTheme
}}
>
{content}
<TwoFactor />
[NEW] Passcode and biometric unlock (#2059) * Update expo libs * Configure expo-local-authentication * ScreenLockedView * Authenticate server change * Auth on app resume * localAuthentication util * Add servers.lastLocalAuthenticatedSession column * Save last session date on background * Use our own version of app state redux * Fix libs * Remove inactive * ScreenLockConfigView * Apply on saved data * Auto lock option label * Starting passcode * Basic passcode flow working * Change passcode * Check if biometry is enrolled * Use fork * Migration * Patch expo-local-authentication * Use async storage * Styling * Timer * Refactor * Lock orientation portrait when not on tablet * share extension * Deep linking * Share extension * Refactoring passcode * use state * Stash * Refactor * Change passcode * Animate dots on error * Matching passcodes * Shake * Remove lib * Delete button * Fade animation on modal * Refactoring * ItemInfo * I18n * I18n * Remove unnecessary prop * Save biometry column * Raise time to lock to 30 seconds * Vibrate on wrong confirmation passcode * Reset attempts and save last authentication on local passcode confirmation * Remove inline style * Save last auth * Fix header blink * Change function name * Fix android modal * Fix vibration permission * PasscodeEnter calls biometry * Passcode on the state * Biometry button on PasscodeEnter * Show whole passcode * Secure passcode * Save passcode with promise to prevent empty passcodes and immediately lock * Patch expo-local-authentication * I18n * Fix biometry being called every time * Blur screen on app inactive * Revert "Blur screen on app inactive" This reverts commit a4ce812934adcf6cf87eb1a92aec9283e2f26753. * Remove immediately because of how Activities work on Android * Pods * New layout * stash * Layout refactored * Fix icons * Force set passcode from server * Lint * Improve permission message * Forced passcode subtitle * Disable based on admin's choice * Require local authentication on login success * Refactor * Update tests * Update react-native-device-info to fix notch * Lint * Fix modal * Fix icons * Fix min auto lock time * Review * keep enabled on mobile * fix forced by admin when enable unlock with passcode * use DEFAULT_AUTO_LOCK when manual enable screenLock * fix check has passcode * request biometry on first password * reset auto time lock when disabled on server Co-authored-by: Djorkaeff Alexandre <djorkaeff.unb@gmail.com>
2020-05-08 17:04:37 +00:00
<ScreenLockedView />
<ChangePasscodeView />
2019-12-04 16:39:53 +00:00
</ThemeContext.Provider>
</Provider>
</AppearanceProvider>
);
}
}