Skip to content

Commit

Permalink
New theme selector
Browse files Browse the repository at this point in the history
  • Loading branch information
cmgustavo committed Aug 28, 2024
1 parent 1047ec3 commit 204919f
Show file tree
Hide file tree
Showing 8 changed files with 105 additions and 59 deletions.
37 changes: 6 additions & 31 deletions src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,47 +1,22 @@
import React, {useCallback, useEffect, useState} from 'react';
import {useColorScheme, ColorSchemeName, Appearance} from 'react-native';
import React, {useEffect} from 'react';

import {NavigationContainer} from '@react-navigation/native';

import {useAppDispatch, useAppSelector, RootState} from './store';
import {useAppDispatch} from './store';
import {initializeApp} from './store/app';
import MainNavigation from './components/main-navigation';
import CombinedDefaultTheme from './themes/light';
import CombinedDarkTheme from './themes/dark';

import {PaperProvider} from 'react-native-paper';
import {PreferencesProvider} from './context/PreferencesContext';

const App = () => {
const dispatch = useAppDispatch();
const _theme = useAppSelector(({APP}: RootState) => APP.appTheme);

const [theme, setTheme] = useState<ColorSchemeName>(useColorScheme());

const themeChangeListener = useCallback(() => {
if (!theme) {
setTheme(Appearance.getColorScheme());
}
}, []);

useEffect(() => {
Appearance.addChangeListener(themeChangeListener);
return () => {
Appearance.addChangeListener(themeChangeListener);
};
}, [themeChangeListener]);

useEffect(() => {
dispatch(initializeApp());
}, []);

return (
<PaperProvider
theme={theme === 'dark' ? CombinedDarkTheme : CombinedDefaultTheme}>
<NavigationContainer
theme={theme === 'dark' ? CombinedDarkTheme : CombinedDefaultTheme}>
<MainNavigation />
</NavigationContainer>
</PaperProvider>
<PreferencesProvider>
<MainNavigation />
</PreferencesProvider>
);
};

Expand Down
60 changes: 60 additions & 0 deletions src/context/PreferencesContext.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import React, {createContext, useState, useEffect, useContext} from 'react';
import {useColorScheme, ColorSchemeName} from 'react-native';
import {useAppDispatch, useAppSelector, RootState} from '../store';
import {setColorScheme} from '../store/app/app.actions';
import {PaperProvider} from 'react-native-paper';
import {NavigationContainer} from '@react-navigation/native';
import CombinedDefaultTheme from '../themes/light';
import CombinedDarkTheme from '../themes/dark';

// Define the type for your context
type PreferencesContextType = {
setColorTheme: (theme: ColorSchemeName) => void;
colorTheme: ColorSchemeName;
};

export const PreferencesContext = createContext<PreferencesContextType>({
setColorTheme: (theme: ColorSchemeName) => {},
colorTheme: null,
});

export const PreferencesProvider = ({
children,
}: {
children: React.ReactNode;
}) => {
const _theme = useAppSelector(({APP}: RootState) => APP.colorScheme);
const [colorTheme, setColorTheme] = useState<ColorSchemeName>(_theme);
const dispatch = useAppDispatch();
const systemColorScheme = useColorScheme();
let appTheme;
if (!colorTheme) {
appTheme =
systemColorScheme === 'dark' ? CombinedDarkTheme : CombinedDefaultTheme;
} else {
appTheme = colorTheme === 'dark' ? CombinedDarkTheme : CombinedDefaultTheme;
}

useEffect(() => {
if (!colorTheme) {
appTheme =
systemColorScheme === 'dark' ? CombinedDarkTheme : CombinedDefaultTheme;
}
}, [systemColorScheme]);

const handleSetColorTheme = (theme: ColorSchemeName) => {
setColorTheme(theme);
dispatch(setColorScheme(theme));
};

return (
<PreferencesContext.Provider
value={{colorTheme, setColorTheme: handleSetColorTheme}}>
<PaperProvider theme={appTheme}>
<NavigationContainer theme={appTheme}>{children}</NavigationContainer>
</PaperProvider>
</PreferencesContext.Provider>
);
};

export const usePreferences = () => useContext(PreferencesContext);
46 changes: 25 additions & 21 deletions src/screens/preferences.tsx
Original file line number Diff line number Diff line change
@@ -1,47 +1,51 @@
import React, {useState} from 'react';
import React, {useState, useContext} from 'react';
import {View, Text, TouchableOpacity, Appearance} from 'react-native';
import {RadioButton, List} from 'react-native-paper';
import {useAppDispatch, useAppSelector, RootState} from '../store';
import {useTheme} from 'react-native-paper';
import {useTheme, Switch} from 'react-native-paper';
import {useColorScheme, ColorSchemeName} from 'react-native';

import {appTheme} from '../store/app/app.actions';
import {
PreferencesContext,
usePreferences,
} from '../context/PreferencesContext';
import {ContainerStyles, GlobalStyles, TextStyles} from '../styles';

