Skip to content

Commit

Permalink
Merge pull request #32672 from margelo/@chrispader/fix-wrong-status-b…
Browse files Browse the repository at this point in the history
…ar-colors

Fix issues with scrollbar and status bar color

(cherry picked from commit b4d1777)
  • Loading branch information
grgia authored and OSBotify committed Dec 15, 2023
1 parent 43029bd commit b4e59cb
Show file tree
Hide file tree
Showing 17 changed files with 184 additions and 125 deletions.
8 changes: 4 additions & 4 deletions src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ import {SafeAreaProvider} from 'react-native-safe-area-context';
import '../wdyr';
import ColorSchemeWrapper from './components/ColorSchemeWrapper';
import ComposeProviders from './components/ComposeProviders';
import CustomStatusBar from './components/CustomStatusBar';
import CustomStatusBarContextProvider from './components/CustomStatusBar/CustomStatusBarContextProvider';
import CustomStatusBarAndBackground from './components/CustomStatusBarAndBackground';
import CustomStatusBarAndBackgroundContextProvider from './components/CustomStatusBarAndBackground/CustomStatusBarAndBackgroundContextProvider';
import ErrorBoundary from './components/ErrorBoundary';
import HTMLEngineProvider from './components/HTMLEngineProvider';
import {LocaleContextProvider} from './components/LocaleContextProvider';
Expand Down Expand Up @@ -68,10 +68,10 @@ function App() {
ReportAttachmentsProvider,
PickerStateProvider,
EnvironmentProvider,
CustomStatusBarContextProvider,
CustomStatusBarAndBackgroundContextProvider,
]}
>
<CustomStatusBar />
<CustomStatusBarAndBackground />
<ErrorBoundary errorMessage="NewExpensify crash caught by error boundary">
<ColorSchemeWrapper>
<Expensify />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {View} from 'react-native';
// We take ScrollView from this package to properly handle the scrolling of AutoCompleteSuggestions in chats since one scroll is nested inside another
import {ScrollView} from 'react-native-gesture-handler';
import Animated, {Easing, FadeOutDown, useAnimatedStyle, useSharedValue, withTiming} from 'react-native-reanimated';
import ColorSchemeWrapper from '@components/ColorSchemeWrapper';
import PressableWithFeedback from '@components/Pressable/PressableWithFeedback';
import useStyleUtils from '@hooks/useStyleUtils';
import useThemeStyles from '@hooks/useThemeStyles';
Expand Down Expand Up @@ -84,18 +85,20 @@ function BaseAutoCompleteSuggestions<TSuggestion>(
style={[styles.autoCompleteSuggestionsContainer, animatedStyles]}
exiting={FadeOutDown.duration(100).easing(Easing.inOut(Easing.ease))}
>
<FlashList
estimatedItemSize={CONST.AUTO_COMPLETE_SUGGESTER.SUGGESTION_ROW_HEIGHT}
ref={scrollRef}
keyboardShouldPersistTaps="handled"
data={suggestions}
renderItem={renderItem}
renderScrollComponent={ScrollView}
keyExtractor={keyExtractor}
removeClippedSubviews={false}
showsVerticalScrollIndicator={innerHeight > rowHeight.value}
extraData={highlightedSuggestionIndex}
/>
<ColorSchemeWrapper>
<FlashList
estimatedItemSize={CONST.AUTO_COMPLETE_SUGGESTER.SUGGESTION_ROW_HEIGHT}
ref={scrollRef}
keyboardShouldPersistTaps="handled"
data={suggestions}
renderItem={renderItem}
renderScrollComponent={ScrollView}
keyExtractor={keyExtractor}
removeClippedSubviews={false}
showsVerticalScrollIndicator={innerHeight > rowHeight.value}
extraData={highlightedSuggestionIndex}
/>
</ColorSchemeWrapper>
</Animated.View>
);
}
Expand Down
11 changes: 0 additions & 11 deletions src/components/CustomStatusBar/CustomStatusBarContext.tsx

This file was deleted.

17 changes: 0 additions & 17 deletions src/components/CustomStatusBar/CustomStatusBarContextProvider.tsx

