Skip to content

Commit

Permalink
Merge pull request #21669 from margelo/@chrispader/theme-switching-go…
Browse files Browse the repository at this point in the history
…ing-live

Theme switching: Going Live! (Add preferences menu entry for ThemePage)
  • Loading branch information
grgia authored Dec 14, 2023
2 parents b950c1e + ab996c7 commit e81ed8f
Show file tree
Hide file tree
Showing 8 changed files with 35 additions and 33 deletions.
5 changes: 3 additions & 2 deletions src/CONST.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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: {
Expand Down
14 changes: 4 additions & 10 deletions src/hooks/useThemePreference.ts
Original file line number Diff line number Diff line change
@@ -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<ThemePreferenceWithoutSystem>(CONST.THEME.DEFAULT);
const [systemTheme, setSystemTheme] = useState<ColorSchemeName>();
const [themePreference, setThemePreference] = useState<ThemePreferenceWithoutSystem>(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);
}
Expand Down
3 changes: 1 addition & 2 deletions src/libs/Navigation/AppNavigator/ModalStackNavigators.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -197,8 +197,7 @@ const SettingsModalStackNavigator = createModalStackNavigator<SettingsNavigatorP
[SCREENS.SETTINGS.PREFERENCES.ROOT]: () => 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,
Expand Down
13 changes: 13 additions & 0 deletions src/pages/settings/Preferences/PreferencesPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand All @@ -33,6 +36,7 @@ const propTypes = {

const defaultProps = {
priorityMode: CONST.PRIORITY_MODE.DEFAULT,
preferredTheme: CONST.DEFAULT_THEME,
user: {},
};

Expand Down Expand Up @@ -80,6 +84,12 @@ function PreferencesPage(props) {
description={translate('languagePage.language')}
onPress={() => Navigation.navigate(ROUTES.SETTINGS_LANGUAGE)}
/>
<MenuItemWithTopDescription
shouldShowRightIcon
title={translate(`themePage.themes.${props.preferredTheme || CONST.THEME.DEFAULT}.label`)}
description={translate('themePage.theme')}
onPress={() => Navigation.navigate(ROUTES.SETTINGS_THEME)}
/>
{/* Enable additional test features in non-production environments */}
{!isProduction && (
<View style={[styles.ml5, styles.mr8, styles.mt6]}>
Expand All @@ -102,4 +112,7 @@ export default withOnyx({
user: {
key: ONYXKEYS.USER,
},
preferredTheme: {
key: ONYXKEYS.PREFERRED_THEME,
},
})(PreferencesPage);
27 changes: 11 additions & 16 deletions src/pages/settings/Preferences/ThemePage.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,15 @@ 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';
import ONYXKEYS from '@src/ONYXKEYS';
import ROUTES from '@src/ROUTES';

const propTypes = {
...withLocalizePropTypes,

/** The theme of the app */
preferredTheme: PropTypes.string,
};
Expand All @@ -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,
}));
Expand All @@ -41,13 +39,13 @@ function ThemePage(props) {
testID={ThemePage.displayName}
>
<HeaderWithBackButton
title={props.translate('themePage.theme')}
title={translate('themePage.theme')}
shouldShowBackButton
onBackButtonPress={() => Navigation.navigate(ROUTES.SETTINGS_PREFERENCES)}
onCloseButtonPress={() => Navigation.dismissModal(true)}
/>

<Text style={[styles.mh5, styles.mv4]}>{props.translate('themePage.chooseThemeBelowOrSync')}</Text>
<Text style={[styles.mh5, styles.mv4]}>{translate('themePage.chooseThemeBelowOrSync')}</Text>

<SelectionList
sections={[{data: localesToThemes}]}
Expand All @@ -62,11 +60,8 @@ ThemePage.displayName = 'ThemePage';
ThemePage.propTypes = propTypes;
ThemePage.defaultProps = defaultProps;

export default compose(
withLocalize,
withOnyx({
preferredTheme: {
key: ONYXKEYS.PREFERRED_THEME,
},
}),
)(ThemePage);
export default withOnyx({
preferredTheme: {
key: ONYXKEYS.PREFERRED_THEME,
},
})(ThemePage);
2 changes: 1 addition & 1 deletion src/styles/theme/illustrations/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ const Illustrations = {
[CONST.THEME.DARK]: darkIllustrations,
} satisfies Record<ThemePreferenceWithoutSystem, IllustrationsType>;

const DefaultIllustrations = Illustrations[CONST.THEME.DEFAULT];
const DefaultIllustrations = Illustrations[CONST.THEME.FALLBACK];

export default Illustrations;
export {DefaultIllustrations};
2 changes: 1 addition & 1 deletion src/styles/theme/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ const themes = {
[CONST.THEME.DARK]: darkTheme,
} satisfies Record<ThemePreferenceWithoutSystem, ThemeColors>;

const defaultTheme = themes[CONST.THEME.DEFAULT];
const defaultTheme = themes[CONST.THEME.FALLBACK];

export default themes;
export {defaultTheme};
2 changes: 1 addition & 1 deletion src/styles/theme/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<ThemePreference, 'system'>;
type ThemePreferenceWithoutSystem = Exclude<ThemePreference, typeof CONST.THEME.SYSTEM>;

type ThemeColors = {
// Figma keys
Expand Down

0 comments on commit e81ed8f

Please sign in to comment.