diff --git a/lib/hooks/theme.js b/lib/hooks/theme.js index e69176c9c..85e2fade2 100644 --- a/lib/hooks/theme.js +++ b/lib/hooks/theme.js @@ -1,37 +1,70 @@ // @flow import * as React from 'react'; import { useDispatch } from 'react-redux'; import { updateThemeInfoActionType } from '../actions/theme-actions.js'; import type { Shape } from '../types/core.js'; -import type { GlobalTheme, GlobalThemeInfo } from '../types/theme-types.js'; +import type { + GlobalTheme, + GlobalThemeInfo, + GlobalThemePreference, +} from '../types/theme-types.js'; import { useSelector } from '../utils/redux-utils.js'; function useUpdateSystemTheme(): (colorScheme: ?GlobalTheme) => mixed { const globalThemeInfo = useSelector(state => state.globalThemeInfo); const dispatch = useDispatch(); return React.useCallback( (colorScheme: ?GlobalTheme) => { if (globalThemeInfo.systemTheme === colorScheme) { return; } let updateObject: Shape = { systemTheme: colorScheme, }; if (globalThemeInfo.preference === 'system') { updateObject = { ...updateObject, activeTheme: colorScheme }; } dispatch({ type: updateThemeInfoActionType, payload: updateObject, }); }, [globalThemeInfo, dispatch], ); } -export { useUpdateSystemTheme }; +function useUpdateThemePreference(): ( + themePreference: GlobalThemePreference, +) => mixed { + const globalThemeInfo = useSelector(state => state.globalThemeInfo); + const dispatch = useDispatch(); + + return React.useCallback( + (themePreference: GlobalThemePreference) => { + if (themePreference === globalThemeInfo.preference) { + return; + } + + let theme = themePreference; + if (themePreference === 'system') { + theme = globalThemeInfo.systemTheme; + } + + dispatch({ + type: updateThemeInfoActionType, + payload: { + preference: themePreference, + activeTheme: theme, + }, + }); + }, + [globalThemeInfo, dispatch], + ); +} + +export { useUpdateSystemTheme, useUpdateThemePreference }; diff --git a/native/profile/appearance-preferences.react.js b/native/profile/appearance-preferences.react.js index c54c385a4..70fd7f7e0 100644 --- a/native/profile/appearance-preferences.react.js +++ b/native/profile/appearance-preferences.react.js @@ -1,172 +1,154 @@ // @flow import * as React from 'react'; import { View, Text, Platform } from 'react-native'; import { ScrollView } from 'react-native-gesture-handler'; -import { useDispatch } from 'react-redux'; -import { updateThemeInfoActionType } from 'lib/actions/theme-actions.js'; -import type { Dispatch } from 'lib/types/redux-types.js'; +import { useUpdateThemePreference } from 'lib/hooks/theme.js'; import type { GlobalThemeInfo, GlobalThemePreference, } from 'lib/types/theme-types.js'; import Button from '../components/button.react.js'; import SWMansionIcon from '../components/swmansion-icon.react.js'; import { useSelector } from '../redux/redux-utils.js'; import { type Colors, useColors, useStyles } from '../themes/colors.js'; import { osCanTheme } from '../themes/theme-utils.js'; const CheckIcon = () => ( ); type OptionText = { themePreference: GlobalThemePreference, text: string, }; const optionTexts: OptionText[] = [ { themePreference: 'light', text: 'Light' }, { themePreference: 'dark', text: 'Dark' }, ]; if (osCanTheme) { optionTexts.push({ themePreference: 'system', text: 'Follow system preferences', }); } type Props = { +globalThemeInfo: GlobalThemeInfo, + +updateThemePreference: (themePreference: GlobalThemePreference) => mixed, +styles: typeof unboundStyles, +colors: Colors, - +dispatch: Dispatch, ... }; class AppearancePreferences extends React.PureComponent { render() { const { panelIosHighlightUnderlay: underlay } = this.props.colors; const options = []; for (let i = 0; i < optionTexts.length; i++) { const { themePreference, text } = optionTexts[i]; const icon = themePreference === this.props.globalThemeInfo.preference ? ( ) : null; options.push( , ); if (i + 1 < optionTexts.length) { options.push( , ); } } return ( APP THEME {options} ); } - - onSelectThemePreference = (themePreference: GlobalThemePreference) => { - if (themePreference === this.props.globalThemeInfo.preference) { - return; - } - const theme = - themePreference === 'system' - ? this.props.globalThemeInfo.systemTheme - : themePreference; - this.props.dispatch({ - type: updateThemeInfoActionType, - payload: { - preference: themePreference, - activeTheme: theme, - }, - }); - }; } const unboundStyles = { header: { color: 'panelBackgroundLabel', fontSize: 12, fontWeight: '400', paddingBottom: 3, paddingHorizontal: 24, }, hr: { backgroundColor: 'panelForegroundBorder', height: 1, marginHorizontal: 15, }, icon: { lineHeight: Platform.OS === 'ios' ? 18 : 20, }, option: { color: 'panelForegroundLabel', fontSize: 16, }, row: { flexDirection: 'row', justifyContent: 'space-between', paddingHorizontal: 24, paddingVertical: 10, }, scrollView: { backgroundColor: 'panelBackground', }, scrollViewContentContainer: { paddingTop: 24, }, section: { backgroundColor: 'panelForeground', borderBottomWidth: 1, borderColor: 'panelForegroundBorder', borderTopWidth: 1, marginBottom: 24, paddingVertical: 2, }, }; const ConnectedAppearancePreferences: React.ComponentType<{ ... }> = React.memo<{ ... }>(function ConnectedAppearancePreferences(props: { ... }) { const globalThemeInfo = useSelector(state => state.globalThemeInfo); + const updateThemePreference = useUpdateThemePreference(); + const styles = useStyles(unboundStyles); const colors = useColors(); - const dispatch = useDispatch(); return ( ); }); export default ConnectedAppearancePreferences;