diff --git a/.imgbotconfig b/.imgbotconfig
index ff5c3345cc4d..43d1b77166cc 100644
--- a/.imgbotconfig
+++ b/.imgbotconfig
@@ -1,6 +1,7 @@
{
"ignoredFiles": [
- "assets/images/empty-state_background-fade.png" // Caused an issue with colour gradients, https://github.com/Expensify/App/issues/30499
+ "assets/images/empty-state_background-fade-dark.png", // Caused an issue with colour gradients, https://github.com/Expensify/App/issues/30499
+ "assets/images/empty-state_background-fade-light.png"
],
"aggressiveCompression": "false"
}
diff --git a/src/App.js b/src/App.js
index ac34ece5c6c7..2caa6b9ffc29 100644
--- a/src/App.js
+++ b/src/App.js
@@ -6,8 +6,10 @@ import Onyx from 'react-native-onyx';
import {PickerStateProvider} from 'react-native-picker-select';
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 ErrorBoundary from './components/ErrorBoundary';
import HTMLEngineProvider from './components/HTMLEngineProvider';
import {LocaleContextProvider} from './components/LocaleContextProvider';
@@ -66,11 +68,14 @@ function App() {
ThemeProvider,
ThemeStylesProvider,
ThemeIllustrationsProvider,
+ CustomStatusBarContextProvider,
]}
>
-
+
+
+
diff --git a/src/CONST.ts b/src/CONST.ts
index 8d928df71ef0..d813d3e016c2 100755
--- a/src/CONST.ts
+++ b/src/CONST.ts
@@ -699,6 +699,14 @@ const CONST = {
DARK: 'dark',
SYSTEM: 'system',
},
+ COLOR_SCHEME: {
+ LIGHT: 'light',
+ DARK: 'dark',
+ },
+ STATUS_BAR_STYLE: {
+ LIGHT_CONTENT: 'light-content',
+ DARK_CONTENT: 'dark-content',
+ },
TRANSACTION: {
DEFAULT_MERCHANT: 'Request',
UNKNOWN_MERCHANT: 'Unknown Merchant',
diff --git a/src/components/ColorSchemeWrapper/index.native.tsx b/src/components/ColorSchemeWrapper/index.native.tsx
new file mode 100644
index 000000000000..9f68ee97d330
--- /dev/null
+++ b/src/components/ColorSchemeWrapper/index.native.tsx
@@ -0,0 +1,5 @@
+function ColorSchemeWrapper({children}: React.PropsWithChildren) {
+ return children;
+}
+
+export default ColorSchemeWrapper;
diff --git a/src/components/ColorSchemeWrapper/index.tsx b/src/components/ColorSchemeWrapper/index.tsx
new file mode 100644
index 000000000000..577ccf9f3794
--- /dev/null
+++ b/src/components/ColorSchemeWrapper/index.tsx
@@ -0,0 +1,13 @@
+import React from 'react';
+import {View} from 'react-native';
+import useTheme from '@styles/themes/useTheme';
+import useThemeStyles from '@styles/useThemeStyles';
+
+function ColorSchemeWrapper({children}: React.PropsWithChildren): React.ReactElement {
+ const theme = useTheme();
+ const themeStyles = useThemeStyles();
+
+ return {children};
+}
+
+export default ColorSchemeWrapper;
diff --git a/src/components/CustomStatusBar/CustomStatusBarContext.tsx b/src/components/CustomStatusBar/CustomStatusBarContext.tsx
new file mode 100644
index 000000000000..b2c317b05c25
--- /dev/null
+++ b/src/components/CustomStatusBar/CustomStatusBarContext.tsx
@@ -0,0 +1,11 @@
+import {createContext} from 'react';
+
+type CustomStatusBarContextType = {
+ isRootStatusBarDisabled: boolean;
+ disableRootStatusBar: (isDisabled: boolean) => void;
+};
+
+const CustomStatusBarContext = createContext({isRootStatusBarDisabled: false, disableRootStatusBar: () => undefined});
+
+export default CustomStatusBarContext;
+export {type CustomStatusBarContextType};
diff --git a/src/components/CustomStatusBar/CustomStatusBarContextProvider.tsx b/src/components/CustomStatusBar/CustomStatusBarContextProvider.tsx
new file mode 100644
index 000000000000..27a5cac5d8cc
--- /dev/null
+++ b/src/components/CustomStatusBar/CustomStatusBarContextProvider.tsx
@@ -0,0 +1,17 @@
+import React, {useMemo, useState} from 'react';
+import CustomStatusBarContext from './CustomStatusBarContext';
+
+function CustomStatusBarContextProvider({children}: React.PropsWithChildren) {
+ const [isRootStatusBarDisabled, disableRootStatusBar] = useState(false);
+ const value = useMemo(
+ () => ({
+ isRootStatusBarDisabled,
+ disableRootStatusBar,
+ }),
+ [isRootStatusBarDisabled],
+ );
+
+ return {children};
+}
+
+export default CustomStatusBarContextProvider;
diff --git a/src/components/CustomStatusBar/index.android.tsx b/src/components/CustomStatusBar/index.android.tsx
deleted file mode 100644
index 81b4f1d25f67..000000000000
--- a/src/components/CustomStatusBar/index.android.tsx
+++ /dev/null
@@ -1,15 +0,0 @@
-/**
- * On Android we setup the status bar in native code.
- */
-import type CustomStatusBarType from './types';
-
-// eslint-disable-next-line react/function-component-definition
-const CustomStatusBar: CustomStatusBarType = () =>
- // Prefer to not render the StatusBar component in Android as it can cause
- // issues with edge to edge display. We setup the status bar appearance in
- // MainActivity.java and styles.xml.
- null;
-
-CustomStatusBar.displayName = 'CustomStatusBar';
-
-export default CustomStatusBar;
diff --git a/src/components/CustomStatusBar/index.tsx b/src/components/CustomStatusBar/index.tsx
index c5c013c2bef9..2e4994378264 100644
--- a/src/components/CustomStatusBar/index.tsx
+++ b/src/components/CustomStatusBar/index.tsx
@@ -1,29 +1,91 @@
-import React, {useEffect} from 'react';
-import Navigation, {navigationRef} from '@libs/Navigation/Navigation';
+import {EventListenerCallback, NavigationContainerEventMap} from '@react-navigation/native';
+import PropTypes from 'prop-types';
+import React, {useCallback, useContext, useEffect} from 'react';
+import {navigationRef} from '@libs/Navigation/Navigation';
import StatusBar from '@libs/StatusBar';
import useTheme from '@styles/themes/useTheme';
-import type CustomStatusBarType from './types';
+import CustomStatusBarContext from './CustomStatusBarContext';
+
+type CustomStatusBarProps = {
+ isNested: boolean;
+};
+
+const propTypes = {
+ /** Whether the CustomStatusBar is nested within another CustomStatusBar.
+ * A nested CustomStatusBar will disable the "root" CustomStatusBar. */
+ isNested: PropTypes.bool,
+};
+
+type CustomStatusBarType = {
+ (props: CustomStatusBarProps): React.ReactNode;
+ displayName: string;
+ propTypes: typeof propTypes;
+};
// eslint-disable-next-line react/function-component-definition
-const CustomStatusBar: CustomStatusBarType = () => {
+const CustomStatusBar: CustomStatusBarType = ({isNested = false}) => {
+ const {isRootStatusBarDisabled, disableRootStatusBar} = useContext(CustomStatusBarContext);
const theme = useTheme();
+
+ const isDisabled = !isNested && isRootStatusBarDisabled;
+
useEffect(() => {
- Navigation.isNavigationReady().then(() => {
- // 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.
- const currentRoute = navigationRef.getCurrentRoute();
- let currentScreenBackgroundColor = theme.appBG;
- if (currentRoute && 'name' in currentRoute && currentRoute.name in theme.PAGE_BACKGROUND_COLORS) {
- currentScreenBackgroundColor = theme.PAGE_BACKGROUND_COLORS[currentRoute.name];
+ if (isNested) {
+ disableRootStatusBar(true);
+ }
+
+ return () => {
+ if (!isNested) {
+ return;
}
- StatusBar.setBarStyle('light-content', true);
- StatusBar.setBackgroundColor(currentScreenBackgroundColor);
- });
- }, [theme.PAGE_BACKGROUND_COLORS, theme.appBG]);
+ disableRootStatusBar(false);
+ };
+ }, [disableRootStatusBar, isNested]);
+
+ const updateStatusBarStyle = useCallback>(() => {
+ if (isDisabled) {
+ 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.
+ const currentRoute = navigationRef.getCurrentRoute();
+
+ let currentScreenBackgroundColor = theme.appBG;
+ let statusBarStyle = theme.statusBarStyle;
+ if (currentRoute && 'name' in currentRoute && currentRoute.name in theme.PAGE_THEMES) {
+ const screenTheme = theme.PAGE_THEMES[currentRoute.name];
+ currentScreenBackgroundColor = screenTheme.backgroundColor;
+ statusBarStyle = screenTheme.statusBarStyle;
+ }
+
+ StatusBar.setBackgroundColor(currentScreenBackgroundColor, true);
+ StatusBar.setBarStyle(statusBarStyle, true);
+ }, [isDisabled, theme.PAGE_THEMES, theme.appBG, theme.statusBarStyle]);
+
+ useEffect(() => {
+ navigationRef.addListener('state', updateStatusBarStyle);
+
+ return () => navigationRef.removeListener('state', updateStatusBarStyle);
+ }, [updateStatusBarStyle]);
+
+ useEffect(() => {
+ if (isDisabled) {
+ return;
+ }
+
+ StatusBar.setBarStyle(theme.statusBarStyle, true);
+ }, [isDisabled, theme.statusBarStyle]);
+
+ if (isDisabled) {
+ return null;
+ }
+
return ;
};
CustomStatusBar.displayName = 'CustomStatusBar';
+CustomStatusBar.propTypes = propTypes;
export default CustomStatusBar;
diff --git a/src/components/CustomStatusBar/types.ts b/src/components/CustomStatusBar/types.ts
deleted file mode 100644
index 7fecd02beba0..000000000000
--- a/src/components/CustomStatusBar/types.ts
+++ /dev/null
@@ -1,6 +0,0 @@
-type CustomStatusBar = {
- (): React.ReactNode;
- displayName: string;
-};
-
-export default CustomStatusBar;
diff --git a/src/libs/Navigation/NavigationRoot.tsx b/src/libs/Navigation/NavigationRoot.tsx
index cbb2e62161f3..7c0b9ef4fc8c 100644
--- a/src/libs/Navigation/NavigationRoot.tsx
+++ b/src/libs/Navigation/NavigationRoot.tsx
@@ -1,12 +1,9 @@
import {DefaultTheme, getPathFromState, NavigationContainer, NavigationState} from '@react-navigation/native';
import React, {useEffect, useMemo, useRef} from 'react';
-import {ColorValue} from 'react-native';
-import {interpolateColor, runOnJS, useAnimatedReaction, useSharedValue, withDelay, withTiming} from 'react-native-reanimated';
import useCurrentReportID from '@hooks/useCurrentReportID';
import useFlipper from '@hooks/useFlipper';
import useWindowDimensions from '@hooks/useWindowDimensions';
import Log from '@libs/Log';
-import StatusBar from '@libs/StatusBar';
import useTheme from '@styles/themes/useTheme';
import AppNavigator from './AppNavigator';
import linkingConfig from './linkingConfig';
@@ -42,8 +39,8 @@ function parseAndLogRoute(state: NavigationState) {
function NavigationRoot({authenticated, onReady}: NavigationRootProps) {
useFlipper(navigationRef);
- const theme = useTheme();
const firstRenderRef = useRef(true);
+ const theme = useTheme();
const currentReportIDValue = useCurrentReportID();
const {isSmallScreenWidth} = useWindowDimensions();
@@ -82,46 +79,6 @@ function NavigationRoot({authenticated, onReady}: NavigationRootProps) {
navigationRef.resetRoot(navigationRef.getRootState());
}, [isSmallScreenWidth, authenticated]);
- const prevStatusBarBackgroundColor = useRef(theme.appBG);
- const statusBarBackgroundColor = useRef(theme.appBG);
- const statusBarAnimation = useSharedValue(0);
-
- const updateStatusBarBackgroundColor = (color: ColorValue) => StatusBar.setBackgroundColor(color);
- useAnimatedReaction(
- () => statusBarAnimation.value,
- (current, previous) => {
- // Do not run if either of the animated value is null
- // or previous animated value is greater than or equal to the current one
- if (previous === null || current === null || current <= previous) {
- return;
- }
- const color = interpolateColor(statusBarAnimation.value, [0, 1], [prevStatusBarBackgroundColor.current, statusBarBackgroundColor.current]);
- runOnJS(updateStatusBarBackgroundColor)(color);
- },
- );
-
- const animateStatusBarBackgroundColor = () => {
- const currentRoute = navigationRef.getCurrentRoute();
-
- const backgroundColorFromRoute =
- currentRoute?.params && 'backgroundColor' in currentRoute.params && typeof currentRoute.params.backgroundColor === 'string' && currentRoute.params.backgroundColor;
- const backgroundColorFallback = currentRoute?.name ? theme.PAGE_BACKGROUND_COLORS[currentRoute.name] || theme.appBG : theme.appBG;
-
- // It's possible for backgroundColorFromRoute to be empty string, so we must use "||" to fallback to backgroundColorFallback.
- // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
- const currentScreenBackgroundColor = backgroundColorFromRoute || backgroundColorFallback;
-
- prevStatusBarBackgroundColor.current = statusBarBackgroundColor.current;
- statusBarBackgroundColor.current = currentScreenBackgroundColor;
-
- if (currentScreenBackgroundColor === theme.appBG && prevStatusBarBackgroundColor.current === theme.appBG) {
- return;
- }
-
- statusBarAnimation.value = 0;
- statusBarAnimation.value = withDelay(300, withTiming(1));
- };
-
const handleStateChange = (state: NavigationState | undefined) => {
if (!state) {
return;
@@ -132,7 +89,6 @@ function NavigationRoot({authenticated, onReady}: NavigationRootProps) {
currentReportIDValue?.updateCurrentReportID(state);
}, 0);
parseAndLogRoute(state);
- animateStatusBarBackgroundColor();
};
return (
diff --git a/src/libs/StatusBar/index.android.ts b/src/libs/StatusBar/index.android.ts
index c928f0949665..6cbf1a762a0b 100644
--- a/src/libs/StatusBar/index.android.ts
+++ b/src/libs/StatusBar/index.android.ts
@@ -1,10 +1,14 @@
import StatusBar from './types';
-// Only has custom web implementation
-StatusBar.getBackgroundColor = () => null;
+const setBackgroundColor = StatusBar.setBackgroundColor;
-// We override this because it's not used – on Android our app display edge-to-edge.
-// Also because Reanimated's interpolateColor gives Android native colors instead of hex strings, causing this to display a warning.
-StatusBar.setBackgroundColor = () => null;
+let statusBarColor: string | null = null;
+
+StatusBar.getBackgroundColor = () => statusBarColor;
+
+StatusBar.setBackgroundColor = (color, animated = false) => {
+ statusBarColor = color as string;
+ setBackgroundColor(color, animated);
+};
export default StatusBar;
diff --git a/src/pages/TeachersUnite/SaveTheWorldPage.js b/src/pages/TeachersUnite/SaveTheWorldPage.js
index 6d448b6b08b1..d179b7d1db95 100644
--- a/src/pages/TeachersUnite/SaveTheWorldPage.js
+++ b/src/pages/TeachersUnite/SaveTheWorldPage.js
@@ -38,7 +38,7 @@ function SaveTheWorldPage(props) {
Navigation.goBack(ROUTES.HOME)}
illustration={LottieAnimations.SaveTheWorld}
>
diff --git a/src/pages/settings/InitialSettingsPage.js b/src/pages/settings/InitialSettingsPage.js
index 61950e14337f..8ca1f96b3796 100755
--- a/src/pages/settings/InitialSettingsPage.js
+++ b/src/pages/settings/InitialSettingsPage.js
@@ -381,7 +381,7 @@ function InitialSettingsPage(props) {
title={translate('common.settings')}
headerContent={headerContent}
headerContainerStyles={[styles.staticHeaderImage, styles.justifyContentCenter]}
- backgroundColor={theme.PAGE_BACKGROUND_COLORS[SCREENS.SETTINGS.ROOT]}
+ backgroundColor={theme.PAGE_THEMES[SCREENS.SETTINGS.ROOT].backgroundColor}
>
{getMenuItems}
diff --git a/src/pages/settings/Preferences/PreferencesPage.js b/src/pages/settings/Preferences/PreferencesPage.js
index 4dbc5fda9198..b010c3790056 100755
--- a/src/pages/settings/Preferences/PreferencesPage.js
+++ b/src/pages/settings/Preferences/PreferencesPage.js
@@ -46,7 +46,7 @@ function PreferencesPage(props) {
Navigation.goBack(ROUTES.SETTINGS)}
- backgroundColor={theme.PAGE_BACKGROUND_COLORS[SCREENS.SETTINGS.PREFERENCES]}
+ backgroundColor={theme.PAGE_THEMES[SCREENS.SETTINGS.PREFERENCES].backgroundColor}
illustration={LottieAnimations.PreferencesDJ}
>
diff --git a/src/pages/settings/Profile/CustomStatus/StatusPage.js b/src/pages/settings/Profile/CustomStatus/StatusPage.js
index 285a3072f859..6850684cfda2 100644
--- a/src/pages/settings/Profile/CustomStatus/StatusPage.js
+++ b/src/pages/settings/Profile/CustomStatus/StatusPage.js
@@ -91,7 +91,7 @@ function StatusPage({draftStatus, currentUserPersonalDetails}) {
/>
}
headerContainerStyles={[styles.staticHeaderImage]}
- backgroundColor={theme.PAGE_BACKGROUND_COLORS[SCREENS.SETTINGS.STATUS]}
+ backgroundColor={theme.PAGE_THEMES[SCREENS.SETTINGS.STATUS].backgroundColor}
footer={footerComponent}
>
diff --git a/src/pages/settings/Security/SecuritySettingsPage.js b/src/pages/settings/Security/SecuritySettingsPage.js
index bf1edd7b806d..95a0efa2fc39 100644
--- a/src/pages/settings/Security/SecuritySettingsPage.js
+++ b/src/pages/settings/Security/SecuritySettingsPage.js
@@ -69,7 +69,7 @@ function SecuritySettingsPage(props) {
onBackButtonPress={() => Navigation.goBack(ROUTES.SETTINGS)}
shouldShowBackButton
illustration={LottieAnimations.Safe}
- backgroundColor={theme.PAGE_BACKGROUND_COLORS[SCREENS.SETTINGS.SECURITY]}
+ backgroundColor={theme.PAGE_THEMES[SCREENS.SETTINGS.SECURITY].backgroundColor}
>
diff --git a/src/pages/settings/Wallet/ActivatePhysicalCardPage.js b/src/pages/settings/Wallet/ActivatePhysicalCardPage.js
index 3534ef5c064c..e45b4ad67f4e 100644
--- a/src/pages/settings/Wallet/ActivatePhysicalCardPage.js
+++ b/src/pages/settings/Wallet/ActivatePhysicalCardPage.js
@@ -134,7 +134,7 @@ function ActivatePhysicalCardPage({
Navigation.navigate(ROUTES.SETTINGS_WALLET_DOMAINCARD.getRoute(domain))}
- backgroundColor={theme.PAGE_BACKGROUND_COLORS[SCREENS.SETTINGS.PREFERENCES]}
+ backgroundColor={theme.PAGE_THEMES[SCREENS.SETTINGS.PREFERENCES].backgroundColor}
illustration={LottieAnimations.Magician}
scrollViewContainerStyles={[styles.mnh100]}
childrenContainerStyles={[styles.flex1]}
diff --git a/src/pages/settings/Wallet/WalletEmptyState.js b/src/pages/settings/Wallet/WalletEmptyState.js
index 8eacd322d695..f2235dfafef2 100644
--- a/src/pages/settings/Wallet/WalletEmptyState.js
+++ b/src/pages/settings/Wallet/WalletEmptyState.js
@@ -36,7 +36,7 @@ function WalletEmptyState({onAddPaymentMethod}) {
const {translate} = useLocalize();
return (
Navigation.goBack(ROUTES.SETTINGS)}
title={translate('common.wallet')}
diff --git a/src/pages/signin/SignInPage.js b/src/pages/signin/SignInPage.js
index b0ced580b30e..e7499e2aef01 100644
--- a/src/pages/signin/SignInPage.js
+++ b/src/pages/signin/SignInPage.js
@@ -5,6 +5,8 @@ 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 useWindowDimensions from '@hooks/useWindowDimensions';
import * as ActiveClientManager from '@libs/ActiveClientManager';
@@ -279,10 +281,13 @@ function SignInPage(props) {
return (
-
+
+
+
+
);
diff --git a/src/pages/workspace/WorkspacesListPage.js b/src/pages/workspace/WorkspacesListPage.js
index 2749ccb52b96..cf258b462285 100755
--- a/src/pages/workspace/WorkspacesListPage.js
+++ b/src/pages/workspace/WorkspacesListPage.js
@@ -183,7 +183,7 @@ function WorkspacesListPage({policies, allPolicyMembers, reimbursementAccount, u
return (
Navigation.goBack(ROUTES.SETTINGS)}
title={translate('common.workspaces')}
diff --git a/src/styles/styles.ts b/src/styles/styles.ts
index 45736295d4be..c7e1988c7b05 100644
--- a/src/styles/styles.ts
+++ b/src/styles/styles.ts
@@ -40,6 +40,9 @@ import wordBreak from './utilities/wordBreak';
import writingDirection from './utilities/writingDirection';
import variables from './variables';
+type ColorScheme = (typeof CONST.COLOR_SCHEME)[keyof typeof CONST.COLOR_SCHEME];
+type StatusBarStyle = (typeof CONST.STATUS_BAR_STYLE)[keyof typeof CONST.STATUS_BAR_STYLE];
+
type AnchorPosition = {
horizontal: number;
vertical: number;
@@ -3984,12 +3987,14 @@ const styles = (theme: ThemeColors) =>
singleOptionSelectorCircle: {
borderColor: theme.icon,
},
+
+ colorSchemeStyle: (colorScheme: ColorScheme) => ({colorScheme}),
} satisfies Styles);
+type ThemeStyle = ReturnType;
+
const stylesGenerator = styles;
const defaultStyles = styles(defaultTheme);
-type ThemeStyle = typeof defaultStyles;
-
export default defaultStyles;
-export {stylesGenerator, type Styles, type ThemeStyle};
+export {stylesGenerator, type Styles, type ThemeStyle, type StatusBarStyle, type ColorScheme};
diff --git a/src/styles/themes/default.ts b/src/styles/themes/default.ts
index 8dd76a4776a4..519e818054e0 100644
--- a/src/styles/themes/default.ts
+++ b/src/styles/themes/default.ts
@@ -1,4 +1,5 @@
import colors from '@styles/colors';
+import CONST from '@src/CONST';
import SCREENS from '@src/SCREENS';
import {ThemeColors} from './types';
@@ -89,16 +90,47 @@ const darkTheme = {
// Note that it needs to be a screen name, not a route url.
// The route urls from ROUTES.ts are only used for deep linking and configuring URLs on web.
// The screen name (see SCREENS.ts) is the name of the screen as far as react-navigation is concerned, and the linkingConfig maps screen names to URLs
- PAGE_BACKGROUND_COLORS: {
- [SCREENS.HOME]: colors.darkHighlightBackground,
- [SCREENS.SAVE_THE_WORLD.ROOT]: colors.tangerine800,
- [SCREENS.SETTINGS.PREFERENCES]: colors.blue500,
- [SCREENS.SETTINGS.WORKSPACES]: colors.pink800,
- [SCREENS.SETTINGS.WALLET]: colors.darkAppBackground,
- [SCREENS.SETTINGS.SECURITY]: colors.ice500,
- [SCREENS.SETTINGS.STATUS]: colors.green700,
- [SCREENS.SETTINGS.ROOT]: colors.darkHighlightBackground,
+ PAGE_THEMES: {
+ [SCREENS.HOME]: {
+ backgroundColor: colors.darkHighlightBackground,
+ statusBarStyle: CONST.STATUS_BAR_STYLE.LIGHT_CONTENT,
+ },
+ [SCREENS.REPORT]: {
+ backgroundColor: colors.darkAppBackground,
+ statusBarStyle: CONST.STATUS_BAR_STYLE.LIGHT_CONTENT,
+ },
+ [SCREENS.SAVE_THE_WORLD.ROOT]: {
+ backgroundColor: colors.tangerine800,
+ statusBarStyle: CONST.STATUS_BAR_STYLE.LIGHT_CONTENT,
+ },
+ [SCREENS.SETTINGS.PREFERENCES]: {
+ backgroundColor: colors.blue500,
+ statusBarStyle: CONST.STATUS_BAR_STYLE.LIGHT_CONTENT,
+ },
+ [SCREENS.SETTINGS.WORKSPACES]: {
+ backgroundColor: colors.pink800,
+ statusBarStyle: CONST.STATUS_BAR_STYLE.LIGHT_CONTENT,
+ },
+ [SCREENS.SETTINGS.WALLET]: {
+ backgroundColor: colors.darkAppBackground,
+ statusBarStyle: CONST.STATUS_BAR_STYLE.LIGHT_CONTENT,
+ },
+ [SCREENS.SETTINGS.SECURITY]: {
+ backgroundColor: colors.ice500,
+ statusBarStyle: CONST.STATUS_BAR_STYLE.DARK_CONTENT,
+ },
+ [SCREENS.SETTINGS.STATUS]: {
+ backgroundColor: colors.green700,
+ statusBarStyle: CONST.STATUS_BAR_STYLE.LIGHT_CONTENT,
+ },
+ [SCREENS.SETTINGS.ROOT]: {
+ backgroundColor: colors.darkHighlightBackground,
+ statusBarStyle: CONST.STATUS_BAR_STYLE.LIGHT_CONTENT,
+ },
},
+
+ statusBarStyle: CONST.STATUS_BAR_STYLE.LIGHT_CONTENT,
+ colorScheme: CONST.COLOR_SCHEME.DARK,
} satisfies ThemeColors;
export default darkTheme;
diff --git a/src/styles/themes/light.ts b/src/styles/themes/light.ts
index cbaadcf196ba..2f6eda2f70dc 100644
--- a/src/styles/themes/light.ts
+++ b/src/styles/themes/light.ts
@@ -1,4 +1,5 @@
import colors from '@styles/colors';
+import CONST from '@src/CONST';
import SCREENS from '@src/SCREENS';
import {ThemeColors} from './types';
@@ -89,16 +90,47 @@ const lightTheme = {
// Note that it needs to be a screen name, not a route url.
// The route urls from ROUTES.ts are only used for deep linking and configuring URLs on web.
// The screen name (see SCREENS.ts) is the name of the screen as far as react-navigation is concerned, and the linkingConfig maps screen names to URLs
- PAGE_BACKGROUND_COLORS: {
- [SCREENS.HOME]: colors.lightHighlightBackground,
- [SCREENS.SAVE_THE_WORLD.ROOT]: colors.tangerine800,
- [SCREENS.SETTINGS.PREFERENCES]: colors.blue500,
- [SCREENS.SETTINGS.WORKSPACES]: colors.pink800,
- [SCREENS.SETTINGS.WALLET]: colors.darkAppBackground,
- [SCREENS.SETTINGS.SECURITY]: colors.ice500,
- [SCREENS.SETTINGS.STATUS]: colors.green700,
- [SCREENS.SETTINGS.ROOT]: colors.lightHighlightBackground,
+ PAGE_THEMES: {
+ [SCREENS.HOME]: {
+ backgroundColor: colors.lightHighlightBackground,
+ statusBarStyle: CONST.STATUS_BAR_STYLE.DARK_CONTENT,
+ },
+ [SCREENS.REPORT]: {
+ backgroundColor: colors.lightAppBackground,
+ statusBarStyle: CONST.STATUS_BAR_STYLE.DARK_CONTENT,
+ },
+ [SCREENS.SAVE_THE_WORLD.ROOT]: {
+ backgroundColor: colors.tangerine800,
+ statusBarStyle: CONST.STATUS_BAR_STYLE.LIGHT_CONTENT,
+ },
+ [SCREENS.SETTINGS.PREFERENCES]: {
+ backgroundColor: colors.blue500,
+ statusBarStyle: CONST.STATUS_BAR_STYLE.LIGHT_CONTENT,
+ },
+ [SCREENS.SETTINGS.WORKSPACES]: {
+ backgroundColor: colors.pink800,
+ statusBarStyle: CONST.STATUS_BAR_STYLE.LIGHT_CONTENT,
+ },
+ [SCREENS.SETTINGS.WALLET]: {
+ backgroundColor: colors.darkAppBackground,
+ statusBarStyle: CONST.STATUS_BAR_STYLE.LIGHT_CONTENT,
+ },
+ [SCREENS.SETTINGS.SECURITY]: {
+ backgroundColor: colors.ice500,
+ statusBarStyle: CONST.STATUS_BAR_STYLE.DARK_CONTENT,
+ },
+ [SCREENS.SETTINGS.STATUS]: {
+ backgroundColor: colors.green700,
+ statusBarStyle: CONST.STATUS_BAR_STYLE.LIGHT_CONTENT,
+ },
+ [SCREENS.SETTINGS.ROOT]: {
+ backgroundColor: colors.lightHighlightBackground,
+ statusBarStyle: CONST.STATUS_BAR_STYLE.DARK_CONTENT,
+ },
},
+
+ statusBarStyle: CONST.STATUS_BAR_STYLE.DARK_CONTENT,
+ colorScheme: CONST.COLOR_SCHEME.LIGHT,
} satisfies ThemeColors;
export default lightTheme;
diff --git a/src/styles/themes/types.ts b/src/styles/themes/types.ts
index d6d1dcea0833..c674b6057d0f 100644
--- a/src/styles/themes/types.ts
+++ b/src/styles/themes/types.ts
@@ -1,3 +1,4 @@
+import {type ColorScheme, type StatusBarStyle} from '@styles/styles';
import CONST from '@src/CONST';
type Color = string;
@@ -88,7 +89,13 @@ type ThemeColors = {
mapAttributionText: Color;
white: Color;
- PAGE_BACKGROUND_COLORS: Record;
+ PAGE_THEMES: Record;
+
+ // Status bar and scroll bars need to adapt their theme based on the active user theme for good contrast
+ // Therefore, we need to define specific themes for these elements
+ // e.g. the StatusBar displays either "light-content" or "dark-content" based on the theme
+ statusBarStyle: StatusBarStyle;
+ colorScheme: ColorScheme;
};
export {type ThemePreference, type ThemePreferenceWithoutSystem, type ThemeColors, type Color};