Skip to content

Commit d040d6b

Browse files
committed
Add automatic theming
1 parent 528c5a4 commit d040d6b

File tree

8 files changed

+209
-82
lines changed

8 files changed

+209
-82
lines changed

App.tsx

Lines changed: 89 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -8,89 +8,109 @@
88

99
import 'react-native-gesture-handler';
1010
import React, {Fragment} from 'react';
11+
1112
import {NavigationContainer} from '@react-navigation/native';
1213
import {createBottomTabNavigator} from '@react-navigation/bottom-tabs';
13-
import {connect, ReactReduxContextValue} from 'react-redux';
14+
import {createStackNavigator} from '@react-navigation/stack';
15+
16+
import {connect} from 'react-redux';
17+
import {AppearanceProvider, Appearance} from 'react-native-appearance';
1418
import Icon from 'react-native-vector-icons/MaterialCommunityIcons';
15-
import {
16-
ApplicationProvider,
17-
Layout,
18-
Text,
19-
} from '@ui-kitten/components';
19+
import {ApplicationProvider, Layout, Text} from '@ui-kitten/components';
2020
import {mapping, light as lightTheme, dark as darkTheme} from '@eva-design/eva';
2121
import {SafeAreaView} from 'react-native';
2222

2323
import {K} from './src/store/constants';
2424

2525
import {HomePage} from './src/pages/Home';
2626
import {SettingsPage} from './src/pages/Settings';
27+
import {SettingsToggleThemePage} from './src/pages/SettingsToggleTheme';
2728
import {FindPage} from './src/pages/Find';
29+
import {store} from './index.js';
2830

2931
const Tab = createBottomTabNavigator();
32+
const Stack = createStackNavigator();
33+
34+
const SettingsPageNest = () => {
35+
return (
36+
<Stack.Navigator initialRouteName="Settings" headerMode="none">
37+
<Stack.Screen name="Settings" component={SettingsPage} />
38+
<Stack.Screen name="Theme" component={SettingsToggleThemePage} />
39+
</Stack.Navigator>
40+
);
41+
};
42+
43+
Appearance.addChangeListener(({ colorScheme }) => {
44+
console.log('change');
45+
store.dispatch({type: 'SET_THEME_NATIVE', theme: colorScheme})
46+
});
3047

