mirror of https://gitlab.com/ceda_ei/sonzai.git
Add Theme Picker.
Moved Provider into App.js. Add AppContainer to store theme in redux store. Add reducers and actions for theme, SET_THEME.
This commit is contained in:
parent
635dbbf709
commit
0103e6abff
96
App.js
96
App.js
|
@ -1,20 +1,22 @@
|
||||||
/**
|
|
||||||
* Sample React Native App
|
|
||||||
* https://github.com/facebook/react-native
|
|
||||||
*
|
|
||||||
* @format
|
|
||||||
* @flow
|
|
||||||
*/
|
|
||||||
|
|
||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
|
import PropTypes from "prop-types";
|
||||||
import {
|
import {
|
||||||
Appbar,
|
Appbar,
|
||||||
BottomNavigation,
|
BottomNavigation,
|
||||||
Text,
|
Text,
|
||||||
Card,
|
Card,
|
||||||
|
Dialog,
|
||||||
|
Portal,
|
||||||
|
Button,
|
||||||
|
Provider,
|
||||||
|
RadioButton,
|
||||||
|
TouchableRipple
|
||||||
} from "react-native-paper";
|
} from "react-native-paper";
|
||||||
|
|
||||||
|
import { View, StatusBar, StyleSheet } from "react-native";
|
||||||
|
|
||||||
import SubjectsContainer from "./containers/SubjectsContainer";
|
import SubjectsContainer from "./containers/SubjectsContainer";
|
||||||
|
import themes from "./themes";
|
||||||
|
|
||||||
|
|
||||||
function Dummy() {
|
function Dummy() {
|
||||||
|
@ -28,7 +30,32 @@ function Dummy() {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const App = () => {
|
function ThemePicker({ onPress, selectionIdx }) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{themes.map((t, idx) => (
|
||||||
|
<TouchableRipple
|
||||||
|
onPress={() => onPress(t, idx)}
|
||||||
|
key={idx}
|
||||||
|
>
|
||||||
|
<View style={styles.radio}>
|
||||||
|
<RadioButton
|
||||||
|
status={selectionIdx === idx ? "checked": "unchecked"}
|
||||||
|
/>
|
||||||
|
<Text>{t.name}</Text>
|
||||||
|
</View>
|
||||||
|
</TouchableRipple>
|
||||||
|
))}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
ThemePicker.propTypes = {
|
||||||
|
onPress: PropTypes.func,
|
||||||
|
selectionIdx: PropTypes.number,
|
||||||
|
};
|
||||||
|
|
||||||
|
const App = ({ theme, setTheme }) => {
|
||||||
const [ pane, setPane ] = useState({
|
const [ pane, setPane ] = useState({
|
||||||
index: 0,
|
index: 0,
|
||||||
routes: [
|
routes: [
|
||||||
|
@ -38,18 +65,39 @@ const App = () => {
|
||||||
{ key: "subjects", title: "Subjects", icon: "book-open" },
|
{ key: "subjects", title: "Subjects", icon: "book-open" },
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
const [ showDialog, setShowDialog ] = useState(false);
|
||||||
|
const [ newTheme, setNewTheme ] = useState(themes.findIndex(
|
||||||
|
i => JSON.stringify(i.theme) === JSON.stringify(theme)
|
||||||
|
));
|
||||||
const renderScene = BottomNavigation.SceneMap({
|
const renderScene = BottomNavigation.SceneMap({
|
||||||
add: Dummy,
|
add: Dummy,
|
||||||
statistics: Dummy,
|
statistics: Dummy,
|
||||||
timetable: Dummy,
|
timetable: Dummy,
|
||||||
subjects: SubjectsContainer,
|
subjects: SubjectsContainer,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function dialogSelection(theme, idx) {
|
||||||
|
setNewTheme(idx);
|
||||||
|
setTheme(theme.theme);
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
<StatusBar
|
||||||
|
backgroundColor={
|
||||||
|
theme.dark && theme.mode === "adaptive" ?
|
||||||
|
theme.colors.surface :
|
||||||
|
theme.colors.primary
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<Provider theme={theme}>
|
||||||
<Appbar.Header>
|
<Appbar.Header>
|
||||||
<Appbar.Content
|
<Appbar.Content
|
||||||
title="Sonzai"
|
title="Sonzai"
|
||||||
/>
|
/>
|
||||||
|
<Appbar.Action
|
||||||
|
icon="brush"
|
||||||
|
onPress={() => setShowDialog(true)}
|
||||||
|
/>
|
||||||
</Appbar.Header>
|
</Appbar.Header>
|
||||||
<BottomNavigation
|
<BottomNavigation
|
||||||
navigationState={pane}
|
navigationState={pane}
|
||||||
|
@ -60,8 +108,38 @@ const App = () => {
|
||||||
renderScene={renderScene}
|
renderScene={renderScene}
|
||||||
shifting={true}
|
shifting={true}
|
||||||
/>
|
/>
|
||||||
|
<Portal>
|
||||||
|
<Dialog
|
||||||
|
visible={showDialog}
|
||||||
|
onDismiss={() => setShowDialog(false)}>
|
||||||
|
<Dialog.Title>Theme</Dialog.Title>
|
||||||
|
<Dialog.Content>
|
||||||
|
<ThemePicker
|
||||||
|
onPress={dialogSelection}
|
||||||
|
selectionIdx={newTheme}
|
||||||
|
/>
|
||||||
|
</Dialog.Content>
|
||||||
|
<Dialog.Actions>
|
||||||
|
<Button onPress={() => setShowDialog(false)}>Close</Button>
|
||||||
|
</Dialog.Actions>
|
||||||
|
</Dialog>
|
||||||
|
</Portal>
|
||||||
|
</Provider>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
App.propTypes = {
|
||||||
|
theme: PropTypes.object,
|
||||||
|
setTheme: PropTypes.func,
|
||||||
|
};
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
radio: {
|
||||||
|
flexDirection: "row",
|
||||||
|
alignItems: "center",
|
||||||
|
margin: 5
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
export default App;
|
export default App;
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
import { connect } from "react-redux";
|
||||||
|
import App from "./App";
|
||||||
|
import { setTheme } from "./actions";
|
||||||
|
|
||||||
|
const mapStateToProps = state => {
|
||||||
|
return {
|
||||||
|
theme: state.theme,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const mapDispatchToProps = dispatch => {
|
||||||
|
return {
|
||||||
|
setTheme: theme => dispatch(setTheme(theme))
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const AppContainer = connect(mapStateToProps, mapDispatchToProps)(App);
|
||||||
|
|
||||||
|
export default AppContainer;
|
|
@ -13,3 +13,10 @@ export function removeSubject(id) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export function setTheme(theme) {
|
||||||
|
return {
|
||||||
|
type: "SET_THEME",
|
||||||
|
theme: theme,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
|
@ -67,6 +67,8 @@ Subjects.propTypes = {
|
||||||
const style = StyleSheet.create({
|
const style = StyleSheet.create({
|
||||||
card: {
|
card: {
|
||||||
marginTop: 12,
|
marginTop: 12,
|
||||||
|
marginLeft: 10,
|
||||||
|
marginRight: 10,
|
||||||
},
|
},
|
||||||
text: {
|
text: {
|
||||||
marginTop: 12,
|
marginTop: 12,
|
||||||
|
|
26
index.js
26
index.js
|
@ -1,40 +1,18 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import {AppRegistry} from "react-native";
|
import {AppRegistry} from "react-native";
|
||||||
import App from "./App";
|
import AppContainer from "./AppContainer";
|
||||||
import {name as appName} from "./app.json";
|
import {name as appName} from "./app.json";
|
||||||
import { DarkTheme, Provider } from "react-native-paper";
|
|
||||||
import { Provider as ReduxProvider } from "react-redux";
|
import { Provider as ReduxProvider } from "react-redux";
|
||||||
import { PersistGate } from "redux-persist/integration/react";
|
import { PersistGate } from "redux-persist/integration/react";
|
||||||
|
|
||||||
import configureStore from "./configureStore";
|
import configureStore from "./configureStore";
|
||||||
const { store, persistor } = configureStore();
|
const { store, persistor } = configureStore();
|
||||||
|
|
||||||
const theme = {
|
|
||||||
...DarkTheme,
|
|
||||||
mode: "exact",
|
|
||||||
colors: {
|
|
||||||
primary: "#ededed",
|
|
||||||
accent: "#1a237e",
|
|
||||||
backdrop: "rgba(0, 0, 0, 0.5)",
|
|
||||||
background: "#000000",
|
|
||||||
disabled: "rgba(255, 255, 255, 0.38)",
|
|
||||||
error: "#CF6679",
|
|
||||||
notification: "#ff80ab",
|
|
||||||
onBackground: "#FFFFFF",
|
|
||||||
onSurface: "#FFFFFF",
|
|
||||||
placeholder: "rgba(255, 255, 255, 0.54)",
|
|
||||||
surface: "#121212",
|
|
||||||
text: "#ffffff"
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export default function Main() {
|
export default function Main() {
|
||||||
return (
|
return (
|
||||||
<ReduxProvider store={store}>
|
<ReduxProvider store={store}>
|
||||||
<PersistGate persistor={persistor}>
|
<PersistGate persistor={persistor}>
|
||||||
<Provider theme={theme}>
|
<AppContainer />
|
||||||
<App />
|
|
||||||
</Provider>
|
|
||||||
</PersistGate>
|
</PersistGate>
|
||||||
</ReduxProvider>
|
</ReduxProvider>
|
||||||
);
|
);
|
||||||
|
|
|
@ -3,11 +3,13 @@ import { combineReducers } from "redux";
|
||||||
import timetable from "./timetable";
|
import timetable from "./timetable";
|
||||||
import classes from "./classes";
|
import classes from "./classes";
|
||||||
import subjects from "./subjects";
|
import subjects from "./subjects";
|
||||||
|
import theme from "./theme";
|
||||||
|
|
||||||
const rootReducer = combineReducers({
|
const rootReducer = combineReducers({
|
||||||
timetable,
|
timetable,
|
||||||
classes,
|
classes,
|
||||||
subjects,
|
subjects,
|
||||||
|
theme,
|
||||||
});
|
});
|
||||||
|
|
||||||
export default rootReducer;
|
export default rootReducer;
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
import themes from "../themes";
|
||||||
|
export default function theme(state, action) {
|
||||||
|
if (typeof state === "undefined")
|
||||||
|
return themes[0].theme;
|
||||||
|
if (action.type === "SET_THEME") {
|
||||||
|
return action.theme;
|
||||||
|
}
|
||||||
|
return state;
|
||||||
|
}
|
|
@ -0,0 +1,119 @@
|
||||||
|
import { DefaultTheme, DarkTheme } from "react-native-paper";
|
||||||
|
export default [
|
||||||
|
{
|
||||||
|
"name": "Dark: Pink and Gray",
|
||||||
|
"theme": {
|
||||||
|
...DarkTheme,
|
||||||
|
mode: "exact",
|
||||||
|
colors: {
|
||||||
|
primary: "#ff1744",
|
||||||
|
accent: "#e0e0e0",
|
||||||
|
backdrop: "rgba(0, 0, 0, 0.5)",
|
||||||
|
background: "#000000",
|
||||||
|
disabled: "rgba(255, 255, 255, 0.38)",
|
||||||
|
error: "#CF6679",
|
||||||
|
notification: "#ff80ab",
|
||||||
|
onBackground: "#FFFFFF",
|
||||||
|
onSurface: "#FFFFFF",
|
||||||
|
placeholder: "rgba(255, 255, 255, 0.54)",
|
||||||
|
surface: "#121212",
|
||||||
|
text: "#ffffff"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Dark: Pastel Colors",
|
||||||
|
"theme": {
|
||||||
|
...DarkTheme,
|
||||||
|
mode: "exact",
|
||||||
|
colors: {
|
||||||
|
primary: "#ef9a9a",
|
||||||
|
accent: "#fce4ec",
|
||||||
|
backdrop: "rgba(0, 0, 0, 0.5)",
|
||||||
|
background: "#000000",
|
||||||
|
disabled: "rgba(255, 255, 255, 0.38)",
|
||||||
|
error: "#CF6679",
|
||||||
|
notification: "#ff80ab",
|
||||||
|
onBackground: "#FFFFFF",
|
||||||
|
onSurface: "#FFFFFF",
|
||||||
|
placeholder: "rgba(255, 255, 255, 0.54)",
|
||||||
|
surface: "#121212",
|
||||||
|
text: "#ffffff"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Dark: Pastel Colors 2",
|
||||||
|
"theme": {
|
||||||
|
...DarkTheme,
|
||||||
|
mode: "exact",
|
||||||
|
colors: {
|
||||||
|
primary: "#e0f7fa",
|
||||||
|
accent: "#ffebee",
|
||||||
|
backdrop: "rgba(0, 0, 0, 0.5)",
|
||||||
|
background: "#000000",
|
||||||
|
disabled: "rgba(255, 255, 255, 0.38)",
|
||||||
|
error: "#CF6679",
|
||||||
|
notification: "#ff80ab",
|
||||||
|
onBackground: "#FFFFFF",
|
||||||
|
onSurface: "#FFFFFF",
|
||||||
|
placeholder: "rgba(255, 255, 255, 0.54)",
|
||||||
|
surface: "#121212",
|
||||||
|
text: "#ffffff"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Absolute Dark: Pink and Gray",
|
||||||
|
"theme": {
|
||||||
|
...DarkTheme,
|
||||||
|
colors: {
|
||||||
|
...DarkTheme.colors,
|
||||||
|
primary: "#ff1744",
|
||||||
|
accent: "#e0e0e0",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Absolute Dark: Purple and Gray",
|
||||||
|
"theme": DarkTheme
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Light: Pink and Gray",
|
||||||
|
"theme": {
|
||||||
|
...DefaultTheme,
|
||||||
|
colors: {
|
||||||
|
...DefaultTheme.colors,
|
||||||
|
primary: "#ff1744",
|
||||||
|
accent: "#e0e0e0",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Light: Pastel Colors",
|
||||||
|
"theme": {
|
||||||
|
...DefaultTheme,
|
||||||
|
mode: "exact",
|
||||||
|
colors: {
|
||||||
|
...DefaultTheme.colors,
|
||||||
|
primary: "#ef9a9a",
|
||||||
|
accent: "#fce4ec",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Light: Pastel Colors 2",
|
||||||
|
"theme": {
|
||||||
|
...DefaultTheme,
|
||||||
|
colors: {
|
||||||
|
...DefaultTheme.colors,
|
||||||
|
primary: "#ffcccb",
|
||||||
|
accent: "#fce4ec",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Light: Purple and Green",
|
||||||
|
"theme": DefaultTheme
|
||||||
|
},
|
||||||
|
];
|
Loading…
Reference in New Issue