const Preferences = ({route, navigation}) => {
const dispatch = useAppDispatch();
const {colors} = useTheme();
const _theme = useAppSelector(({APP}: RootState) => APP.appTheme);
const [theme, setTheme] = useState<ColorSchemeName>(_theme);
const [checked, setChecked] = useState(theme);
const theme = useTheme();

const {colorTheme, setColorTheme} = usePreferences();
console.log('[preferences.tsx:16]', colorTheme); /* TODO */

const [checked, setChecked] = useState(colorTheme);
console.log('[preferences.tsx:19]', checked); /* TODO */

const handleThemeChange = (newTheme: ColorSchemeName) => {
setColorTheme(newTheme);
setChecked(newTheme);
dispatch(appTheme(newTheme));
setTheme(newTheme);
Appearance.setColorScheme(newTheme);
};

return (
<View
style={[
ContainerStyles.globalContainer,
{backgroundColor: colors.background},
{backgroundColor: theme.colors.background},
]}>
<List.Section>
<Text style={[TextStyles.optionsTitle, {color: colors.primary}]}>
<Text style={[TextStyles.optionsTitle, {color: theme.colors.primary}]}>
Theme
</Text>
<TouchableOpacity
onPress={() => handleThemeChange('light')}
style={[
GlobalStyles.itemContainer,
{
backgroundColor: colors.background,
borderBottomColor: colors.surfaceVariant,
backgroundColor: theme.colors.background,
borderBottomColor: theme.colors.surfaceVariant,
},
]}>
<Text style={[GlobalStyles.itemText, {color: colors.primary}]}>
<Text style={[GlobalStyles.itemText, {color: theme.colors.primary}]}>
Light
</Text>
<RadioButton
Expand All @@ -55,11 +59,11 @@ const Preferences = ({route, navigation}) => {
style={[
GlobalStyles.itemContainer,
{
backgroundColor: colors.background,
borderBottomColor: colors.surfaceVariant,
backgroundColor: theme.colors.background,
borderBottomColor: theme.colors.surfaceVariant,
},
]}>
<Text style={[GlobalStyles.itemText, {color: colors.primary}]}>
<Text style={[GlobalStyles.itemText, {color: theme.colors.primary}]}>
Dark
</Text>
<RadioButton
Expand All @@ -73,11 +77,11 @@ const Preferences = ({route, navigation}) => {
style={[
GlobalStyles.itemContainer,
{
backgroundColor: colors.background,
borderBottomColor: colors.surfaceVariant,
backgroundColor: theme.colors.background,
borderBottomColor: theme.colors.surfaceVariant,
},
]}>
<Text style={[GlobalStyles.itemText, {color: colors.primary}]}>
<Text style={[GlobalStyles.itemText, {color: theme.colors.primary}]}>
System
</Text>
<RadioButton
Expand Down
2 changes: 1 addition & 1 deletion src/store/app/app.actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export const appFailed = (): AppActionType => ({
type: AppActionTypes.APP_FAILED,
});

export const appTheme = (theme: ColorSchemeName): AppActionType => ({
export const setColorScheme = (theme: ColorSchemeName): AppActionType => ({
type: AppActionTypes.APP_THEME,
payload: theme,
});
6 changes: 3 additions & 3 deletions src/store/app/app.reducer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@ export const AppReduxPersistBlackList: (keyof AppState)[] = ['appStatus'];

export interface AppState {
appStatus: AppStatus;
appTheme: ColorSchemeName;
colorScheme: ColorSchemeName;
}

const initialState: AppState = {
appStatus: 'loading',
appTheme: null,
colorScheme: null,
};

export const AppReducer = (
Expand All @@ -31,7 +31,7 @@ export const AppReducer = (
case AppActionTypes.APP_THEME:
return {
...state,
appTheme: action.payload,
colorScheme: action.payload,
};
default:
return state;
Expand Down
4 changes: 2 additions & 2 deletions src/store/app/app.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ interface AppFailed {
type: typeof AppActionTypes.APP_FAILED;
}

interface AppThemeAction {
interface AppColorScheme {
type: typeof AppActionTypes.APP_THEME;
payload: ColorSchemeName;
}

export type AppActionType = AppSuccess | AppFailed | AppThemeAction;
export type AppActionType = AppSuccess | AppFailed | AppColorScheme;
2 changes: 1 addition & 1 deletion src/store/app/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
export {appSuccess, appFailed, appTheme} from './app.actions';
export {appSuccess, appFailed, setColorScheme} from './app.actions';
export {initializeApp} from './app.effects';
7 changes: 7 additions & 0 deletions src/styles/global.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,18 @@ export const GlobalStyles = StyleSheet.create({
itemContainer: {
flexDirection: 'row',
alignItems: 'center',
backgroundColor: '#fff',
padding: 15,
borderBottomWidth: 1,
borderBottomColor: '#e0e0e0',
},
itemText: {
flex: 1,
fontSize: 16,
},
subheader: {
padding: 10,
color: '#6e6e6e',
fontSize: 18,
},
});

0 comments on commit 204919f

Please sign in to comment.