This file was deleted.

79 changes: 0 additions & 79 deletions src/components/CustomStatusBar/index.tsx

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import {createContext} from 'react';

type CustomStatusBarAndBackgroundContextType = {
isRootStatusBarDisabled: boolean;
disableRootStatusBar: (isDisabled: boolean) => void;
};

const CustomStatusBarAndBackgroundContext = createContext<CustomStatusBarAndBackgroundContextType>({isRootStatusBarDisabled: false, disableRootStatusBar: () => undefined});

export default CustomStatusBarAndBackgroundContext;
export {type CustomStatusBarAndBackgroundContextType};
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import React, {useMemo, useState} from 'react';
import CustomStatusBarAndBackgroundContext from './CustomStatusBarAndBackgroundContext';

function CustomStatusBarAndBackgroundContextProvider({children}: React.PropsWithChildren) {
const [isRootStatusBarDisabled, disableRootStatusBar] = useState(false);
const value = useMemo(
() => ({
isRootStatusBarDisabled,
disableRootStatusBar,
}),
[isRootStatusBarDisabled],
);

return <CustomStatusBarAndBackgroundContext.Provider value={value}>{children}</CustomStatusBarAndBackgroundContext.Provider>;
}

export default CustomStatusBarAndBackgroundContextProvider;
113 changes: 113 additions & 0 deletions src/components/CustomStatusBarAndBackground/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import React, {useCallback, useContext, useEffect, useRef, useState} from 'react';
import useTheme from '@hooks/useTheme';
import {navigationRef} from '@libs/Navigation/Navigation';
import StatusBar from '@libs/StatusBar';
import CustomStatusBarAndBackgroundContext from './CustomStatusBarAndBackgroundContext';
import updateGlobalBackgroundColor from './updateGlobalBackgroundColor';
import updateStatusBarAppearance from './updateStatusBarAppearance';

type CustomStatusBarAndBackgroundProps = {
/** Whether the CustomStatusBar is nested within another CustomStatusBar.
* A nested CustomStatusBar will disable the "root" CustomStatusBar. */
isNested: boolean;
};

function CustomStatusBarAndBackground({isNested = false}: CustomStatusBarAndBackgroundProps) {
const {isRootStatusBarDisabled, disableRootStatusBar} = useContext(CustomStatusBarAndBackgroundContext);
const theme = useTheme();
const [statusBarStyle, setStatusBarStyle] = useState(theme.statusBarStyle);

const isDisabled = !isNested && isRootStatusBarDisabled;

// Disable the root status bar when a nested status bar is rendered
useEffect(() => {
if (isNested) {
disableRootStatusBar(true);
}

return () => {
if (!isNested) {
return;
}
disableRootStatusBar(false);
};
}, [disableRootStatusBar, isNested]);

const listenerCount = useRef(0);
const updateStatusBarStyle = useCallback(
(listenerId?: number) => {
// Check if this function is either called through the current navigation listener or the general useEffect which listens for theme changes.
if (listenerId !== undefined && listenerId !== listenerCount.current) {
return;
}

// Set the status bar colour depending on the current route.
// If we don't have any colour defined for a route, fall back to
// appBG color.
let currentRoute: ReturnType<typeof navigationRef.getCurrentRoute> | undefined;
if (navigationRef.isReady()) {
currentRoute = navigationRef.getCurrentRoute();
}

let currentScreenBackgroundColor = theme.appBG;
let newStatusBarStyle = theme.statusBarStyle;
if (currentRoute && 'name' in currentRoute && currentRoute.name in theme.PAGE_THEMES) {
const screenTheme = theme.PAGE_THEMES[currentRoute.name];
currentScreenBackgroundColor = screenTheme.backgroundColor;
newStatusBarStyle = screenTheme.statusBarStyle;
}

// Don't update the status bar style if it's the same as the current one, to prevent flashing.
if (newStatusBarStyle === statusBarStyle) {
updateStatusBarAppearance({backgroundColor: currentScreenBackgroundColor});
} else {
updateStatusBarAppearance({backgroundColor: currentScreenBackgroundColor, statusBarStyle: newStatusBarStyle});
setStatusBarStyle(newStatusBarStyle);
}
},
[statusBarStyle, theme.PAGE_THEMES, theme.appBG, theme.statusBarStyle],
);

// Add navigation state listeners to update the status bar every time the route changes
// We have to pass a count as the listener id, because "react-navigation" somehow doesn't remove listeners properyl
useEffect(() => {
if (isDisabled) {
return;
}

const listenerId = ++listenerCount.current;
const listener = () => updateStatusBarStyle(listenerId);

navigationRef.addListener('state', listener);
return () => navigationRef.removeListener('state', listener);
}, [isDisabled, theme.appBG, updateStatusBarStyle]);

// Update the status bar style everytime the theme changes
useEffect(() => {
if (isDisabled) {
return;
}

updateStatusBarStyle();
}, [isDisabled, theme, updateStatusBarStyle]);

// Update the global background (on web) everytime the theme changes.
// The background of the html element needs to be updated, otherwise you will see a big contrast when resizing the window or when the keyboard is open on iOS web.
useEffect(() => {
if (isDisabled) {
return;
}

updateGlobalBackgroundColor(theme);
}, [isDisabled, theme]);

if (isDisabled) {
return null;
}

return <StatusBar />;
}

