// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. import React, {PureComponent} from 'react'; import PropTypes from 'prop-types'; import {Dimensions, Keyboard, NativeModules, View} from 'react-native'; import SafeArea from 'react-native-safe-area'; import {DeviceTypes} from 'app/constants'; const {StatusBarManager} = NativeModules; export default class SafeAreaIos extends PureComponent { static propTypes = { backgroundColor: PropTypes.string, children: PropTypes.node.isRequired, excludeHeader: PropTypes.bool, footerColor: PropTypes.string, footerComponent: PropTypes.node, forceTop: PropTypes.number, keyboardOffset: PropTypes.number.isRequired, navBarBackgroundColor: PropTypes.string, navigator: PropTypes.object, headerComponent: PropTypes.node, theme: PropTypes.object.isRequired, }; static defaultProps = { keyboardOffset: 0, }; constructor(props) { super(props); if (props.navigator) { props.navigator.setOnNavigatorEvent(this.onNavigatorEvent); } this.state = { keyboard: false, safeAreaInsets: { top: DeviceTypes.IS_IPHONE_X ? 44 : 20, left: 0, bottom: DeviceTypes.IS_IPHONE_X ? 34 : 15, right: 0, }, statusBarHeight: 20, }; } componentWillMount() { this.mounted = true; this.getSafeAreaInsets(); this.mounted = true; } componentDidMount() { Dimensions.addEventListener('change', this.getSafeAreaInsets); this.keyboardDidShowListener = Keyboard.addListener('keyboardWillShow', this.keyboardWillShow); this.keyboardDidHideListener = Keyboard.addListener('keyboardWillHide', this.keyboardWillHide); this.getStatusBarHeight(); } componentWillUnmount() { this.mounted = false; Dimensions.removeEventListener('change', this.getSafeAreaInsets); this.keyboardDidShowListener.remove(); this.keyboardDidHideListener.remove(); this.mounted = false; } getStatusBarHeight = () => { try { StatusBarManager.getHeight( (statusBarFrameData) => { if (this.mounted) { this.setState({statusBarHeight: statusBarFrameData.height}); } } ); } catch (e) { // not needed } }; getSafeAreaInsets = () => { this.getStatusBarHeight(); if (DeviceTypes.IS_IPHONE_X) { SafeArea.getSafeAreaInsetsForRootView().then((result) => { const {safeAreaInsets} = result; if (this.mounted) { this.setState({safeAreaInsets}); } }); } }; keyboardWillHide = () => { this.setState({keyboard: false}); }; keyboardWillShow = () => { this.setState({keyboard: true}); }; onNavigatorEvent = (event) => { switch (event.id) { case 'willAppear': case 'didDisappear': this.getSafeAreaInsets(); break; } }; renderTopBar = () => { const {safeAreaInsets, statusBarHeight} = this.state; const {headerComponent, excludeHeader, forceTop, navBarBackgroundColor, theme} = this.props; const hideTopBar = excludeHeader || !statusBarHeight; if (hideTopBar) { return null; } let topColor = theme.sidebarHeaderBg; if (navBarBackgroundColor) { topColor = navBarBackgroundColor; } let top = safeAreaInsets.top; if (forceTop && DeviceTypes.IS_IPHONE_X && !hideTopBar) { top = forceTop; } if (headerComponent) { return ( {headerComponent} ); } return ( ); }; render() { const {backgroundColor, children, footerColor, footerComponent, keyboardOffset, theme} = this.props; const {keyboard, safeAreaInsets} = this.state; let bgColor = theme.centerChannelBg; if (backgroundColor) { bgColor = backgroundColor; } let bottomColor = theme.centerChannelBg; if (footerColor) { bottomColor = footerColor; } let offset = 0; if (keyboardOffset && DeviceTypes.IS_IPHONE_X) { offset = keyboardOffset; } return ( {this.renderTopBar()} {children} {footerComponent} ); } }