diff --git a/src/CONST.ts b/src/CONST.ts index fa8e6d761185..c0e3d64b5eee 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -707,9 +707,10 @@ const CONST = { DEFAULT: 'default', }, THEME: { - DEFAULT: 'dark', - LIGHT: 'light', + DEFAULT: 'system', + FALLBACK: 'dark', DARK: 'dark', + LIGHT: 'light', SYSTEM: 'system', }, COLOR_SCHEME: { diff --git a/src/hooks/useThemePreference.ts b/src/hooks/useThemePreference.ts index 7c9dad49a841..5d3ec4c3a860 100644 --- a/src/hooks/useThemePreference.ts +++ b/src/hooks/useThemePreference.ts @@ -1,26 +1,20 @@ import {useContext, useEffect, useState} from 'react'; -import {Appearance, ColorSchemeName} from 'react-native'; +import {useColorScheme} from 'react-native'; import {PreferredThemeContext} from '@components/OnyxProvider'; import {ThemePreferenceWithoutSystem} from '@styles/theme/types'; import CONST from '@src/CONST'; function useThemePreference() { - const [themePreference, setThemePreference] = useState(CONST.THEME.DEFAULT); - const [systemTheme, setSystemTheme] = useState(); + const [themePreference, setThemePreference] = useState(CONST.THEME.FALLBACK); const preferredThemeFromStorage = useContext(PreferredThemeContext); - - useEffect(() => { - // This is used for getting the system theme, that can be set in the OS's theme settings. This will always return either "light" or "dark" and will update automatically if the OS theme changes. - const systemThemeSubscription = Appearance.addChangeListener(({colorScheme}) => setSystemTheme(colorScheme)); - return () => systemThemeSubscription.remove(); - }, []); + const systemTheme = useColorScheme(); useEffect(() => { const theme = preferredThemeFromStorage ?? CONST.THEME.DEFAULT; // If the user chooses to use the device theme settings, we need to set the theme preference to the system theme if (theme === CONST.THEME.SYSTEM) { - setThemePreference(systemTheme ?? CONST.THEME.DEFAULT); + setThemePreference(systemTheme ?? CONST.THEME.FALLBACK); } else { setThemePreference(theme); } diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators.tsx b/src/libs/Navigation/AppNavigator/ModalStackNavigators.tsx index 65c3d7011d78..256ea6d4eceb 100644 --- a/src/libs/Navigation/AppNavigator/ModalStackNavigators.tsx +++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators.tsx @@ -197,8 +197,7 @@ const SettingsModalStackNavigator = createModalStackNavigator require('../../../pages/settings/Preferences/PreferencesPage').default as React.ComponentType, [SCREENS.SETTINGS.PREFERENCES.PRIORITY_MODE]: () => require('../../../pages/settings/Preferences/PriorityModePage').default as React.ComponentType, [SCREENS.SETTINGS.PREFERENCES.LANGUAGE]: () => require('../../../pages/settings/Preferences/LanguagePage').default as React.ComponentType, - // Will be uncommented as part of https://github.com/Expensify/App/issues/21670 - // [SCREENS.SETTINGS.PREFERENCES.THEME]: () => require('../../../pages/settings/Preferences/ThemePage').default as React.ComponentType, + [SCREENS.SETTINGS.PREFERENCES.THEME]: () => require('../../../pages/settings/Preferences/ThemePage').default as React.ComponentType, [SCREENS.SETTINGS.CLOSE]: () => require('../../../pages/settings/Security/CloseAccountPage').default as React.ComponentType, [SCREENS.SETTINGS.SECURITY]: () => require('../../../pages/settings/Security/SecuritySettingsPage').default as React.ComponentType, [SCREENS.SETTINGS.ABOUT]: () => require('../../../pages/settings/AboutPage/AboutPage').default as React.ComponentType, diff --git a/src/pages/settings/Preferences/PreferencesPage.js b/src/pages/settings/Preferences/PreferencesPage.js index 10e09e7aee3b..e98cd2b19c39 100755 --- a/src/pages/settings/Preferences/PreferencesPage.js +++ b/src/pages/settings/Preferences/PreferencesPage.js @@ -24,6 +24,9 @@ const propTypes = { /** The chat priority mode */ priorityMode: PropTypes.string, + /** The app's color theme */ + preferredTheme: PropTypes.string, + /** The details about the user that is signed in */ user: PropTypes.shape({ /** Whether or not the user is subscribed to news updates */ @@ -33,6 +36,7 @@ const propTypes = { const defaultProps = { priorityMode: CONST.PRIORITY_MODE.DEFAULT, + preferredTheme: CONST.DEFAULT_THEME, user: {}, }; @@ -80,6 +84,12 @@ function PreferencesPage(props) { description={translate('languagePage.language')} onPress={() => Navigation.navigate(ROUTES.SETTINGS_LANGUAGE)} /> + Navigation.navigate(ROUTES.SETTINGS_THEME)} + /> {/* Enable additional test features in non-production environments */} {!isProduction && ( @@ -102,4 +112,7 @@ export default withOnyx({ user: { key: ONYXKEYS.USER, }, + preferredTheme: { + key: ONYXKEYS.PREFERRED_THEME, + }, })(PreferencesPage); diff --git a/src/pages/settings/Preferences/ThemePage.js b/src/pages/settings/Preferences/ThemePage.js index 529759df6611..453bf0a72aa8 100644 --- a/src/pages/settings/Preferences/ThemePage.js +++ b/src/pages/settings/Preferences/ThemePage.js @@ -6,9 +6,8 @@ import HeaderWithBackButton from '@components/HeaderWithBackButton'; import ScreenWrapper from '@components/ScreenWrapper'; import SelectionList from '@components/SelectionList'; import Text from '@components/Text'; -import withLocalize, {withLocalizePropTypes} from '@components/withLocalize'; +import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; -import compose from '@libs/compose'; import Navigation from '@libs/Navigation/Navigation'; import * as User from '@userActions/User'; import CONST from '@src/CONST'; @@ -16,8 +15,6 @@ import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; const propTypes = { - ...withLocalizePropTypes, - /** The theme of the app */ preferredTheme: PropTypes.string, }; @@ -28,9 +25,10 @@ const defaultProps = { function ThemePage(props) { const styles = useThemeStyles(); - const localesToThemes = _.map(_.values(_.omit(CONST.THEME, 'DEFAULT')), (theme) => ({ + const {translate} = useLocalize(); + const localesToThemes = _.map(_.values(_.omit(CONST.THEME, 'DEFAULT', 'FALLBACK')), (theme) => ({ value: theme, - text: props.translate(`themePage.themes.${theme}.label`), + text: translate(`themePage.themes.${theme}.label`), keyForList: theme, isSelected: (props.preferredTheme || CONST.THEME.DEFAULT) === theme, })); @@ -41,13 +39,13 @@ function ThemePage(props) { testID={ThemePage.displayName} > Navigation.navigate(ROUTES.SETTINGS_PREFERENCES)} onCloseButtonPress={() => Navigation.dismissModal(true)} /> - {props.translate('themePage.chooseThemeBelowOrSync')} + {translate('themePage.chooseThemeBelowOrSync')} ; -const DefaultIllustrations = Illustrations[CONST.THEME.DEFAULT]; +const DefaultIllustrations = Illustrations[CONST.THEME.FALLBACK]; export default Illustrations; export {DefaultIllustrations}; diff --git a/src/styles/theme/index.ts b/src/styles/theme/index.ts index de7805a6fe9d..c8c3a6ec12c1 100644 --- a/src/styles/theme/index.ts +++ b/src/styles/theme/index.ts @@ -8,7 +8,7 @@ const themes = { [CONST.THEME.DARK]: darkTheme, } satisfies Record; -const defaultTheme = themes[CONST.THEME.DEFAULT]; +const defaultTheme = themes[CONST.THEME.FALLBACK]; export default themes; export {defaultTheme}; diff --git a/src/styles/theme/types.ts b/src/styles/theme/types.ts index 0cd69b45270f..56da65ddd17d 100644 --- a/src/styles/theme/types.ts +++ b/src/styles/theme/types.ts @@ -4,7 +4,7 @@ import {type ColorScheme, type StatusBarStyle} from '..'; type Color = string; type ThemePreference = (typeof CONST.THEME)[keyof typeof CONST.THEME]; -type ThemePreferenceWithoutSystem = Exclude; +type ThemePreferenceWithoutSystem = Exclude; type ThemeColors = { // Figma keys