3148
const App = (props: any) => {
49+
3250
const themeColor = props.theme === 'dark' ? K.color.dark : K.color.light;
3351
return (
34-
<Fragment>
35-
<SafeAreaView
36-
style={{
37-
flex: 0,
38-
backgroundColor:
39-
props.theme === 'dark'
40-
? themeColor.linkBG
41-
: themeColor.linkBG,
42-
}}
43-
/>
44-
<SafeAreaView
45-
style={{
46-
flex: 1,
47-
backgroundColor:
48-
props.theme === 'dark'
49-
? themeColor.secondaryBG
50-
: themeColor.secondaryBG,
51-
}}>
52-
<ApplicationProvider
53-
mapping={mapping}
54-
theme={props.theme === 'dark' ? darkTheme : lightTheme}>
55-
<NavigationContainer>
56-
<Tab.Navigator
57-
initialRouteName={'Home'}
58-
screenOptions={({navigation, route}) => ({
59-
tabBarIcon: ({focused, color, size}) => {
60-
let iconName;
61-
switch (route.name) {
62-
case 'Home':
63-
iconName = focused
64-
? 'home-variant'
65-
: 'home-variant-outline';
66-
break;
67-
case 'Settings':
68-
iconName = focused ? 'settings' : 'settings-outline';
69-
break;
70-
case 'Find':
71-
iconName = focused ? 'map-marker' : 'map-marker-outline';
72-
break;
73-
default:
74-
iconName = 'alert-circle';
75-
}
76-
return <Icon name={iconName} size={size} color={color} />;
77-
},
78-
})}
79-
tabBarOptions={{
80-
activeTintColor: themeColor.contrast,
81-
activeBackgroundColor: themeColor.secondaryBG,
82-
inactiveTintColor: 'gray',
83-
inactiveBackgroundColor: themeColor.secondaryBG,
84-
style: {borderTopColor: themeColor.primaryBG}
85-
}}>
86-
<Tab.Screen name="Find" component={FindPage} />
87-
<Tab.Screen name="Home" component={HomePage} />
88-
<Tab.Screen name="Settings" component={SettingsPage} />
89-
</Tab.Navigator>
90-
</NavigationContainer>
91-
</ApplicationProvider>
92-
</SafeAreaView>
93-
</Fragment>
52+
<AppearanceProvider>
53+
<Fragment>
54+
<SafeAreaView
55+
style={{
56+
flex: 0,
57+
backgroundColor:
58+
props.theme === 'dark' ? themeColor.linkBG : themeColor.linkBG,
59+
}}
60+
/>
61+
<SafeAreaView
62+
style={{
63+
flex: 1,
64+
backgroundColor:
65+
props.theme === 'dark'
66+
? themeColor.secondaryBG
67+
: themeColor.secondaryBG,
68+
}}>
69+
<ApplicationProvider
70+
mapping={mapping}
71+
theme={props.theme === 'dark' ? darkTheme : lightTheme}>
72+
<NavigationContainer>
73+
<Tab.Navigator
74+
initialRouteName={'Home'}
75+
screenOptions={({navigation, route}) => ({
76+
tabBarIcon: ({focused, color, size}) => {
77+
let iconName;
78+
switch (route.name) {
79+
case 'Home':
80+
iconName = focused
81+
? 'home-variant'
82+
: 'home-variant-outline';
83+
break;
84+
case 'Settings':
85+
iconName = focused ? 'settings' : 'settings-outline';
86+
break;
87+
case 'Find':
88+
iconName = focused
89+
? 'map-marker'
90+
: 'map-marker-outline';
91+
break;
92+
default:
93+
iconName = 'alert-circle';
94+
}
95+
return <Icon name={iconName} size={size} color={color} />;
96+
},
97+
})}
98+
tabBarOptions={{
99+
activeTintColor: themeColor.contrast,
100+
activeBackgroundColor: themeColor.secondaryBG,
101+
inactiveTintColor: 'gray',
102+
inactiveBackgroundColor: themeColor.secondaryBG,
103+
style: {borderTopColor: themeColor.primaryBG},
104+
}}>
105+
<Tab.Screen name="Find" component={FindPage} />
106+
<Tab.Screen name="Home" component={HomePage} />
107+
<Tab.Screen name="Settings" component={SettingsPageNest} />
108+
</Tab.Navigator>
109+
</NavigationContainer>
110+
</ApplicationProvider>
111+
</SafeAreaView>
112+
</Fragment>
113+
</AppearanceProvider>
94114
);
95115
};
96116

@@ -101,7 +121,9 @@ const mapStateToProps = (state: any) => {
101121
};
102122

103123
const mapDispatchToProps = (dispatch: any) => {
104-
return {};
124+
return {
125+
setThemeNative: (theme: string) => dispatch({type: 'SET_THEME_NATIVE', theme: theme}),
126+
};
105127
};
106128

107129
export default connect(mapStateToProps, mapDispatchToProps)(App);

index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import { Provider } from 'react-redux';
1111
import { createStore } from 'redux';
1212
import { reducer } from './src/store/reducer';
1313

14-
const store = createStore(reducer);
14+
export const store = createStore(reducer);
1515