CustomStatusBarAndBackground.displayName = 'CustomStatusBarAndBackground';

export default CustomStatusBarAndBackground;
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import type UpdateGlobalBackgroundColor from './types';

const updateGlobalBackgroundColor: UpdateGlobalBackgroundColor = () => undefined;

export default updateGlobalBackgroundColor;
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import UpdateGlobalBackgroundColor from './types';

const updateGlobalBackgroundColor: UpdateGlobalBackgroundColor = (theme) => {
const htmlElement = document.getElementsByTagName('html')[0];
htmlElement.style.setProperty('background-color', theme.appBG);
};

export default updateGlobalBackgroundColor;
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import {ThemeColors} from '@styles/theme/types';

type UpdateGlobalBackgroundColor = (theme: ThemeColors) => void;

export default UpdateGlobalBackgroundColor;
4 changes: 4 additions & 0 deletions src/components/RNTextInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,20 @@ import React, {ForwardedRef} from 'react';
// eslint-disable-next-line no-restricted-imports
import {TextInput, TextInputProps} from 'react-native';
import Animated, {AnimatedProps} from 'react-native-reanimated';
import useTheme from '@hooks/useTheme';

// Convert the underlying TextInput into an Animated component so that we can take an animated ref and pass it to a worklet
const AnimatedTextInput = Animated.createAnimatedComponent(TextInput);

// eslint-disable-next-line @typescript-eslint/no-explicit-any
function RNTextInputWithRef(props: TextInputProps, ref: ForwardedRef<React.Component<AnimatedProps<TextInputProps>>>) {
const theme = useTheme();

return (
<AnimatedTextInput
allowFontScaling={false}
textBreakStrategy="simple"
keyboardAppearance={theme.colorScheme}
ref={(refHandle) => {
if (typeof ref !== 'function') {
return;
Expand Down
4 changes: 2 additions & 2 deletions src/pages/signin/SignInPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {View} from 'react-native';
import {withOnyx} from 'react-native-onyx';
import _ from 'underscore';
import ColorSchemeWrapper from '@components/ColorSchemeWrapper';
import CustomStatusBar from '@components/CustomStatusBar';
import CustomStatusBarAndBackground from '@components/CustomStatusBarAndBackground';
import ThemeProvider from '@components/ThemeProvider';
import ThemeStylesProvider from '@components/ThemeStylesProvider';
import useLocalize from '@hooks/useLocalize';
Expand Down Expand Up @@ -288,7 +288,7 @@ function SignInPage(props) {
<ThemeProvider theme={CONST.THEME.DARK}>
<ThemeStylesProvider>
<ColorSchemeWrapper>
<CustomStatusBar isNested />
<CustomStatusBarAndBackground isNested />
<SignInPageInner
// eslint-disable-next-line react/jsx-props-no-spreading
{...props}
Expand Down

0 comments on commit b4e59cb

Please sign in to comment.