Skip to content

Commit 534bb8d

Browse files
authored
Feature/theme (#12)
* integrated dark/light theme using react context and useState hooks
1 parent 487a4a7 commit 534bb8d

File tree

11 files changed

+149
-61
lines changed

11 files changed

+149
-61
lines changed

App/App.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,19 @@ import { Provider } from 'react-redux';
1414
import { Navigation } from './navigation';
1515
import NavigationService from './utils/navigationService';
1616

17+
import { ThemeContextProvider } from './theme/themeProvider';
18+
1719
const App = () => {
1820
return (
1921

2022
<Provider store={store}>
23+
<ThemeContextProvider>
2124
<Navigation
2225
ref={navigatorRef => {
2326
NavigationService.setTopLevelNavigator(navigatorRef);
2427
}}
2528
/>
29+
</ThemeContextProvider>
2630
</Provider>
2731
);
2832
};

App/components/content.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,10 @@ export const Content = ({style,children}) => {
77
return (
88
<KeyboardAwareScrollView
99
automaticallyAdjustContentInsets={false}
10-
style={{flex: 1}}
1110
showsVerticalScrollIndicator
1211
contentContainerStyle={[{
1312
padding: 15,
13+
height:'100%',
1414
flexDirection: 'column'
1515
},style]}>
1616
{children}

App/components/footer.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ export const Footer = ({ style, children }) => {
1515
flexDirection: 'row',
1616
justifyContent: 'center',
1717
alignItems: 'center',
18-
backgroundColor: 'transparent'
18+
backgroundColor: 'white'
1919
}, style]}>
2020
{children}
2121
</View>

App/components/header.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ import { View,StatusBar } from 'react-native';
33
import { BarStyle } from '../theme/global';
44

55
export const Header = ({style,statusbarColor,barStyle = BarStyle ,children}) => {
6-
console.log(children)
76
return (
87
<View style={[{
98
height: 48,

App/containers/about/index.js

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,14 @@ import {
66
HeaderRight,
77
HeaderLeft, Button
88
} from '../../components/index';
9+
import { wrapTheme } from '../../theme/themeProvider';
910

10-
export default class AboutScreen extends PureComponent {
11-
11+
class About extends PureComponent {
12+
constructor(props) {
13+
super(props)
14+
}
1215
render() {
16+
const { theme } = this.props;
1317
const images = [
1418
'https://cdn.dribbble.com/users/4103091/screenshots/7353178/media/6d1a3a06961c0dcfd513ffe241636472.png',
1519
'https://cdn.dribbble.com/users/4103091/screenshots/7154300/media/7839c89716a90284e0c52595efb61dd5.jpg',
@@ -30,15 +34,17 @@ export default class AboutScreen extends PureComponent {
3034
</HeaderBody>
3135
<HeaderRight />
3236
</Header>
33-
<Content>
37+
<Content style={{
38+
backgroundColor: theme.backgroundColor
39+
}}>
3440
<View style={{
3541
flexDirection: 'column',
3642
width: '100%',
3743
justifyContent: 'center',
3844
alignItems: 'center',
3945
marginBottom: 30,
4046
}}>
41-
<Text style={style.title}>About Screen</Text>
47+
<Text style={[style.title,{color: theme.color}]}>About Screen</Text>
4248

4349
<Button
4450
style={{ backgroundColor: 'green' }}
@@ -63,6 +69,8 @@ export default class AboutScreen extends PureComponent {
6369
}
6470
}
6571

72+
export default AboutScreen = wrapTheme(About);
73+
6674
const style = StyleSheet.create({
6775
title: {
6876
fontSize: 18,

App/containers/login/index.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,20 @@ import NavigationService from '../../utils/navigationService';
44
import storageService from '../../utils/storageService';
55
import { connect } from 'react-redux';
66
import * as loginActions from './actions';
7+
import { wrapTheme } from '../../theme/themeProvider';
78

8-
class LoginScreen extends PureComponent {
9+
class Login extends PureComponent {
910
constructor(props) {
1011
super(props)
1112
}
1213
render() {
14+
const { theme } = this.props;
1315
return (
1416
<View
1517
style={{
1618
flex: 1,
1719
padding: 30,
20+
backgroundColor: theme.backgroundColor,
1821
justifyContent: 'space-evenly',
1922
alignItems: 'center',
2023
}}>
@@ -44,6 +47,7 @@ const mapDispatchToProps = dispatch => {
4447
};
4548
};
4649

50+
const LoginScreen = wrapTheme(Login)
4751
export default connect(
4852
mapStateToProps,
4953
mapDispatchToProps

App/containers/sideMenu/index.js

Lines changed: 64 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,56 +1,90 @@
1-
import React, {PureComponent} from 'react';
2-
import SafeAreaView from 'react-native-safe-area-view';
3-
import { DrawerNavigatorItems } from 'react-navigation-drawer';
4-
import { StyleSheet, Text } from 'react-native';
1+
import React, { PureComponent } from 'react';
2+
import { StyleSheet, View, Text, Switch } from 'react-native';
53
import {
64
Container, Header, Content, HeaderBody,
7-
HeaderRight,Footer,
5+
HeaderRight, Footer,
86
HeaderLeft, Button
97
} from '../../components/index';
108
import { GlobalStyle } from '../../theme/global';
119
import store from '../../store/configureStore';
1210
import * as loginTypes from '../login/types';
11+
import { wrapTheme } from '../../theme/themeProvider';
12+
import storageService from '../../utils/storageService';
13+
14+
15+
class Sidemenu extends PureComponent {
1316

14-
export class SidemenuScreen extends PureComponent {
1517
constructor(props) {
1618
super(props)
17-
console.log(props)
18-
19+
this.state = {
20+
isDarkMode: this.props.theme.key === 'Dark Mode' ? true : false
21+
}
1922
}
2023

2124
onLogOut() {
2225
store.dispatch({
2326
type: loginTypes.LOGOUT
2427
});
2528
}
29+
onThemeChange() {
30+
this.props.setTheme(this.state.isDarkMode ? 'Light Mode' : 'Dark Mode');
31+
storageService.setThemeId(this.state.isDarkMode ? 'Light Mode' : 'Dark Mode');
32+
this.setState((prev) => ({ isDarkMode: !prev.isDarkMode }))
33+
}
2634
render() {
27-
return (
28-
<Container>
29-
<Header
30-
barStyle="dark-content"
31-
statusbarColor="white">
32-
<HeaderLeft />
33-
<HeaderBody>
34-
<Text style={[GlobalStyle.headerTitle]}>Boilerplate</Text>
35-
</HeaderBody>
36-
<HeaderRight />
37-
</Header>
38-
<Content>
39-
</Content>
40-
<Footer>
41-
<Button
42-
onClick={()=> this.onLogOut()}
43-
style={{backgroundColor: 'red'}}>
44-
<Text style={{color:'white'}}>Logout</Text>
45-
</Button>
46-
</Footer>
47-
</Container>
48-
)
35+
const { isDarkMode } = this.state;
36+
const { theme } = this.props;
37+
return (
38+
<Container>
39+
<Header
40+
barStyle="dark-content"
41+
statusbarColor="white">
42+
<HeaderLeft />
43+
<HeaderBody>
44+
<Text style={[GlobalStyle.headerTitle]}>Boilerplate</Text>
45+
</HeaderBody>
46+
<HeaderRight />
47+
</Header>
48+
<Content style={{
49+
backgroundColor: theme.backgroundColor
50+
}}>
51+
<Text style={{
52+
marginBottom: 40,
53+
color: theme.color,
54+
fontWeight: 'bold'
55+
}}>Switch Theme</Text>
56+
<View style={styles.switchContainer}>
57+
<Text style={{ color: theme.color,
58+
fontSize: isDarkMode ? 14 : 16,
59+
fontWeight: isDarkMode ? '100' : 'bold' }}>{'Light Mode'}</Text>
60+
<Switch
61+
onValueChange={() => this.onThemeChange()}
62+
value={isDarkMode} />
63+
<Text style={{ color: theme.color,
64+
fontSize: isDarkMode ? 16 : 14,
65+
fontWeight: isDarkMode ? 'bold' : '100' }}>{'Dark Mode'}</Text>
66+
</View>
67+
</Content>
68+
<Footer>
69+
<Button
70+
onClick={() => this.onLogOut()}
71+
style={{ backgroundColor: 'red' }}>
72+
<Text style={{ color: 'white' }}>Logout</Text>
73+
</Button>
74+
</Footer>
75+
</Container>
76+
)
4977
}
5078
}
5179

80+
export const SidemenuScreen = wrapTheme(Sidemenu);
5281
const styles = StyleSheet.create({
5382
container: {
5483
flex: 1,
5584
},
85+
switchContainer: {
86+
flexDirection: 'row',
87+
justifyContent: 'space-evenly',
88+
alignItems: 'center',
89+
}
5690
});

App/theme/themeProvider.js

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,38 @@
1-
import THEMES from './themes.json';
1+
import React, { useContext, useState, useEffect } from 'react';
22

3-
export const themes = THEMES;
4-
export const theme = THEMES[1];
3+
export const ThemeContext = React.createContext();
4+
5+
import storageService from '../utils/storageService';
6+
7+
8+
import Themes from './themes.json';
9+
10+
11+
12+
export const ThemeContextProvider = ({ children }) => {
13+
const [themeID, setThemeID] = useState();
14+
15+
useEffect(() => {
16+
(async () => {
17+
const storedThemeID = await storageService.getThemeId();
18+
if (storedThemeID) setThemeID(storedThemeID);
19+
else setThemeID(Themes[0].key);
20+
})();
21+
}, []);
22+
return (
23+
<ThemeContext.Provider value={{ themeID, setThemeID }}>
24+
{!!themeID ? children : null}
25+
</ThemeContext.Provider>
26+
);
27+
};
28+
29+
export function wrapTheme(Component) {
30+
return props => {
31+
const { themeID, setThemeID } = useContext(ThemeContext);
32+
const getTheme = themeID => Themes.find(theme => theme.key === themeID);
33+
const setTheme = themeID => setThemeID(themeID);
34+
35+
return <Component {...props} themes={Themes} theme={getTheme(themeID)}
36+
setTheme={setTheme}/>;
37+
};
38+
}

App/theme/themes.json

Lines changed: 6 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,12 @@
11
[
22
{
3-
"key": "MAASTRICHT BLUE",
4-
"backgroundColor": "#011627",
5-
"color": "#ffffff"
3+
"key": "Light Mode",
4+
"backgroundColor": "white",
5+
"color": "black"
66
},
77
{
8-
"key": "MAXIMUM BLUE GREEN",
9-
"backgroundColor": "#2EC4B6",
10-
"color": "#ffffff"
11-
},
12-
{
13-
"key": "ROSE MADDER",
14-
"backgroundColor": "#E71D36",
15-
"color": "#ffffff"
16-
},
17-
{
18-
"key": "BRIGHT YELLOW (CRAYOLA)",
19-
"backgroundColor": "#FF9F1C",
20-
"color": "#1F2D3D"
8+
"key": "Dark Mode",
9+
"backgroundColor": "#24292e",
10+
"color": "white"
2111
}
2212
]

App/utils/storageService.js

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,27 @@ const getApiKey = async () => {
1414
}
1515
};
1616

17+
const setThemeId = id =>{
18+
AsyncStorage.setItem('theme_id', id);
19+
}
20+
21+
const getThemeId = async () => {
22+
try {
23+
const themeId = await AsyncStorage.getItem('theme_id');
24+
return themeId;
25+
} catch (error) {
26+
return error;
27+
}
28+
};
29+
1730
const clearApiKey = async () => {
1831
await AsyncStorage.removeItem('api_key');
1932
}
2033

2134
export default {
2235
setApiKey,
2336
getApiKey,
24-
clearApiKey
37+
clearApiKey,
38+
setThemeId,
39+
getThemeId
2540
};

0 commit comments

Comments
 (0)