import React from 'react';
import { Dimensions, StyleSheet } from 'react-native';
import { ThemeColors, ThemeContext, SceneView } from '@react-navigation/core';
import DrawerLayout from 'react-native-gesture-handler/DrawerLayout';
import { ScreenContainer } from 'react-native-screens';
import DrawerActions from '../routers/DrawerActions';
import DrawerSidebar from './DrawerSidebar';
import DrawerGestureContext from '../utils/DrawerGestureContext';
import ResourceSavingScene from '../views/ResourceSavingScene';
/**
* Component that renders the drawer.
*/
export default class DrawerView extends React.PureComponent {
static contextType = ThemeContext;
static defaultProps = {
lazy: true
};
static getDerivedStateFromProps(nextProps, prevState) {
const { index } = nextProps.navigation.state;
return {
// Set the current tab to be loaded if it was not loaded before
loaded: prevState.loaded.includes(index) ? prevState.loaded : [...prevState.loaded, index]
};
}
state = {
loaded: [this.props.navigation.state.index],
drawerWidth: typeof this.props.navigationConfig.drawerWidth === 'function' ? this.props.navigationConfig.drawerWidth() : this.props.navigationConfig.drawerWidth
};
componentDidMount() {
Dimensions.addEventListener('change', this._updateWidth);
}
componentDidUpdate(prevProps) {
const {
openId,
closeId,
toggleId,
isDrawerOpen
} = this.props.navigation.state;
const {
openId: prevOpenId,
closeId: prevCloseId,
toggleId: prevToggleId
} = prevProps.navigation.state;
let prevIds = [prevOpenId, prevCloseId, prevToggleId];
let changedIds = [openId, closeId, toggleId].filter(id => !prevIds.includes(id)).sort((a, b) => a > b);
changedIds.forEach(id => {
if (id === openId) {
this._drawer.openDrawer();
} else if (id === closeId) {
this._drawer.closeDrawer();
} else if (id === toggleId) {
if (isDrawerOpen) {
this._drawer.closeDrawer();
} else {
this._drawer.openDrawer();
}
}
});
}
componentWillUnmount() {
Dimensions.removeEventListener('change', this._updateWidth);
}
drawerGestureRef = React.createRef();
_handleDrawerStateChange = (newState, willShow) => {
if (newState === 'Idle') {
if (!this.props.navigation.state.isDrawerIdle) {
this.props.navigation.dispatch({
type: DrawerActions.MARK_DRAWER_IDLE,
key: this.props.navigation.state.key
});
}
} else if (newState === 'Settling') {
this.props.navigation.dispatch({
type: DrawerActions.MARK_DRAWER_SETTLING,
key: this.props.navigation.state.key,
willShow
});
} else {
if (this.props.navigation.state.isDrawerIdle) {
this.props.navigation.dispatch({
type: DrawerActions.MARK_DRAWER_ACTIVE,
key: this.props.navigation.state.key
});
}
}
};
_handleDrawerOpen = () => {
this.props.navigation.dispatch({
type: DrawerActions.DRAWER_OPENED,
key: this.props.navigation.state.key
});
};
_handleDrawerClose = () => {
this.props.navigation.dispatch({
type: DrawerActions.DRAWER_CLOSED,
key: this.props.navigation.state.key
});
};
_updateWidth = () => {
const drawerWidth = typeof this.props.navigationConfig.drawerWidth === 'function' ? this.props.navigationConfig.drawerWidth() : this.props.navigationConfig.drawerWidth;
if (this.state.drawerWidth !== drawerWidth) {
this.setState({ drawerWidth });
}
};
_renderNavigationView = drawerOpenProgress => {
return <DrawerGestureContext.Provider value={this.drawerGestureRef}>
<DrawerSidebar screenProps={this.props.screenProps} drawerOpenProgress={drawerOpenProgress} navigation={this.props.navigation} descriptors={this.props.descriptors} contentComponent={this.props.navigationConfig.contentComponent} contentOptions={this.props.navigationConfig.contentOptions} drawerPosition={this.props.navigationConfig.drawerPosition} style={this.props.navigationConfig.style} {...this.props.navigationConfig} />
</DrawerGestureContext.Provider>;
};
_renderContent = () => {
let { lazy, navigation } = this.props;
let { loaded } = this.state;
let { routes } = navigation.state;
if (this.props.navigationConfig.unmountInactiveRoutes) {
let activeKey = navigation.state.routes[navigation.state.index].key;
let descriptor = this.props.descriptors[activeKey];
return <SceneView navigation={descriptor.navigation} screenProps={this.props.screenProps} component={descriptor.getComponent()} />;
} else {
return <ScreenContainer style={styles.pages}>
{routes.map((route, index) => {
if (lazy && !loaded.includes(index)) {
// Don't render a screen if we've never navigated to it
return null;
}
let isFocused = navigation.state.index === index;
let descriptor = this.props.descriptors[route.key];
return <ResourceSavingScene key={route.key} style={[StyleSheet.absoluteFill, { opacity: isFocused ? 1 : 0 }]} isVisible={isFocused}>
<SceneView navigation={descriptor.navigation} screenProps={this.props.screenProps} component={descriptor.getComponent()} />
</ResourceSavingScene>;
})}
</ScreenContainer>;
}
};
_setDrawerGestureRef = ref => {
this.drawerGestureRef.current = ref;
};
render() {
const { navigation } = this.props;
const activeKey = navigation.state.routes[navigation.state.index].key;
const { drawerLockMode } = this.props.descriptors[activeKey].options;
let { overlayColor, drawerBackgroundColor } = this.props.navigationConfig;
if (drawerBackgroundColor) {
drawerBackgroundColor = typeof drawerBackgroundColor === 'string' ? drawerBackgroundColor : drawerBackgroundColor[this.context];
} else {
drawerBackgroundColor = ThemeColors[this.context].bodyContent;
}
if (overlayColor) {
overlayColor = typeof overlayColor === 'string' ? overlayColor : overlayColor[this.context];
} else {
overlayColor = ThemeColors[this.context].bodyContent;
}
return <DrawerLayout ref={c => {
this._drawer = c;
}} onGestureRef={this._setDrawerGestureRef} drawerLockMode={drawerLockMode || this.props.screenProps && this.props.screenProps.drawerLockMode || this.props.navigationConfig.drawerLockMode} drawerBackgroundColor={drawerBackgroundColor} overlayColor={overlayColor} keyboardDismissMode={this.props.navigationConfig.keyboardDismissMode} drawerWidth={this.state.drawerWidth} onDrawerOpen={this._handleDrawerOpen} onDrawerClose={this._handleDrawerClose} onDrawerStateChanged={this._handleDrawerStateChange} useNativeAnimations={this.props.navigationConfig.useNativeAnimations} renderNavigationView={this._renderNavigationView} drawerPosition={this.props.navigationConfig.drawerPosition === 'right' ? DrawerLayout.positions.Right : DrawerLayout.positions.Left}
/* props specific to react-native-gesture-handler/DrawerLayout */
drawerType={this.props.navigationConfig.drawerType} edgeWidth={this.props.navigationConfig.edgeWidth} hideStatusBar={this.props.navigationConfig.hideStatusBar} statusBarAnimation={this.props.navigationConfig.statusBarAnimation} minSwipeDistance={this.props.navigationConfig.minSwipeDistance} drawerContainerStyle={this.props.navigationConfig.drawerContainerStyle} contentContainerStyle={this.props.navigationConfig.contentContainerStyle}>
<DrawerGestureContext.Provider value={this.drawerGestureRef}>
{this._renderContent()}
</DrawerGestureContext.Provider>
</DrawerLayout>;
}
}
const styles = StyleSheet.create({
pages: {
flex: 1
}
});