1616
const RenderApp = () => {
1717
return (

ios/Podfile.lock

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,8 @@ PODS:
182182
- React-cxxreact (= 0.61.5)
183183
- React-jsi (= 0.61.5)
184184
- React-jsinspector (0.61.5)
185+
- react-native-appearance (0.3.3):
186+
- React
185187
- react-native-safe-area-context (0.7.3):
186188
- React
187189
- React-RCTActionSheet (0.61.5):
@@ -250,6 +252,7 @@ DEPENDENCIES:
250252
- React-jsi (from `../node_modules/react-native/ReactCommon/jsi`)
251253
- React-jsiexecutor (from `../node_modules/react-native/ReactCommon/jsiexecutor`)
252254
- React-jsinspector (from `../node_modules/react-native/ReactCommon/jsinspector`)
255+
- react-native-appearance (from `../node_modules/react-native-appearance`)
253256
- react-native-safe-area-context (from `../node_modules/react-native-safe-area-context`)
254257
- React-RCTActionSheet (from `../node_modules/react-native/Libraries/ActionSheetIOS`)
255258
- React-RCTAnimation (from `../node_modules/react-native/Libraries/NativeAnimation`)
@@ -303,6 +306,8 @@ EXTERNAL SOURCES:
303306
:path: "../node_modules/react-native/ReactCommon/jsiexecutor"
304307
React-jsinspector:
305308
:path: "../node_modules/react-native/ReactCommon/jsinspector"
309+
react-native-appearance:
310+
:path: "../node_modules/react-native-appearance"
306311
react-native-safe-area-context:
307312
:path: "../node_modules/react-native-safe-area-context"
308313
React-RCTActionSheet:
@@ -356,6 +361,7 @@ SPEC CHECKSUMS:
356361
React-jsi: cb2cd74d7ccf4cffb071a46833613edc79cdf8f7
357362
React-jsiexecutor: d5525f9ed5f782fdbacb64b9b01a43a9323d2386
358363
React-jsinspector: fa0ecc501688c3c4c34f28834a76302233e29dc0
364+
react-native-appearance: ff12122b6456efc29b3a22a3731eb54f7c291e69
359365
react-native-safe-area-context: 8260e5157617df4b72865f44006797f895b2ada7
360366
React-RCTActionSheet: 600b4d10e3aea0913b5a92256d2719c0cdd26d76
361367
React-RCTAnimation: 791a87558389c80908ed06cc5dfc5e7920dfa360

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,11 @@
1414
"@react-native-community/masked-view": "^0.1.7",
1515
"@react-navigation/bottom-tabs": "^5.1.1",
1616
"@react-navigation/native": "^5.0.9",
17+
"@react-navigation/stack": "^5.2.1",
1718
"@ui-kitten/components": "^4.4.1",
1819
"react": "16.9.0",
1920
"react-native": "0.61.5",
21+
"react-native-appearance": "^0.3.3",
2022
"react-native-gesture-handler": "^1.6.0",
2123
"react-native-modals": "^0.19.9",
2224
"react-native-reanimated": "^1.7.0",

src/pages/Home/index.tsx

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import React from 'react';
2+
import {ScrollView} from 'react-native';
23
import {connect} from 'react-redux';
34
import {Layout, Text} from '@ui-kitten/components';
45

@@ -8,14 +9,16 @@ import {ViewShadow} from '../../components/Shadow/View';
89
const HomePageC = (props: any) => {
910
return (
1011
<Layout style={{height: '100%'}}>
11-
<PageHeader title="Home" theme={props.theme} />
12-
<Layout style={{marginHorizontal: 20}}>
13-
<ViewShadow theme={props.theme} style={{marginTop: -20}}>
14-
<Layout style={{overflow: 'hidden', borderRadius: 20}}>
15-
<Text>Home</Text>
16-
</Layout>
17-
</ViewShadow>
18-
</Layout>
12+
<ScrollView>
13+
<PageHeader title="Home" theme={props.theme} />
14+
<Layout style={{marginHorizontal: 20}}>
15+
<ViewShadow theme={props.theme} style={{marginTop: -20}}>
16+
<Layout style={{overflow: 'hidden', borderRadius: 20}}>
17+
<Text>Home</Text>
18+
</Layout>
19+
</ViewShadow>
20+
</Layout>
21+
</ScrollView>
1922
</Layout>
2023
);
2124
};

src/pages/Settings/index.tsx

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,13 @@ import {K} from '../../store/constants';
1212
import {PageHeader} from '../../components/Page/PageHeader';
1313
import {ViewShadow} from '../../components/Shadow/View';
1414

15-
const SettingsPageC = (props: any) => {
15+
const SettingsPageC = (props: any, {navigation}) => {
1616
const themeColor = props.theme === 'dark' ? K.color.dark : K.color.light;
1717

1818
const list1 = [
1919
{
20-
title: 'Toggle theme',
21-
onPress: () => {
22-
props.toggleTheme();
23-
},
20+
title: 'Change Theme',
21+
onPress: () => {props.navigation.navigate('Theme')},
2422
},
2523
{
2624
title: 'Privacy',
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
import React from 'react';
2+
import {Layout, List, ListItem, Text} from '@ui-kitten/components';
3+
import {connect} from 'react-redux';
4+
import Icon from 'react-native-vector-icons/MaterialCommunityIcons';
5+
6+
import {K} from '../../store/constants';
7+
import {PageHeader} from '../../components/Page/PageHeader';
8+
import {ViewShadow} from '../../components/Shadow/View';
9+
import { View } from 'react-native';
10+
11+
const SettingsToggleThemePageC = (props: any) => {
12+
const themeColor = props.theme === 'dark' ? K.color.dark : K.color.light;
13+
14+
const list = [
15+
{
16+
title: 'Automatic',
17+
onPress: () => {props.setThemeMode('auto')},
18+
selected: props.themeMode === 'auto'
19+
},
20+
{
21+
title: 'Dark',
22+
onPress: () => {props.setThemeMode('dark')},
23+
selected: props.themeMode === 'dark'
24+
},
25+
{
26+
title: 'Light',
27+
onPress: () => {props.setThemeMode('light')},
28+
selected: props.themeMode === 'light'
29+
},
30+
];
31+
32+
const renderItem = ({item, index}) => {
33+
let selectedStyle;
34+
if (item.selected) {
35+
selectedStyle = {backgroundColor: themeColor.secondaryBG}
36+
}
37+
return (
38+
<ListItem
39+
title={`${item.title}`}
40+
onPress={item.onPress}
41+
style={{height: 50, ...selectedStyle}}
42+
icon={() => item.selected ? <Icon name={'checkbox-marked-circle'} size={20} color={themeColor.contrast} style={{position: "absolute", right: 10, top: 15}} /> : <View style={{width: 0, marginHorizontal: 0, paddingHorizontal: 0}}/>}
43+
/>
44+
);
45+
};
46+
47+
return (
48+
<Layout style={{height: '100%', flex: 1}}>
49+
<PageHeader title="Theme" theme={props.theme} />
50+
<Layout style={{marginHorizontal: 20}}>
51+
<ViewShadow theme={props.theme} style={{height: 150, marginTop: -20}}>
52+
<List
53+
data={list}
54+
renderItem={renderItem}
55+
scrollEnabled={false}
56+
style={{borderRadius: 20, overflow: 'hidden'}}
57+
/>
58+
</ViewShadow>
59+
</Layout>
60+
</Layout>
61+
);
62+
};
63+
64+
const mapStateToProps = (state: any) => {
65+
return {
66+
theme: state.theme,
67+
themeMode: state.themeMode,
68+
themeNative: state.themeNative
69+
};
70+
};
71+
72+
const mapDispatchToProps = (dispatch: any) => {
73+
return {
74+
toggleTheme: () => dispatch({type: 'TOGGLE_THEME'}),
75+
setThemeMode: (setTo) => dispatch({type: 'SET_THEME_MODE', setTo: setTo}),
76+
};
77+
};
78+
79+
export const SettingsToggleThemePage = connect(
80+
mapStateToProps,
81+
mapDispatchToProps,
82+
)(SettingsToggleThemePageC);

0 commit comments

Comments
 (0)