* Remove mattermost-redux * Move mm-redux files into app/redux * Add @redux path to tsconfig.json * Fix imports * Install missing dependencies * Fix tsc errors * Fix i18n_utils test * Fix more imports * Remove redux websocket * Fix tests * Rename @redux * Apply changes from mattermost-redux PR 1103 * Remove mattermost-redux mention in template * Add missing imports * Rename app/redux/ to app/mm-redux/ * Remove test file * Fix fetching Sidebar GM profiles Co-authored-by: Elias Nahum <nahumhbl@gmail.com>
229 lines
7.4 KiB
JavaScript
229 lines
7.4 KiB
JavaScript
// 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 EventEmitter from '@mm-redux/utils/event_emitter';
|
|
|
|
import {DeviceTypes, ViewTypes} from 'app/constants';
|
|
import mattermostManaged from 'app/mattermost_managed';
|
|
import EphemeralStore from 'app/store/ephemeral_store';
|
|
|
|
const {StatusBarManager} = NativeModules;
|
|
const {PORTRAIT, LANDSCAPE} = ViewTypes;
|
|
|
|
export default class SafeAreaIos extends PureComponent {
|
|
static propTypes = {
|
|
backgroundColor: PropTypes.string,
|
|
children: PropTypes.node.isRequired,
|
|
excludeHeader: PropTypes.bool,
|
|
excludeFooter: PropTypes.bool,
|
|
footerColor: PropTypes.string,
|
|
footerComponent: PropTypes.node,
|
|
forceTop: PropTypes.number,
|
|
keyboardOffset: PropTypes.number.isRequired,
|
|
navBarBackgroundColor: PropTypes.string,
|
|
headerComponent: PropTypes.node,
|
|
theme: PropTypes.object.isRequired,
|
|
useLandscapeMargin: PropTypes.bool.isRequired,
|
|
};
|
|
|
|
static defaultProps = {
|
|
keyboardOffset: 0,
|
|
useLandscapeMargin: false,
|
|
};
|
|
|
|
constructor(props) {
|
|
super(props);
|
|
|
|
let insetBottom = 0;
|
|
if ((DeviceTypes.IS_IPHONE_WITH_INSETS || mattermostManaged.hasSafeAreaInsets) && props.excludeFooter) {
|
|
insetBottom = 20;
|
|
}
|
|
|
|
this.state = {
|
|
keyboard: false,
|
|
safeAreaInsets: {
|
|
top: DeviceTypes.IS_IPHONE_WITH_INSETS ? 44 : 20,
|
|
left: 0,
|
|
bottom: insetBottom,
|
|
right: 0,
|
|
},
|
|
statusBarHeight: 20,
|
|
};
|
|
}
|
|
|
|
componentDidMount() {
|
|
this.mounted = true;
|
|
|
|
Dimensions.addEventListener('change', this.getSafeAreaInsets);
|
|
EventEmitter.on('update_safe_area_view', this.getSafeAreaInsets);
|
|
if (EphemeralStore.safeAreaInsets[PORTRAIT] === null || EphemeralStore.safeAreaInsets[LANDSCAPE] === null) {
|
|
SafeArea.addEventListener('safeAreaInsetsForRootViewDidChange', this.onSafeAreaInsetsForRootViewChange);
|
|
}
|
|
|
|
this.keyboardDidShowListener = Keyboard.addListener('keyboardWillShow', this.keyboardWillShow);
|
|
this.keyboardDidHideListener = Keyboard.addListener('keyboardWillHide', this.keyboardWillHide);
|
|
|
|
this.getSafeAreaInsets();
|
|
}
|
|
|
|
componentWillUnmount() {
|
|
Dimensions.removeEventListener('change', this.getSafeAreaInsets);
|
|
EventEmitter.off('update_safe_area_view', this.getSafeAreaInsets);
|
|
SafeArea.removeEventListener('safeAreaInsetsForRootViewDidChange', this.onSafeAreaInsetsForRootViewChange);
|
|
this.keyboardDidShowListener.remove();
|
|
this.keyboardDidHideListener.remove();
|
|
|
|
this.mounted = false;
|
|
}
|
|
|
|
getSafeAreaInsets = async (dimensions) => {
|
|
this.getStatusBarHeight();
|
|
|
|
if (DeviceTypes.IS_IPHONE_WITH_INSETS || mattermostManaged.hasSafeAreaInsets) {
|
|
const window = dimensions?.window || Dimensions.get('window');
|
|
const orientation = window.width > window.height ? LANDSCAPE : PORTRAIT;
|
|
const {safeAreaInsets} = await SafeArea.getSafeAreaInsetsForRootView();
|
|
this.setSafeAreaInsets(safeAreaInsets, orientation);
|
|
}
|
|
}
|
|
|
|
setSafeAreaInsets = (safeAreaInsets, orientation) => {
|
|
if (EphemeralStore.safeAreaInsets[orientation] === null) {
|
|
EphemeralStore.safeAreaInsets[orientation] = safeAreaInsets;
|
|
}
|
|
|
|
if (this.mounted) {
|
|
this.setState({
|
|
safeAreaInsets: EphemeralStore.safeAreaInsets[orientation],
|
|
});
|
|
}
|
|
}
|
|
|
|
getStatusBarHeight = () => {
|
|
try {
|
|
StatusBarManager.getHeight(
|
|
(statusBarFrameData) => {
|
|
if (this.mounted) {
|
|
this.setState({statusBarHeight: statusBarFrameData.height});
|
|
}
|
|
},
|
|
);
|
|
} catch (e) {
|
|
// not needed
|
|
}
|
|
};
|
|
|
|
onSafeAreaInsetsForRootViewChange = ({safeAreaInsets}) => {
|
|
if (EphemeralStore.safeAreaInsets[PORTRAIT] !== null && EphemeralStore.safeAreaInsets[LANDSCAPE] !== null) {
|
|
SafeArea.removeEventListener('safeAreaInsetsForRootViewDidChange', this.onSafeAreaInsetsForRootViewChange);
|
|
return;
|
|
}
|
|
|
|
if (DeviceTypes.IS_IPHONE_WITH_INSETS || mattermostManaged.hasSafeAreaInsets) {
|
|
this.getStatusBarHeight();
|
|
|
|
const {width, height} = Dimensions.get('window');
|
|
const orientation = width > height ? LANDSCAPE : PORTRAIT;
|
|
this.setSafeAreaInsets(safeAreaInsets, orientation);
|
|
}
|
|
}
|
|
|
|
keyboardWillHide = () => {
|
|
this.setState({keyboard: false});
|
|
};
|
|
|
|
keyboardWillShow = () => {
|
|
this.setState({keyboard: true});
|
|
};
|
|
|
|
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_WITH_INSETS && !hideTopBar) {
|
|
top = forceTop;
|
|
}
|
|
|
|
if (headerComponent) {
|
|
return (
|
|
<View
|
|
style={{
|
|
backgroundColor: topColor,
|
|
height: top,
|
|
zIndex: 10,
|
|
}}
|
|
>
|
|
{headerComponent}
|
|
</View>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<View
|
|
style={{
|
|
backgroundColor: topColor,
|
|
paddingTop: top,
|
|
zIndex: 10,
|
|
}}
|
|
/>
|
|
);
|
|
};
|
|
|
|
render() {
|
|
const {backgroundColor, children, excludeFooter, footerColor, footerComponent, keyboardOffset, theme, useLandscapeMargin} = 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 && mattermostManaged.hasSafeAreaInsets) {
|
|
offset = keyboardOffset;
|
|
}
|
|
|
|
let bottomInset = safeAreaInsets.bottom;
|
|
if (excludeFooter) {
|
|
bottomInset = 0;
|
|
}
|
|
|
|
return (
|
|
<View
|
|
style={{
|
|
flex: 1,
|
|
backgroundColor: bgColor,
|
|
marginLeft: useLandscapeMargin ? safeAreaInsets.left : 0,
|
|
marginRight: useLandscapeMargin ? safeAreaInsets.right : 0,
|
|
}}
|
|
>
|
|
{this.renderTopBar()}
|
|
{children}
|
|
<View style={{height: keyboard ? offset : bottomInset, backgroundColor: bottomColor}}>
|
|
{footerComponent}
|
|
</View>
|
|
</View>
|
|
);
|
|
}
|
|
}
|