Skip to content

Commit

Permalink
Merge pull request #32335 from margelo/@chrispader/fix-status-bar-saf…
Browse files Browse the repository at this point in the history
…e-area

Fix: New Status bar causes wrong safe area insets
(cherry picked from commit d7366c6)
  • Loading branch information
grgia authored and OSBotify committed Dec 4, 2023
1 parent 92827c2 commit 09dc834
Show file tree
Hide file tree
Showing 17 changed files with 191 additions and 69 deletions.
5 changes: 5 additions & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@ const restrictedImportPaths = [
importNames: ['TouchableOpacity', 'TouchableWithoutFeedback', 'TouchableNativeFeedback', 'TouchableHighlight'],
message: "Please use 'PressableWithFeedback' and/or 'PressableWithoutFeedback' from 'src/components/Pressable' instead.",
},
{
name: 'react-native-safe-area-context',
importNames: ['useSafeAreaInsets', 'SafeAreaConsumer', 'SafeAreaInsetsContext'],
message: "Please use 'useSafeAreaInsets' from 'src/hooks/useSafeAreaInset' and/or 'SafeAreaConsumer' from 'src/components/SafeAreaConsumer' instead.",
},
];

const restrictedImportPatterns = [
Expand Down
6 changes: 3 additions & 3 deletions src/components/CustomStatusBar/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {navigationRef} from '@libs/Navigation/Navigation';
import StatusBar from '@libs/StatusBar';
import useTheme from '@styles/themes/useTheme';
import CustomStatusBarContext from './CustomStatusBarContext';
import updateStatusBarAppearance from './updateStatusBarAppearance';

type CustomStatusBarProps = {
isNested: boolean;
Expand Down Expand Up @@ -60,8 +61,7 @@ const CustomStatusBar: CustomStatusBarType = ({isNested = false}) => {
statusBarStyle = screenTheme.statusBarStyle;
}

StatusBar.setBackgroundColor(currentScreenBackgroundColor, true);
StatusBar.setBarStyle(statusBarStyle, true);
updateStatusBarAppearance({backgroundColor: currentScreenBackgroundColor, statusBarStyle});
}, [isDisabled, theme.PAGE_THEMES, theme.appBG, theme.statusBarStyle]);

useEffect(() => {
Expand All @@ -75,7 +75,7 @@ const CustomStatusBar: CustomStatusBarType = ({isNested = false}) => {
return;
}

StatusBar.setBarStyle(theme.statusBarStyle, true);
updateStatusBarAppearance({statusBarStyle: theme.statusBarStyle});
}, [isDisabled, theme.statusBarStyle]);

if (isDisabled) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import StatusBar from '@libs/StatusBar';
import UpdateStatusBarAppearanceProps from './types';

