mirror of
https://github.com/zhigang1992/react-navigation.git
synced 2026-02-12 22:30:36 +08:00
feat: add custom theme support (#211)
This commit is contained in:
@@ -1,5 +1,4 @@
|
||||
import * as React from 'react';
|
||||
import { StyleSheet } from 'react-native';
|
||||
import { createMaterialTopTabNavigator } from '@react-navigation/material-top-tabs';
|
||||
import Albums from '../Shared/Albums';
|
||||
import Contacts from '../Shared/Contacts';
|
||||
@@ -15,13 +14,7 @@ const MaterialTopTabs = createMaterialTopTabNavigator<MaterialTopTabParams>();
|
||||
|
||||
export default function MaterialTopTabsScreen() {
|
||||
return (
|
||||
<MaterialTopTabs.Navigator
|
||||
tabBarOptions={{
|
||||
style: styles.tabBar,
|
||||
labelStyle: styles.tabLabel,
|
||||
indicatorStyle: styles.tabIndicator,
|
||||
}}
|
||||
>
|
||||
<MaterialTopTabs.Navigator>
|
||||
<MaterialTopTabs.Screen
|
||||
name="chat"
|
||||
component={Chat}
|
||||
@@ -40,15 +33,3 @@ export default function MaterialTopTabsScreen() {
|
||||
</MaterialTopTabs.Navigator>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
tabBar: {
|
||||
backgroundColor: 'white',
|
||||
},
|
||||
tabLabel: {
|
||||
color: 'black',
|
||||
},
|
||||
tabIndicator: {
|
||||
backgroundColor: 'tomato',
|
||||
},
|
||||
});
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
RouteProp,
|
||||
ParamListBase,
|
||||
useFocusEffect,
|
||||
useTheme,
|
||||
} from '@react-navigation/native';
|
||||
import { DrawerNavigationProp } from '@react-navigation/drawer';
|
||||
import { StackNavigationProp } from '@react-navigation/stack';
|
||||
@@ -23,90 +24,113 @@ type NativeStackParams = {
|
||||
|
||||
type NativeStackNavigation = NativeStackNavigationProp<NativeStackParams>;
|
||||
|
||||
const Title = ({ children }: { children: React.ReactNode }) => {
|
||||
const { colors } = useTheme();
|
||||
|
||||
return <Text style={[styles.title, { color: colors.text }]}>{children}</Text>;
|
||||
};
|
||||
|
||||
const Paragraph = ({ children }: { children: React.ReactNode }) => {
|
||||
const { colors } = useTheme();
|
||||
|
||||
return (
|
||||
<Text style={[styles.paragraph, { color: colors.text }]}>{children}</Text>
|
||||
);
|
||||
};
|
||||
|
||||
const ArticleScreen = ({
|
||||
navigation,
|
||||
}: {
|
||||
navigation: NativeStackNavigation;
|
||||
route: RouteProp<NativeStackParams, 'article'>;
|
||||
}) => (
|
||||
<ScrollView style={styles.container} contentContainerStyle={styles.content}>
|
||||
<View style={styles.buttons}>
|
||||
<Button
|
||||
mode="contained"
|
||||
onPress={() => navigation.push('album')}
|
||||
style={styles.button}
|
||||
>
|
||||
Push album
|
||||
</Button>
|
||||
<Button
|
||||
mode="outlined"
|
||||
onPress={() => navigation.goBack()}
|
||||
style={styles.button}
|
||||
>
|
||||
Go back
|
||||
</Button>
|
||||
</View>
|
||||
<Text style={styles.title}>What is Lorem Ipsum?</Text>
|
||||
<Text style={styles.paragraph}>
|
||||
Lorem Ipsum is simply dummy text of the printing and typesetting industry.
|
||||
Lorem Ipsum has been the industry's standard dummy text ever since
|
||||
the 1500s, when an unknown printer took a galley of type and scrambled it
|
||||
to make a type specimen book. It has survived not only five centuries, but
|
||||
also the leap into electronic typesetting, remaining essentially
|
||||
unchanged. It was popularised in the 1960s with the release of Letraset
|
||||
sheets containing Lorem Ipsum passages, and more recently with desktop
|
||||
publishing software like Aldus PageMaker including versions of Lorem
|
||||
Ipsum.
|
||||
</Text>
|
||||
<Text style={styles.title}>Where does it come from?</Text>
|
||||
<Text style={styles.paragraph}>
|
||||
Contrary to popular belief, Lorem Ipsum is not simply random text. It has
|
||||
roots in a piece of classical Latin literature from 45 BC, making it over
|
||||
2000 years old. Richard McClintock, a Latin professor at Hampden-Sydney
|
||||
College in Virginia, looked up one of the more obscure Latin words,
|
||||
consectetur, from a Lorem Ipsum passage, and going through the cites of
|
||||
the word in classical literature, discovered the undoubtable source. Lorem
|
||||
Ipsum comes from sections 1.10.32 and 1.10.33 of "de Finibus Bonorum
|
||||
et Malorum" (The Extremes of Good and Evil) by Cicero, written in 45
|
||||
BC. This book is a treatise on the theory of ethics, very popular during
|
||||
the Renaissance. The first line of Lorem Ipsum, "Lorem ipsum dolor
|
||||
sit amet..", comes from a line in section 1.10.32.
|
||||
</Text>
|
||||
<Text style={styles.paragraph}>
|
||||
The standard chunk of Lorem Ipsum used since the 1500s is reproduced below
|
||||
for those interested. Sections 1.10.32 and 1.10.33 from "de Finibus
|
||||
Bonorum et Malorum" by Cicero are also reproduced in their exact
|
||||
original form, accompanied by English versions from the 1914 translation
|
||||
by H. Rackham.
|
||||
</Text>
|
||||
<Text style={styles.title}>Why do we use it?</Text>
|
||||
<Text style={styles.paragraph}>
|
||||
It is a long established fact that a reader will be distracted by the
|
||||
readable content of a page when looking at its layout. The point of using
|
||||
Lorem Ipsum is that it has a more-or-less normal distribution of letters,
|
||||
as opposed to using "Content here, content here", making it look
|
||||
like readable English. Many desktop publishing packages and web page
|
||||
editors now use Lorem Ipsum as their default model text, and a search for
|
||||
"lorem ipsum" will uncover many web sites still in their
|
||||
infancy. Various versions have evolved over the years, sometimes by
|
||||
accident, sometimes on purpose (injected humour and the like).
|
||||
</Text>
|
||||
<Text style={styles.title}>Where can I get some?</Text>
|
||||
<Text style={styles.paragraph}>
|
||||
There are many variations of passages of Lorem Ipsum available, but the
|
||||
majority have suffered alteration in some form, by injected humour, or
|
||||
randomised words which don't look even slightly believable. If you
|
||||
are going to use a passage of Lorem Ipsum, you need to be sure there
|
||||
isn't anything embarrassing hidden in the middle of text. All the
|
||||
Lorem Ipsum generators on the Internet tend to repeat predefined chunks as
|
||||
necessary, making this the first true generator on the Internet. It uses a
|
||||
dictionary of over 200 Latin words, combined with a handful of model
|
||||
sentence structures, to generate Lorem Ipsum which looks reasonable. The
|
||||
generated Lorem Ipsum is therefore always free from repetition, injected
|
||||
humour, or non-characteristic words etc.
|
||||
</Text>
|
||||
</ScrollView>
|
||||
);
|
||||
}) => {
|
||||
const { colors } = useTheme();
|
||||
|
||||
return (
|
||||
<ScrollView
|
||||
style={{ backgroundColor: colors.card }}
|
||||
contentContainerStyle={styles.content}
|
||||
>
|
||||
<View style={styles.buttons}>
|
||||
<Button
|
||||
mode="contained"
|
||||
onPress={() => navigation.push('album')}
|
||||
style={styles.button}
|
||||
>
|
||||
Push album
|
||||
</Button>
|
||||
<Button
|
||||
mode="outlined"
|
||||
onPress={() => navigation.goBack()}
|
||||
style={styles.button}
|
||||
>
|
||||
Go back
|
||||
</Button>
|
||||
</View>
|
||||
<Title>What is Lorem Ipsum?</Title>
|
||||
<Paragraph>
|
||||
Lorem Ipsum is simply dummy text of the printing and typesetting
|
||||
industry. Lorem Ipsum has been the industry's standard dummy text
|
||||
ever since the 1500s, when an unknown printer took a galley of type and
|
||||
scrambled it to make a type specimen book. It has survived not only five
|
||||
centuries, but also the leap into electronic typesetting, remaining
|
||||
essentially unchanged. It was popularised in the 1960s with the release
|
||||
of Letraset sheets containing Lorem Ipsum passages, and more recently
|
||||
with desktop publishing software like Aldus PageMaker including versions
|
||||
of Lorem Ipsum.
|
||||
</Paragraph>
|
||||
<Title>Where does it come from?</Title>
|
||||
<Paragraph>
|
||||
Contrary to popular belief, Lorem Ipsum is not simply random text. It
|
||||
has roots in a piece of classical Latin literature from 45 BC, making it
|
||||
over 2000 years old. Richard McClintock, a Latin professor at
|
||||
Hampden-Sydney College in Virginia, looked up one of the more obscure
|
||||
Latin words, consectetur, from a Lorem Ipsum passage, and going through
|
||||
the cites of the word in classical literature, discovered the
|
||||
undoubtable source. Lorem Ipsum comes from sections 1.10.32 and 1.10.33
|
||||
of "de Finibus Bonorum et Malorum" (The Extremes of Good and
|
||||
Evil) by Cicero, written in 45 BC. This book is a treatise on the theory
|
||||
of ethics, very popular during the Renaissance. The first line of Lorem
|
||||
Ipsum, "Lorem ipsum dolor sit amet..", comes from a line in
|
||||
section 1.10.32.
|
||||
</Paragraph>
|
||||
<Paragraph>
|
||||
The standard chunk of Lorem Ipsum used since the 1500s is reproduced
|
||||
below for those interested. Sections 1.10.32 and 1.10.33 from "de
|
||||
Finibus Bonorum et Malorum" by Cicero are also reproduced in their
|
||||
exact original form, accompanied by English versions from the 1914
|
||||
translation by H. Rackham.
|
||||
</Paragraph>
|
||||
<Title>Why do we use it?</Title>
|
||||
<Paragraph>
|
||||
It is a long established fact that a reader will be distracted by the
|
||||
readable content of a page when looking at its layout. The point of
|
||||
using Lorem Ipsum is that it has a more-or-less normal distribution of
|
||||
letters, as opposed to using "Content here, content here",
|
||||
making it look like readable English. Many desktop publishing packages
|
||||
and web page editors now use Lorem Ipsum as their default model text,
|
||||
and a search for "lorem ipsum" will uncover many web sites
|
||||
still in their infancy. Various versions have evolved over the years,
|
||||
sometimes by accident, sometimes on purpose (injected humour and the
|
||||
like).
|
||||
</Paragraph>
|
||||
<Title>Where can I get some?</Title>
|
||||
<Paragraph>
|
||||
There are many variations of passages of Lorem Ipsum available, but the
|
||||
majority have suffered alteration in some form, by injected humour, or
|
||||
randomised words which don't look even slightly believable. If you
|
||||
are going to use a passage of Lorem Ipsum, you need to be sure there
|
||||
isn't anything embarrassing hidden in the middle of text. All the
|
||||
Lorem Ipsum generators on the Internet tend to repeat predefined chunks
|
||||
as necessary, making this the first true generator on the Internet. It
|
||||
uses a dictionary of over 200 Latin words, combined with a handful of
|
||||
model sentence structures, to generate Lorem Ipsum which looks
|
||||
reasonable. The generated Lorem Ipsum is therefore always free from
|
||||
repetition, injected humour, or non-characteristic words etc.
|
||||
</Paragraph>
|
||||
</ScrollView>
|
||||
);
|
||||
};
|
||||
|
||||
const AlbumsScreen = ({
|
||||
navigation,
|
||||
@@ -191,21 +215,16 @@ const styles = StyleSheet.create({
|
||||
button: {
|
||||
margin: 8,
|
||||
},
|
||||
container: {
|
||||
backgroundColor: 'white',
|
||||
},
|
||||
content: {
|
||||
paddingVertical: 16,
|
||||
},
|
||||
title: {
|
||||
color: '#000',
|
||||
fontWeight: 'bold',
|
||||
fontSize: 24,
|
||||
marginVertical: 8,
|
||||
marginHorizontal: 16,
|
||||
},
|
||||
paragraph: {
|
||||
color: '#000',
|
||||
fontSize: 16,
|
||||
lineHeight: 24,
|
||||
marginVertical: 8,
|
||||
|
||||
@@ -38,7 +38,7 @@ export default function Albums() {
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
backgroundColor: '#343C46',
|
||||
backgroundColor: '#000',
|
||||
},
|
||||
content: {
|
||||
flexDirection: 'row',
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import * as React from 'react';
|
||||
import { View, Text, Image, ScrollView, StyleSheet } from 'react-native';
|
||||
import { useScrollToTop } from '@react-navigation/native';
|
||||
import { useScrollToTop, useTheme } from '@react-navigation/native';
|
||||
|
||||
type Props = {
|
||||
date?: string;
|
||||
@@ -19,10 +19,12 @@ export default function Article({
|
||||
|
||||
useScrollToTop(ref);
|
||||
|
||||
const { colors } = useTheme();
|
||||
|
||||
return (
|
||||
<ScrollView
|
||||
ref={ref}
|
||||
style={styles.container}
|
||||
style={{ backgroundColor: colors.card }}
|
||||
contentContainerStyle={styles.content}
|
||||
>
|
||||
<View style={styles.author}>
|
||||
@@ -31,24 +33,26 @@ export default function Article({
|
||||
source={require('../../assets/avatar-1.png')}
|
||||
/>
|
||||
<View style={styles.meta}>
|
||||
<Text style={styles.name}>{author.name}</Text>
|
||||
<Text style={styles.timestamp}>{date}</Text>
|
||||
<Text style={[styles.name, { color: colors.text }]}>
|
||||
{author.name}
|
||||
</Text>
|
||||
<Text style={[styles.timestamp, { color: colors.text }]}>{date}</Text>
|
||||
</View>
|
||||
</View>
|
||||
<Text style={styles.title}>Lorem Ipsum</Text>
|
||||
<Text style={styles.paragraph}>
|
||||
<Text style={[styles.title, { color: colors.text }]}>Lorem Ipsum</Text>
|
||||
<Text style={[styles.paragraph, { color: colors.text }]}>
|
||||
Contrary to popular belief, Lorem Ipsum is not simply random text. It
|
||||
has roots in a piece of classical Latin literature from 45 BC, making it
|
||||
over 2000 years old.
|
||||
</Text>
|
||||
<Image style={styles.image} source={require('../../assets/book.jpg')} />
|
||||
<Text style={styles.paragraph}>
|
||||
<Text style={[styles.paragraph, { color: colors.text }]}>
|
||||
Richard McClintock, a Latin professor at Hampden-Sydney College in
|
||||
Virginia, looked up one of the more obscure Latin words, consectetur,
|
||||
from a Lorem Ipsum passage, and going through the cites of the word in
|
||||
classical literature, discovered the undoubtable source.
|
||||
</Text>
|
||||
<Text style={styles.paragraph}>
|
||||
<Text style={[styles.paragraph, { color: colors.text }]}>
|
||||
Lorem Ipsum comes from sections 1.10.32 and 1.10.33 of "de Finibus
|
||||
Bonorum et Malorum" (The Extremes of Good and Evil) by Cicero,
|
||||
written in 45 BC. This book is a treatise on the theory of ethics, very
|
||||
@@ -61,9 +65,6 @@ export default function Article({
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
backgroundColor: 'white',
|
||||
},
|
||||
content: {
|
||||
paddingVertical: 16,
|
||||
},
|
||||
@@ -77,13 +78,12 @@ const styles = StyleSheet.create({
|
||||
justifyContent: 'center',
|
||||
},
|
||||
name: {
|
||||
color: '#000',
|
||||
fontWeight: 'bold',
|
||||
fontSize: 16,
|
||||
lineHeight: 24,
|
||||
},
|
||||
timestamp: {
|
||||
color: '#999',
|
||||
opacity: 0.5,
|
||||
fontSize: 14,
|
||||
lineHeight: 21,
|
||||
},
|
||||
@@ -93,14 +93,12 @@ const styles = StyleSheet.create({
|
||||
borderRadius: 24,
|
||||
},
|
||||
title: {
|
||||
color: '#000',
|
||||
fontWeight: 'bold',
|
||||
fontSize: 36,
|
||||
marginVertical: 8,
|
||||
marginHorizontal: 16,
|
||||
},
|
||||
paragraph: {
|
||||
color: '#000',
|
||||
fontSize: 16,
|
||||
lineHeight: 24,
|
||||
marginVertical: 8,
|
||||
|
||||
@@ -7,7 +7,8 @@ import {
|
||||
ScrollView,
|
||||
StyleSheet,
|
||||
} from 'react-native';
|
||||
import { useScrollToTop } from '@react-navigation/native';
|
||||
import { useScrollToTop, useTheme } from '@react-navigation/native';
|
||||
import Color from 'color';
|
||||
|
||||
const MESSAGES = [
|
||||
'okay',
|
||||
@@ -21,6 +22,8 @@ export default function Chat() {
|
||||
|
||||
useScrollToTop(ref);
|
||||
|
||||
const { colors } = useTheme();
|
||||
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<ScrollView
|
||||
@@ -45,9 +48,12 @@ export default function Chat() {
|
||||
}
|
||||
/>
|
||||
<View
|
||||
style={[styles.bubble, odd ? styles.received : styles.sent]}
|
||||
style={[
|
||||
styles.bubble,
|
||||
{ backgroundColor: odd ? colors.primary : colors.card },
|
||||
]}
|
||||
>
|
||||
<Text style={odd ? styles.receivedText : styles.sentText}>
|
||||
<Text style={{ color: odd ? 'white' : colors.text }}>
|
||||
{text}
|
||||
</Text>
|
||||
</View>
|
||||
@@ -56,7 +62,14 @@ export default function Chat() {
|
||||
})}
|
||||
</ScrollView>
|
||||
<TextInput
|
||||
style={styles.input}
|
||||
style={[
|
||||
styles.input,
|
||||
{ backgroundColor: colors.card, color: colors.text },
|
||||
]}
|
||||
placeholderTextColor={Color(colors.text)
|
||||
.alpha(0.5)
|
||||
.rgb()
|
||||
.string()}
|
||||
placeholder="Write a message"
|
||||
underlineColorAndroid="transparent"
|
||||
/>
|
||||
@@ -67,7 +80,6 @@ export default function Chat() {
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
backgroundColor: '#eceff1',
|
||||
},
|
||||
inverted: {
|
||||
transform: [{ scaleY: -1 }],
|
||||
@@ -97,22 +109,9 @@ const styles = StyleSheet.create({
|
||||
paddingHorizontal: 16,
|
||||
borderRadius: 20,
|
||||
},
|
||||
sent: {
|
||||
backgroundColor: '#cfd8dc',
|
||||
},
|
||||
received: {
|
||||
backgroundColor: '#2196F3',
|
||||
},
|
||||
sentText: {
|
||||
color: 'black',
|
||||
},
|
||||
receivedText: {
|
||||
color: 'white',
|
||||
},
|
||||
input: {
|
||||
height: 48,
|
||||
paddingVertical: 12,
|
||||
paddingHorizontal: 24,
|
||||
backgroundColor: 'white',
|
||||
},
|
||||
});
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import * as React from 'react';
|
||||
import { View, Text, FlatList, StyleSheet } from 'react-native';
|
||||
import { useScrollToTop } from '@react-navigation/native';
|
||||
import { useScrollToTop, useTheme } from '@react-navigation/native';
|
||||
|
||||
type Item = { name: string; number: number };
|
||||
|
||||
@@ -57,27 +57,35 @@ const CONTACTS: Item[] = [
|
||||
{ name: 'Vincent Sandoval', number: 2606111495 },
|
||||
];
|
||||
|
||||
class ContactItem extends React.PureComponent<{
|
||||
item: { name: string; number: number };
|
||||
}> {
|
||||
render() {
|
||||
const { item } = this.props;
|
||||
const ContactItem = React.memo(
|
||||
({ item }: { item: { name: string; number: number } }) => {
|
||||
const { colors } = useTheme();
|
||||
|
||||
return (
|
||||
<View style={styles.item}>
|
||||
<View style={[styles.item, { backgroundColor: colors.card }]}>
|
||||
<View style={styles.avatar}>
|
||||
<Text style={styles.letter}>
|
||||
{item.name.slice(0, 1).toUpperCase()}
|
||||
</Text>
|
||||
</View>
|
||||
<View style={styles.details}>
|
||||
<Text style={styles.name}>{item.name}</Text>
|
||||
<Text style={styles.number}>{item.number}</Text>
|
||||
<Text style={[styles.name, { color: colors.text }]}>{item.name}</Text>
|
||||
<Text style={[styles.number, { color: colors.text, opacity: 0.5 }]}>
|
||||
{item.number}
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
const ItemSeparator = () => {
|
||||
const { colors } = useTheme();
|
||||
|
||||
return (
|
||||
<View style={[styles.separator, { backgroundColor: colors.border }]} />
|
||||
);
|
||||
};
|
||||
|
||||
export default function Contacts() {
|
||||
const ref = React.useRef<FlatList<Item>>(null);
|
||||
@@ -86,8 +94,6 @@ export default function Contacts() {
|
||||
|
||||
const renderItem = ({ item }: { item: Item }) => <ContactItem item={item} />;
|
||||
|
||||
const ItemSeparator = () => <View style={styles.separator} />;
|
||||
|
||||
return (
|
||||
<FlatList
|
||||
ref={ref}
|
||||
@@ -101,7 +107,6 @@ export default function Contacts() {
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
item: {
|
||||
backgroundColor: 'white',
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
padding: 8,
|
||||
@@ -124,14 +129,11 @@ const styles = StyleSheet.create({
|
||||
name: {
|
||||
fontWeight: 'bold',
|
||||
fontSize: 14,
|
||||
color: 'black',
|
||||
},
|
||||
number: {
|
||||
fontSize: 12,
|
||||
color: '#999',
|
||||
},
|
||||
separator: {
|
||||
height: StyleSheet.hairlineWidth,
|
||||
backgroundColor: 'rgba(0, 0, 0, .08)',
|
||||
},
|
||||
});
|
||||
|
||||
@@ -1,7 +1,23 @@
|
||||
import * as React from 'react';
|
||||
import { ScrollView, AsyncStorage, YellowBox } from 'react-native';
|
||||
import {
|
||||
View,
|
||||
ScrollView,
|
||||
AsyncStorage,
|
||||
YellowBox,
|
||||
Platform,
|
||||
StatusBar,
|
||||
} from 'react-native';
|
||||
import { MaterialIcons } from '@expo/vector-icons';
|
||||
import { Appbar, List } from 'react-native-paper';
|
||||
import {
|
||||
Provider as PaperProvider,
|
||||
DefaultTheme as PaperLightTheme,
|
||||
DarkTheme as PaperDarkTheme,
|
||||
Subheading,
|
||||
Appbar,
|
||||
List,
|
||||
Switch,
|
||||
Divider,
|
||||
} from 'react-native-paper';
|
||||
import { Asset } from 'expo-asset';
|
||||
import {
|
||||
InitialState,
|
||||
@@ -9,6 +25,8 @@ import {
|
||||
useLinking,
|
||||
NavigationContainerRef,
|
||||
NavigationNativeContainer,
|
||||
DefaultTheme,
|
||||
DarkTheme,
|
||||
} from '@react-navigation/native';
|
||||
import {
|
||||
createDrawerNavigator,
|
||||
@@ -72,7 +90,8 @@ const SCREENS = {
|
||||
const Drawer = createDrawerNavigator<RootDrawerParamList>();
|
||||
const Stack = createStackNavigator<RootStackParamList>();
|
||||
|
||||
const PERSISTENCE_KEY = 'NAVIGATION_STATE';
|
||||
const NAVIGATION_PERSISTENCE_KEY = 'NAVIGATION_STATE';
|
||||
const THEME_PERSISTENCE_KEY = 'THEME_TYPE';
|
||||
|
||||
Asset.loadAsync(StackAssets);
|
||||
|
||||
@@ -102,6 +121,8 @@ export default function App() {
|
||||
},
|
||||
});
|
||||
|
||||
const [theme, setTheme] = React.useState(DefaultTheme);
|
||||
|
||||
const [isReady, setIsReady] = React.useState(false);
|
||||
const [initialState, setInitialState] = React.useState<
|
||||
InitialState | undefined
|
||||
@@ -113,7 +134,9 @@ export default function App() {
|
||||
let state = await getInitialState();
|
||||
|
||||
if (state === undefined) {
|
||||
const savedState = await AsyncStorage.getItem(PERSISTENCE_KEY);
|
||||
const savedState = await AsyncStorage.getItem(
|
||||
NAVIGATION_PERSISTENCE_KEY
|
||||
);
|
||||
state = savedState ? JSON.parse(savedState) : undefined;
|
||||
}
|
||||
|
||||
@@ -121,6 +144,14 @@ export default function App() {
|
||||
setInitialState(state);
|
||||
}
|
||||
} finally {
|
||||
try {
|
||||
const themeName = await AsyncStorage.getItem(THEME_PERSISTENCE_KEY);
|
||||
|
||||
setTheme(themeName === 'dark' ? DarkTheme : DefaultTheme);
|
||||
} catch (e) {
|
||||
// Ignore
|
||||
}
|
||||
|
||||
setIsReady(true);
|
||||
}
|
||||
};
|
||||
@@ -128,78 +159,126 @@ export default function App() {
|
||||
restoreState();
|
||||
}, [getInitialState]);
|
||||
|
||||
const paperTheme = React.useMemo(() => {
|
||||
const t = theme.dark ? PaperDarkTheme : PaperLightTheme;
|
||||
|
||||
return {
|
||||
...t,
|
||||
colors: {
|
||||
...t.colors,
|
||||
...theme.colors,
|
||||
surface: theme.colors.card,
|
||||
accent: theme.dark ? 'rgb(255, 55, 95)' : 'rgb(255, 45, 85)',
|
||||
},
|
||||
};
|
||||
}, [theme.colors, theme.dark]);
|
||||
|
||||
if (!isReady) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<NavigationNativeContainer
|
||||
ref={containerRef}
|
||||
initialState={initialState}
|
||||
onStateChange={state =>
|
||||
AsyncStorage.setItem(PERSISTENCE_KEY, JSON.stringify(state))
|
||||
}
|
||||
>
|
||||
<Drawer.Navigator>
|
||||
<Drawer.Screen
|
||||
name="Root"
|
||||
options={{
|
||||
title: 'Examples',
|
||||
drawerIcon: ({ size, color }) => (
|
||||
<MaterialIcons size={size} color={color} name="folder" />
|
||||
),
|
||||
}}
|
||||
>
|
||||
{({
|
||||
navigation,
|
||||
}: {
|
||||
navigation: DrawerNavigationProp<RootDrawerParamList>;
|
||||
}) => (
|
||||
<Stack.Navigator>
|
||||
<Stack.Screen
|
||||
name="Home"
|
||||
options={{
|
||||
title: 'Examples',
|
||||
headerLeft: () => (
|
||||
<Appbar.Action
|
||||
icon="menu"
|
||||
onPress={() => navigation.toggleDrawer()}
|
||||
/>
|
||||
),
|
||||
}}
|
||||
>
|
||||
{({
|
||||
navigation,
|
||||
}: {
|
||||
navigation: StackNavigationProp<RootStackParamList>;
|
||||
}) => (
|
||||
<ScrollView>
|
||||
{(Object.keys(SCREENS) as Array<keyof typeof SCREENS>).map(
|
||||
name => (
|
||||
<PaperProvider theme={paperTheme}>
|
||||
{Platform.OS === 'ios' && (
|
||||
<StatusBar barStyle={theme.dark ? 'light-content' : 'dark-content'} />
|
||||
)}
|
||||
<NavigationNativeContainer
|
||||
ref={containerRef}
|
||||
initialState={initialState}
|
||||
onStateChange={state =>
|
||||
AsyncStorage.setItem(
|
||||
NAVIGATION_PERSISTENCE_KEY,
|
||||
JSON.stringify(state)
|
||||
)
|
||||
}
|
||||
theme={theme}
|
||||
>
|
||||
<Drawer.Navigator>
|
||||
<Drawer.Screen
|
||||
name="Root"
|
||||
options={{
|
||||
title: 'Examples',
|
||||
drawerIcon: ({ size, color }) => (
|
||||
<MaterialIcons size={size} color={color} name="folder" />
|
||||
),
|
||||
}}
|
||||
>
|
||||
{({
|
||||
navigation,
|
||||
}: {
|
||||
navigation: DrawerNavigationProp<RootDrawerParamList>;
|
||||
}) => (
|
||||
<Stack.Navigator>
|
||||
<Stack.Screen
|
||||
name="Home"
|
||||
options={{
|
||||
title: 'Examples',
|
||||
headerLeft: () => (
|
||||
<Appbar.Action
|
||||
color={theme.colors.text}
|
||||
icon="menu"
|
||||
onPress={() => navigation.toggleDrawer()}
|
||||
/>
|
||||
),
|
||||
}}
|
||||
>
|
||||
{({
|
||||
navigation,
|
||||
}: {
|
||||
navigation: StackNavigationProp<RootStackParamList>;
|
||||
}) => (
|
||||
<ScrollView
|
||||
style={{ backgroundColor: theme.colors.background }}
|
||||
>
|
||||
<View
|
||||
style={{
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
padding: 16,
|
||||
}}
|
||||
>
|
||||
<Subheading>Dark theme</Subheading>
|
||||
<Switch
|
||||
value={theme.dark}
|
||||
onValueChange={() => {
|
||||
AsyncStorage.setItem(
|
||||
THEME_PERSISTENCE_KEY,
|
||||
theme.dark ? 'light' : 'dark'
|
||||
);
|
||||
|
||||
setTheme(t => (t.dark ? DefaultTheme : DarkTheme));
|
||||
}}
|
||||
/>
|
||||
</View>
|
||||
<Divider />
|
||||
{(Object.keys(SCREENS) as Array<
|
||||
keyof typeof SCREENS
|
||||
>).map(name => (
|
||||
<List.Item
|
||||
key={name}
|
||||
title={SCREENS[name].title}
|
||||
onPress={() => navigation.push(name)}
|
||||
/>
|
||||
)
|
||||
)}
|
||||
</ScrollView>
|
||||
))}
|
||||
</ScrollView>
|
||||
)}
|
||||
</Stack.Screen>
|
||||
{(Object.keys(SCREENS) as Array<keyof typeof SCREENS>).map(
|
||||
name => (
|
||||
<Stack.Screen
|
||||
key={name}
|
||||
name={name}
|
||||
component={SCREENS[name].component}
|
||||
options={{ title: SCREENS[name].title }}
|
||||
/>
|
||||
)
|
||||
)}
|
||||
</Stack.Screen>
|
||||
{(Object.keys(SCREENS) as Array<keyof typeof SCREENS>).map(
|
||||
name => (
|
||||
<Stack.Screen
|
||||
key={name}
|
||||
name={name}
|
||||
component={SCREENS[name].component}
|
||||
options={{ title: SCREENS[name].title }}
|
||||
/>
|
||||
)
|
||||
)}
|
||||
</Stack.Navigator>
|
||||
)}
|
||||
</Drawer.Screen>
|
||||
</Drawer.Navigator>
|
||||
</NavigationNativeContainer>
|
||||
</Stack.Navigator>
|
||||
)}
|
||||
</Drawer.Screen>
|
||||
</Drawer.Navigator>
|
||||
</NavigationNativeContainer>
|
||||
</PaperProvider>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user