// eslint-disable-next-line @typescript-eslint/naming-convention
export default function updateStatusBarAppearance({statusBarStyle}: UpdateStatusBarAppearanceProps) {
StatusBar.setBackgroundColor('transparent');
StatusBar.setTranslucent(true);
if (statusBarStyle) {
StatusBar.setBarStyle(statusBarStyle, true);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import StatusBar from '@libs/StatusBar';
import UpdateStatusBarAppearanceProps from './types';

// eslint-disable-next-line @typescript-eslint/naming-convention
export default function updateStatusBarAppearance({statusBarStyle}: UpdateStatusBarAppearanceProps) {
if (!statusBarStyle) {
return;
}
StatusBar.setBarStyle(statusBarStyle, true);
}
11 changes: 11 additions & 0 deletions src/components/CustomStatusBar/updateStatusBarAppearance/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import StatusBar from '@libs/StatusBar';
import UpdateStatusBarAppearanceProps from './types';

export default function updateStatusBarAppearance({backgroundColor, statusBarStyle}: UpdateStatusBarAppearanceProps) {
if (backgroundColor) {
StatusBar.setBackgroundColor(backgroundColor, true);
}
if (statusBarStyle) {
StatusBar.setBarStyle(statusBarStyle, true);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import {StatusBarStyle} from '@styles/styles';

type UpdateStatusBarAppearanceProps = {
backgroundColor?: string;
statusBarStyle?: StatusBarStyle;
};

export default UpdateStatusBarAppearanceProps;
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React from 'react';
import {Animated} from 'react-native';
import {SafeAreaInsetsContext} from 'react-native-safe-area-context';
import useSafeAreaInsets from '@hooks/useSafeAreaInsets';
import * as StyleUtils from '@styles/StyleUtils';
import useThemeStyles from '@styles/useThemeStyles';
import growlNotificationContainerPropTypes from './growlNotificationContainerPropTypes';
Expand All @@ -11,14 +11,12 @@ const propTypes = {

function GrowlNotificationContainer(props) {
const styles = useThemeStyles();
const insets = useSafeAreaInsets;

return (
<SafeAreaInsetsContext.Consumer>
{(insets) => (
<Animated.View style={[StyleUtils.getSafeAreaPadding(insets), styles.growlNotificationContainer, styles.growlNotificationTranslateY(props.translateY)]}>
{props.children}
</Animated.View>
)}
</SafeAreaInsetsContext.Consumer>
<Animated.View style={[StyleUtils.getSafeAreaPadding(insets), styles.growlNotificationContainer, styles.growlNotificationTranslateY(props.translateY)]}>
{props.children}
</Animated.View>
);
}

Expand Down
2 changes: 1 addition & 1 deletion src/components/Modal/BaseModal.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import React, {forwardRef, useCallback, useEffect, useMemo, useRef} from 'react';
import {View} from 'react-native';
import ReactNativeModal from 'react-native-modal';
import {useSafeAreaInsets} from 'react-native-safe-area-context';
import usePrevious from '@hooks/usePrevious';
import useSafeAreaInsets from '@hooks/useSafeAreaInsets';
import useWindowDimensions from '@hooks/useWindowDimensions';
import ComposerFocusManager from '@libs/ComposerFocusManager';
import useNativeDriver from '@libs/useNativeDriver';
Expand Down
92 changes: 53 additions & 39 deletions src/components/PopoverWithoutOverlay/index.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import React from 'react';
import React, {useMemo} from 'react';
import {View} from 'react-native';
import {SafeAreaInsetsContext} from 'react-native-safe-area-context';
import {defaultProps, propTypes} from '@components/Popover/popoverPropTypes';
import {PopoverContext} from '@components/PopoverProvider';
import withWindowDimensions from '@components/withWindowDimensions';
import useSafeAreaInsets from '@hooks/useSafeAreaInsets';
import getModalStyles from '@styles/getModalStyles';
import * as StyleUtils from '@styles/StyleUtils';
import useTheme from '@styles/themes/useTheme';
Expand All @@ -14,6 +14,7 @@ function Popover(props) {
const theme = useTheme();
const styles = useThemeStyles();
const {onOpen, close} = React.useContext(PopoverContext);
const insets = useSafeAreaInsets();
const {modalStyle, modalContainerStyle, shouldAddTopSafeAreaMargin, shouldAddBottomSafeAreaMargin, shouldAddTopSafeAreaPadding, shouldAddBottomSafeAreaPadding} = getModalStyles(
'popover',
{
Expand All @@ -28,6 +29,47 @@ function Popover(props) {
props.outerStyle,
);

const {
paddingTop: safeAreaPaddingTop,
paddingBottom: safeAreaPaddingBottom,
paddingLeft: safeAreaPaddingLeft,
paddingRight: safeAreaPaddingRight,
} = useMemo(() => StyleUtils.getSafeAreaPadding(insets), [insets]);

const modalPaddingStyles = useMemo(
() =>
StyleUtils.getModalPaddingStyles({
safeAreaPaddingTop,
safeAreaPaddingBottom,
safeAreaPaddingLeft,
safeAreaPaddingRight,
shouldAddBottomSafeAreaMargin,
shouldAddTopSafeAreaMargin,
shouldAddBottomSafeAreaPadding,
shouldAddTopSafeAreaPadding,
modalContainerStyleMarginTop: modalContainerStyle.marginTop,
modalContainerStyleMarginBottom: modalContainerStyle.marginBottom,
modalContainerStylePaddingTop: modalContainerStyle.paddingTop,
modalContainerStylePaddingBottom: modalContainerStyle.paddingBottom,
insets,
}),
[
insets,
modalContainerStyle.marginBottom,
modalContainerStyle.marginTop,
modalContainerStyle.paddingBottom,
modalContainerStyle.paddingTop,
safeAreaPaddingBottom,
safeAreaPaddingLeft,
safeAreaPaddingRight,
safeAreaPaddingTop,
shouldAddBottomSafeAreaMargin,
shouldAddBottomSafeAreaPadding,
shouldAddTopSafeAreaMargin,
shouldAddTopSafeAreaPadding,
],
);

React.useEffect(() => {
let removeOnClose;
if (props.isVisible) {
Expand Down Expand Up @@ -64,44 +106,16 @@ function Popover(props) {
style={[modalStyle, {zIndex: 1}]}
ref={props.withoutOverlayRef}
>
<SafeAreaInsetsContext.Consumer>
{(insets) => {
const {
paddingTop: safeAreaPaddingTop,
paddingBottom: safeAreaPaddingBottom,
paddingLeft: safeAreaPaddingLeft,
paddingRight: safeAreaPaddingRight,
} = StyleUtils.getSafeAreaPadding(insets);

const modalPaddingStyles = StyleUtils.getModalPaddingStyles({
safeAreaPaddingTop,
safeAreaPaddingBottom,
safeAreaPaddingLeft,
safeAreaPaddingRight,
shouldAddBottomSafeAreaMargin,
shouldAddTopSafeAreaMargin,
shouldAddBottomSafeAreaPadding,
shouldAddTopSafeAreaPadding,
modalContainerStyleMarginTop: modalContainerStyle.marginTop,
modalContainerStyleMarginBottom: modalContainerStyle.marginBottom,
modalContainerStylePaddingTop: modalContainerStyle.paddingTop,
modalContainerStylePaddingBottom: modalContainerStyle.paddingBottom,
insets,
});
return (
<View
style={{
...styles.defaultModalContainer,
...modalContainerStyle,
...modalPaddingStyles,
}}
ref={props.forwardedRef}
>
{props.children}
</View>
);
<View
style={{
...styles.defaultModalContainer,
...modalContainerStyle,
...modalPaddingStyles,
}}
</SafeAreaInsetsContext.Consumer>
ref={props.forwardedRef}
>
{props.children}
</View>
</View>
);
}
Expand Down
42 changes: 42 additions & 0 deletions src/components/SafeAreaConsumer/index.android.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import React from 'react';
// eslint-disable-next-line no-restricted-imports
import {SafeAreaInsetsContext} from 'react-native-safe-area-context';
import StatusBar from '@libs/StatusBar';
import * as StyleUtils from '@styles/StyleUtils';
import SafeAreaConsumerProps from './types';

/**
* This component is a light wrapper around the SafeAreaInsetsContext.Consumer. There are several places where we
* may need not just the insets, but the computed styles so we save a few lines of code with this.
*/
function SafeAreaConsumer({children}: SafeAreaConsumerProps) {
return (
<SafeAreaInsetsContext.Consumer>
{(insets) => {
const insetsWithDefault = insets ?? {
top: 0,
bottom: 0,
left: 0,
right: 0,
};

const androidInsets = {
...insetsWithDefault,
top: StatusBar.currentHeight ?? insetsWithDefault.top,
};

const {paddingTop, paddingBottom} = StyleUtils.getSafeAreaPadding(androidInsets ?? undefined);
return children({
paddingTop,
paddingBottom,
insets: androidInsets ?? undefined,
safeAreaPaddingBottomStyle: {paddingBottom},
});
}}
</SafeAreaInsetsContext.Consumer>
);
}

SafeAreaConsumer.displayName = 'SafeAreaConsumer';

export default SafeAreaConsumer;
Original file line number Diff line number Diff line change
@@ -1,20 +1,8 @@
import React from 'react';
import type {DimensionValue} from 'react-native';
import {EdgeInsets, SafeAreaInsetsContext} from 'react-native-safe-area-context';
// eslint-disable-next-line no-restricted-imports
import {SafeAreaInsetsContext} from 'react-native-safe-area-context';
import * as StyleUtils from '@styles/StyleUtils';

type ChildrenProps = {
paddingTop?: DimensionValue;
paddingBottom?: DimensionValue;
insets?: EdgeInsets;
safeAreaPaddingBottomStyle: {
paddingBottom?: DimensionValue;
};
};

type SafeAreaConsumerProps = {
children: React.FC<ChildrenProps>;
};
import SafeAreaConsumerProps from './types';

/**
* This component is a light wrapper around the SafeAreaInsetsContext.Consumer. There are several places where we
Expand Down
17 changes: 17 additions & 0 deletions src/components/SafeAreaConsumer/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import {DimensionValue} from 'react-native';
import {EdgeInsets} from 'react-native-safe-area-context';

type ChildrenProps = {
paddingTop?: DimensionValue;
paddingBottom?: DimensionValue;
insets?: EdgeInsets;
safeAreaPaddingBottomStyle: {
paddingBottom?: DimensionValue;
};
};

type SafeAreaConsumerProps = {
children: React.FC<ChildrenProps>;
};

export default SafeAreaConsumerProps;
2 changes: 1 addition & 1 deletion src/components/withWindowDimensions/index.native.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import PropTypes from 'prop-types';
import React, {ComponentType, createContext, ForwardedRef, RefAttributes, useEffect, useMemo, useState} from 'react';
import {Dimensions} from 'react-native';
import {useSafeAreaInsets} from 'react-native-safe-area-context';
import useSafeAreaInsets from '@hooks/useSafeAreaInsets';
import getComponentDisplayName from '@libs/getComponentDisplayName';
import getWindowHeightAdjustment from '@libs/getWindowHeightAdjustment';
import variables from '@styles/variables';
Expand Down
2 changes: 1 addition & 1 deletion src/components/withWindowDimensions/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import lodashDebounce from 'lodash/debounce';
import PropTypes from 'prop-types';
import React, {ComponentType, createContext, ForwardedRef, RefAttributes, useEffect, useMemo, useState} from 'react';
import {Dimensions} from 'react-native';
import {useSafeAreaInsets} from 'react-native-safe-area-context';
import useSafeAreaInsets from '@hooks/useSafeAreaInsets';
import getComponentDisplayName from '@libs/getComponentDisplayName';
import getWindowHeightAdjustment from '@libs/getWindowHeightAdjustment';
import variables from '@styles/variables';
Expand Down
14 changes: 14 additions & 0 deletions src/hooks/useSafeAreaInsets/index.android.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// eslint-disable-next-line no-restricted-imports
import {EdgeInsets, useSafeAreaInsets as useSafeAreaInsetsInternal} from 'react-native-safe-area-context';
import StatusBar from '@libs/StatusBar';

function useSafeAreaInsets(): EdgeInsets {
const insets = useSafeAreaInsetsInternal();

return {
...insets,
top: StatusBar.currentHeight ?? insets.top,
};
}

export default useSafeAreaInsets;
4 changes: 4 additions & 0 deletions src/hooks/useSafeAreaInsets/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
/* eslint-disable no-restricted-imports */
import {useSafeAreaInsets} from 'react-native-safe-area-context';

export default useSafeAreaInsets;
2 changes: 1 addition & 1 deletion src/pages/signin/SignInPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ import PropTypes from 'prop-types';
import React, {useEffect, useRef, useState} from 'react';
import {View} from 'react-native';
import {withOnyx} from 'react-native-onyx';
import {useSafeAreaInsets} from 'react-native-safe-area-context';
import _ from 'underscore';
import ColorSchemeWrapper from '@components/ColorSchemeWrapper';
import CustomStatusBar from '@components/CustomStatusBar';
import useLocalize from '@hooks/useLocalize';
import useSafeAreaInsets from '@hooks/useSafeAreaInsets';
import useWindowDimensions from '@hooks/useWindowDimensions';
import * as ActiveClientManager from '@libs/ActiveClientManager';
import getPlatform from '@libs/getPlatform';
Expand Down

0 comments on commit 09dc834

Please sign in to comment.