forked from lucas.delanier/MovieFinder
commit
2530644edf
@ -0,0 +1,14 @@
|
|||||||
|
node_modules/
|
||||||
|
.expo/
|
||||||
|
dist/
|
||||||
|
npm-debug.*
|
||||||
|
*.jks
|
||||||
|
*.p8
|
||||||
|
*.p12
|
||||||
|
*.key
|
||||||
|
*.mobileprovision
|
||||||
|
*.orig.*
|
||||||
|
web-build/
|
||||||
|
|
||||||
|
# macOS
|
||||||
|
.DS_Store
|
@ -0,0 +1,22 @@
|
|||||||
|
import { StatusBar } from 'expo-status-bar';
|
||||||
|
import { SafeAreaProvider } from 'react-native-safe-area-context';
|
||||||
|
|
||||||
|
import useCachedResources from './hooks/useCachedResources';
|
||||||
|
import useColorScheme from './hooks/useColorScheme';
|
||||||
|
import Navigation from './navigation';
|
||||||
|
|
||||||
|
export default function App() {
|
||||||
|
const isLoadingComplete = useCachedResources();
|
||||||
|
const colorScheme = useColorScheme();
|
||||||
|
|
||||||
|
if (!isLoadingComplete) {
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
return (
|
||||||
|
<SafeAreaProvider>
|
||||||
|
<Navigation colorScheme={colorScheme} />
|
||||||
|
<StatusBar />
|
||||||
|
</SafeAreaProvider>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,34 @@
|
|||||||
|
{
|
||||||
|
"expo": {
|
||||||
|
"name": "MoovieFinderTS",
|
||||||
|
"slug": "MoovieFinderTS",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"orientation": "portrait",
|
||||||
|
"icon": "./assets/images/icon.png",
|
||||||
|
"scheme": "myapp",
|
||||||
|
"userInterfaceStyle": "automatic",
|
||||||
|
"splash": {
|
||||||
|
"image": "./assets/images/splash.png",
|
||||||
|
"resizeMode": "contain",
|
||||||
|
"backgroundColor": "#ffffff"
|
||||||
|
},
|
||||||
|
"updates": {
|
||||||
|
"fallbackToCacheTimeout": 0
|
||||||
|
},
|
||||||
|
"assetBundlePatterns": [
|
||||||
|
"**/*"
|
||||||
|
],
|
||||||
|
"ios": {
|
||||||
|
"supportsTablet": true
|
||||||
|
},
|
||||||
|
"android": {
|
||||||
|
"adaptiveIcon": {
|
||||||
|
"foregroundImage": "./assets/images/adaptive-icon.png",
|
||||||
|
"backgroundColor": "#ffffff"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"web": {
|
||||||
|
"favicon": "./assets/images/favicon.png"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Binary file not shown.
After Width: | Height: | Size: 17 KiB |
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 22 KiB |
After Width: | Height: | Size: 46 KiB |
@ -0,0 +1,6 @@
|
|||||||
|
module.exports = function(api) {
|
||||||
|
api.cache(true);
|
||||||
|
return {
|
||||||
|
presets: ['babel-preset-expo']
|
||||||
|
};
|
||||||
|
};
|
@ -0,0 +1,79 @@
|
|||||||
|
import * as WebBrowser from 'expo-web-browser';
|
||||||
|
import { StyleSheet, TouchableOpacity } from 'react-native';
|
||||||
|
|
||||||
|
import Colors from '../constants/Colors';
|
||||||
|
import { MonoText } from './StyledText';
|
||||||
|
import { Text, View } from './Themed';
|
||||||
|
|
||||||
|
export default function EditScreenInfo({ path }: { path: string }) {
|
||||||
|
return (
|
||||||
|
<View>
|
||||||
|
<View style={styles.getStartedContainer}>
|
||||||
|
<Text
|
||||||
|
style={styles.getStartedText}
|
||||||
|
lightColor="rgba(0,0,0,0.8)"
|
||||||
|
darkColor="rgba(255,255,255,0.8)">
|
||||||
|
Open up the code for this screen:
|
||||||
|
</Text>
|
||||||
|
|
||||||
|
<View
|
||||||
|
style={[styles.codeHighlightContainer, styles.homeScreenFilename]}
|
||||||
|
darkColor="rgba(255,255,255,0.05)"
|
||||||
|
lightColor="rgba(0,0,0,0.05)">
|
||||||
|
<MonoText>{path}</MonoText>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<Text
|
||||||
|
style={styles.getStartedText}
|
||||||
|
lightColor="rgba(0,0,0,0.8)"
|
||||||
|
darkColor="rgba(255,255,255,0.8)">
|
||||||
|
Change any of the text, save the file, and your app will automatically update.
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<View style={styles.helpContainer}>
|
||||||
|
<TouchableOpacity onPress={handleHelpPress} style={styles.helpLink}>
|
||||||
|
<Text style={styles.helpLinkText} lightColor={Colors.light.tint}>
|
||||||
|
Tap here if your app doesn't automatically update after making changes
|
||||||
|
</Text>
|
||||||
|
</TouchableOpacity>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleHelpPress() {
|
||||||
|
WebBrowser.openBrowserAsync(
|
||||||
|
'https://docs.expo.io/get-started/create-a-new-app/#opening-the-app-on-your-phonetablet'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
getStartedContainer: {
|
||||||
|
alignItems: 'center',
|
||||||
|
marginHorizontal: 50,
|
||||||
|
},
|
||||||
|
homeScreenFilename: {
|
||||||
|
marginVertical: 7,
|
||||||
|
},
|
||||||
|
codeHighlightContainer: {
|
||||||
|
borderRadius: 3,
|
||||||
|
paddingHorizontal: 4,
|
||||||
|
},
|
||||||
|
getStartedText: {
|
||||||
|
fontSize: 17,
|
||||||
|
lineHeight: 24,
|
||||||
|
textAlign: 'center',
|
||||||
|
},
|
||||||
|
helpContainer: {
|
||||||
|
marginTop: 15,
|
||||||
|
marginHorizontal: 20,
|
||||||
|
alignItems: 'center',
|
||||||
|
},
|
||||||
|
helpLink: {
|
||||||
|
paddingVertical: 15,
|
||||||
|
},
|
||||||
|
helpLinkText: {
|
||||||
|
textAlign: 'center',
|
||||||
|
},
|
||||||
|
});
|
@ -0,0 +1,5 @@
|
|||||||
|
import { Text, TextProps } from './Themed';
|
||||||
|
|
||||||
|
export function MonoText(props: TextProps) {
|
||||||
|
return <Text {...props} style={[props.style, { fontFamily: 'space-mono' }]} />;
|
||||||
|
}
|
@ -0,0 +1,45 @@
|
|||||||
|
/**
|
||||||
|
* Learn more about Light and Dark modes:
|
||||||
|
* https://docs.expo.io/guides/color-schemes/
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { Text as DefaultText, View as DefaultView } from 'react-native';
|
||||||
|
|
||||||
|
import Colors from '../constants/Colors';
|
||||||
|
import useColorScheme from '../hooks/useColorScheme';
|
||||||
|
|
||||||
|
export function useThemeColor(
|
||||||
|
props: { light?: string; dark?: string },
|
||||||
|
colorName: keyof typeof Colors.light & keyof typeof Colors.dark
|
||||||
|
) {
|
||||||
|
const theme = useColorScheme();
|
||||||
|
const colorFromProps = props[theme];
|
||||||
|
|
||||||
|
if (colorFromProps) {
|
||||||
|
return colorFromProps;
|
||||||
|
} else {
|
||||||
|
return Colors[theme][colorName];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type ThemeProps = {
|
||||||
|
lightColor?: string;
|
||||||
|
darkColor?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type TextProps = ThemeProps & DefaultText['props'];
|
||||||
|
export type ViewProps = ThemeProps & DefaultView['props'];
|
||||||
|
|
||||||
|
export function Text(props: TextProps) {
|
||||||
|
const { style, lightColor, darkColor, ...otherProps } = props;
|
||||||
|
const color = useThemeColor({ light: lightColor, dark: darkColor }, 'text');
|
||||||
|
|
||||||
|
return <DefaultText style={[{ color }, style]} {...otherProps} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function View(props: ViewProps) {
|
||||||
|
const { style, lightColor, darkColor, ...otherProps } = props;
|
||||||
|
const backgroundColor = useThemeColor({ light: lightColor, dark: darkColor }, 'background');
|
||||||
|
|
||||||
|
return <DefaultView style={[{ backgroundColor }, style]} {...otherProps} />;
|
||||||
|
}
|
@ -0,0 +1,10 @@
|
|||||||
|
import * as React from 'react';
|
||||||
|
import renderer from 'react-test-renderer';
|
||||||
|
|
||||||
|
import { MonoText } from '../StyledText';
|
||||||
|
|
||||||
|
it(`renders correctly`, () => {
|
||||||
|
const tree = renderer.create(<MonoText>Snapshot test!</MonoText>).toJSON();
|
||||||
|
|
||||||
|
expect(tree).toMatchSnapshot();
|
||||||
|
});
|
@ -0,0 +1,19 @@
|
|||||||
|
const tintColorLight = '#2f95dc';
|
||||||
|
const tintColorDark = '#fff';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
light: {
|
||||||
|
text: '#000',
|
||||||
|
background: '#fff',
|
||||||
|
tint: tintColorLight,
|
||||||
|
tabIconDefault: '#ccc',
|
||||||
|
tabIconSelected: tintColorLight,
|
||||||
|
},
|
||||||
|
dark: {
|
||||||
|
text: '#fff',
|
||||||
|
background: '#000',
|
||||||
|
tint: tintColorDark,
|
||||||
|
tabIconDefault: '#ccc',
|
||||||
|
tabIconSelected: tintColorDark,
|
||||||
|
},
|
||||||
|
};
|
@ -0,0 +1,12 @@
|
|||||||
|
import { Dimensions } from 'react-native';
|
||||||
|
|
||||||
|
const width = Dimensions.get('window').width;
|
||||||
|
const height = Dimensions.get('window').height;
|
||||||
|
|
||||||
|
export default {
|
||||||
|
window: {
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
},
|
||||||
|
isSmallDevice: width < 375,
|
||||||
|
};
|
@ -0,0 +1,33 @@
|
|||||||
|
import { FontAwesome } from '@expo/vector-icons';
|
||||||
|
import * as Font from 'expo-font';
|
||||||
|
import * as SplashScreen from 'expo-splash-screen';
|
||||||
|
import { useEffect, useState } from 'react';
|
||||||
|
|
||||||
|
export default function useCachedResources() {
|
||||||
|
const [isLoadingComplete, setLoadingComplete] = useState(false);
|
||||||
|
|
||||||
|
// Load any resources or data that we need prior to rendering the app
|
||||||
|
useEffect(() => {
|
||||||
|
async function loadResourcesAndDataAsync() {
|
||||||
|
try {
|
||||||
|
SplashScreen.preventAutoHideAsync();
|
||||||
|
|
||||||
|
// Load fonts
|
||||||
|
await Font.loadAsync({
|
||||||
|
...FontAwesome.font,
|
||||||
|
'space-mono': require('../assets/fonts/SpaceMono-Regular.ttf'),
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
// We might want to provide this error information to an error reporting service
|
||||||
|
console.warn(e);
|
||||||
|
} finally {
|
||||||
|
setLoadingComplete(true);
|
||||||
|
SplashScreen.hideAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
loadResourcesAndDataAsync();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return isLoadingComplete;
|
||||||
|
}
|
@ -0,0 +1,8 @@
|
|||||||
|
import { ColorSchemeName, useColorScheme as _useColorScheme } from 'react-native';
|
||||||
|
|
||||||
|
// The useColorScheme value is always either light or dark, but the built-in
|
||||||
|
// type suggests that it can be null. This will not happen in practice, so this
|
||||||
|
// makes it a bit easier to work with.
|
||||||
|
export default function useColorScheme(): NonNullable<ColorSchemeName> {
|
||||||
|
return _useColorScheme() as NonNullable<ColorSchemeName>;
|
||||||
|
}
|
@ -0,0 +1,36 @@
|
|||||||
|
/**
|
||||||
|
* Learn more about deep linking with React Navigation
|
||||||
|
* https://reactnavigation.org/docs/deep-linking
|
||||||
|
* https://reactnavigation.org/docs/configuring-links
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { LinkingOptions } from '@react-navigation/native';
|
||||||
|
import * as Linking from 'expo-linking';
|
||||||
|
|
||||||
|
import { RootStackParamList } from '../types';
|
||||||
|
|
||||||
|
const linking: LinkingOptions<RootStackParamList> = {
|
||||||
|
prefixes: [Linking.createURL('/')],
|
||||||
|
config: {
|
||||||
|
screens: {
|
||||||
|
Root: {
|
||||||
|
screens: {
|
||||||
|
TabOne: {
|
||||||
|
screens: {
|
||||||
|
TabOneScreen: 'one',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
TabTwo: {
|
||||||
|
screens: {
|
||||||
|
TabTwoScreen: 'two',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Modal: 'modal',
|
||||||
|
NotFound: '*',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default linking;
|
@ -0,0 +1,107 @@
|
|||||||
|
/**
|
||||||
|
* If you are not familiar with React Navigation, refer to the "Fundamentals" guide:
|
||||||
|
* https://reactnavigation.org/docs/getting-started
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
import { FontAwesome } from '@expo/vector-icons';
|
||||||
|
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
|
||||||
|
import { NavigationContainer, DefaultTheme, DarkTheme } from '@react-navigation/native';
|
||||||
|
import { createNativeStackNavigator } from '@react-navigation/native-stack';
|
||||||
|
import * as React from 'react';
|
||||||
|
import { ColorSchemeName, Pressable } from 'react-native';
|
||||||
|
|
||||||
|
import Colors from '../constants/Colors';
|
||||||
|
import useColorScheme from '../hooks/useColorScheme';
|
||||||
|
import ModalScreen from '../screens/ModalScreen';
|
||||||
|
import NotFoundScreen from '../screens/NotFoundScreen';
|
||||||
|
import TabOneScreen from '../screens/TabOneScreen';
|
||||||
|
import TabTwoScreen from '../screens/TabTwoScreen';
|
||||||
|
import { RootStackParamList, RootTabParamList, RootTabScreenProps } from '../types';
|
||||||
|
import LinkingConfiguration from './LinkingConfiguration';
|
||||||
|
|
||||||
|
export default function Navigation({ colorScheme }: { colorScheme: ColorSchemeName }) {
|
||||||
|
return (
|
||||||
|
<NavigationContainer
|
||||||
|
linking={LinkingConfiguration}
|
||||||
|
theme={colorScheme === 'dark' ? DarkTheme : DefaultTheme}>
|
||||||
|
<RootNavigator />
|
||||||
|
</NavigationContainer>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A root stack navigator is often used for displaying modals on top of all other content.
|
||||||
|
* https://reactnavigation.org/docs/modal
|
||||||
|
*/
|
||||||
|
const Stack = createNativeStackNavigator<RootStackParamList>();
|
||||||
|
|
||||||
|
function RootNavigator() {
|
||||||
|
return (
|
||||||
|
<Stack.Navigator>
|
||||||
|
<Stack.Screen name="Root" component={BottomTabNavigator} options={{ headerShown: false }} />
|
||||||
|
<Stack.Screen name="NotFound" component={NotFoundScreen} options={{ title: 'Oops!' }} />
|
||||||
|
<Stack.Group screenOptions={{ presentation: 'modal' }}>
|
||||||
|
<Stack.Screen name="Modal" component={ModalScreen} />
|
||||||
|
</Stack.Group>
|
||||||
|
</Stack.Navigator>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A bottom tab navigator displays tab buttons on the bottom of the display to switch screens.
|
||||||
|
* https://reactnavigation.org/docs/bottom-tab-navigator
|
||||||
|
*/
|
||||||
|
const BottomTab = createBottomTabNavigator<RootTabParamList>();
|
||||||
|
|
||||||
|
function BottomTabNavigator() {
|
||||||
|
const colorScheme = useColorScheme();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<BottomTab.Navigator
|
||||||
|
initialRouteName="TabOne"
|
||||||
|
screenOptions={{
|
||||||
|
tabBarActiveTintColor: Colors[colorScheme].tint,
|
||||||
|
}}>
|
||||||
|
<BottomTab.Screen
|
||||||
|
name="TabOne"
|
||||||
|
component={TabOneScreen}
|
||||||
|
options={({ navigation }: RootTabScreenProps<'TabOne'>) => ({
|
||||||
|
title: 'Tab One',
|
||||||
|
tabBarIcon: ({ color }) => <TabBarIcon name="code" color={color} />,
|
||||||
|
headerRight: () => (
|
||||||
|
<Pressable
|
||||||
|
onPress={() => navigation.navigate('Modal')}
|
||||||
|
style={({ pressed }) => ({
|
||||||
|
opacity: pressed ? 0.5 : 1,
|
||||||
|
})}>
|
||||||
|
<FontAwesome
|
||||||
|
name="info-circle"
|
||||||
|
size={25}
|
||||||
|
color={Colors[colorScheme].text}
|
||||||
|
style={{ marginRight: 15 }}
|
||||||
|
/>
|
||||||
|
</Pressable>
|
||||||
|
),
|
||||||
|
})}
|
||||||
|
/>
|
||||||
|
<BottomTab.Screen
|
||||||
|
name="TabTwo"
|
||||||
|
component={TabTwoScreen}
|
||||||
|
options={{
|
||||||
|
title: 'Tab Two',
|
||||||
|
tabBarIcon: ({ color }) => <TabBarIcon name="code" color={color} />,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</BottomTab.Navigator>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* You can explore the built-in icon families and icons on the web at https://icons.expo.fyi/
|
||||||
|
*/
|
||||||
|
function TabBarIcon(props: {
|
||||||
|
name: React.ComponentProps<typeof FontAwesome>['name'];
|
||||||
|
color: string;
|
||||||
|
}) {
|
||||||
|
return <FontAwesome size={30} style={{ marginBottom: -3 }} {...props} />;
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,46 @@
|
|||||||
|
{
|
||||||
|
"name": "mooviefinderts",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"main": "node_modules/expo/AppEntry.js",
|
||||||
|
"scripts": {
|
||||||
|
"start": "expo start",
|
||||||
|
"android": "expo start --android",
|
||||||
|
"ios": "expo start --ios",
|
||||||
|
"web": "expo start --web",
|
||||||
|
"test": "jest --watchAll"
|
||||||
|
},
|
||||||
|
"jest": {
|
||||||
|
"preset": "jest-expo"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@expo/vector-icons": "^13.0.0",
|
||||||
|
"@react-navigation/bottom-tabs": "^6.0.5",
|
||||||
|
"@react-navigation/native": "^6.0.2",
|
||||||
|
"@react-navigation/native-stack": "^6.1.0",
|
||||||
|
"expo": "~47.0.12",
|
||||||
|
"expo-asset": "~8.7.0",
|
||||||
|
"expo-constants": "~14.0.2",
|
||||||
|
"expo-font": "~11.0.1",
|
||||||
|
"expo-linking": "~3.3.0",
|
||||||
|
"expo-splash-screen": "~0.17.5",
|
||||||
|
"expo-status-bar": "~1.4.2",
|
||||||
|
"expo-system-ui": "~2.0.1",
|
||||||
|
"expo-web-browser": "~12.0.0",
|
||||||
|
"react": "18.1.0",
|
||||||
|
"react-dom": "18.1.0",
|
||||||
|
"react-native": "0.70.5",
|
||||||
|
"react-native-safe-area-context": "4.4.1",
|
||||||
|
"react-native-screens": "~3.18.0",
|
||||||
|
"react-native-web": "~0.18.9"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@babel/core": "^7.12.9",
|
||||||
|
"@types/react": "~18.0.24",
|
||||||
|
"@types/react-native": "~0.70.6",
|
||||||
|
"jest": "^26.6.3",
|
||||||
|
"jest-expo": "~47.0.1",
|
||||||
|
"react-test-renderer": "18.1.0",
|
||||||
|
"typescript": "^4.6.3"
|
||||||
|
},
|
||||||
|
"private": true
|
||||||
|
}
|
@ -0,0 +1,35 @@
|
|||||||
|
import { StatusBar } from 'expo-status-bar';
|
||||||
|
import { Platform, StyleSheet } from 'react-native';
|
||||||
|
|
||||||
|
import EditScreenInfo from '../components/EditScreenInfo';
|
||||||
|
import { Text, View } from '../components/Themed';
|
||||||
|
|
||||||
|
export default function ModalScreen() {
|
||||||
|
return (
|
||||||
|
<View style={styles.container}>
|
||||||
|
<Text style={styles.title}>Modal</Text>
|
||||||
|
<View style={styles.separator} lightColor="#eee" darkColor="rgba(255,255,255,0.1)" />
|
||||||
|
<EditScreenInfo path="/screens/ModalScreen.tsx" />
|
||||||
|
|
||||||
|
{/* Use a light status bar on iOS to account for the black space above the modal */}
|
||||||
|
<StatusBar style={Platform.OS === 'ios' ? 'light' : 'auto'} />
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
container: {
|
||||||
|
flex: 1,
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
fontSize: 20,
|
||||||
|
fontWeight: 'bold',
|
||||||
|
},
|
||||||
|
separator: {
|
||||||
|
marginVertical: 30,
|
||||||
|
height: 1,
|
||||||
|
width: '80%',
|
||||||
|
},
|
||||||
|
});
|
@ -0,0 +1,36 @@
|
|||||||
|
import { StyleSheet, TouchableOpacity } from 'react-native';
|
||||||
|
|
||||||
|
import { Text, View } from '../components/Themed';
|
||||||
|
import { RootStackScreenProps } from '../types';
|
||||||
|
|
||||||
|
export default function NotFoundScreen({ navigation }: RootStackScreenProps<'NotFound'>) {
|
||||||
|
return (
|
||||||
|
<View style={styles.container}>
|
||||||
|
<Text style={styles.title}>This screen doesn't exist.</Text>
|
||||||
|
<TouchableOpacity onPress={() => navigation.replace('Root')} style={styles.link}>
|
||||||
|
<Text style={styles.linkText}>Go to home screen!</Text>
|
||||||
|
</TouchableOpacity>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
container: {
|
||||||
|
flex: 1,
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
padding: 20,
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
fontSize: 20,
|
||||||
|
fontWeight: 'bold',
|
||||||
|
},
|
||||||
|
link: {
|
||||||
|
marginTop: 15,
|
||||||
|
paddingVertical: 15,
|
||||||
|
},
|
||||||
|
linkText: {
|
||||||
|
fontSize: 14,
|
||||||
|
color: '#2e78b7',
|
||||||
|
},
|
||||||
|
});
|
@ -0,0 +1,32 @@
|
|||||||
|
import { StyleSheet } from 'react-native';
|
||||||
|
|
||||||
|
import EditScreenInfo from '../components/EditScreenInfo';
|
||||||
|
import { Text, View } from '../components/Themed';
|
||||||
|
import { RootTabScreenProps } from '../types';
|
||||||
|
|
||||||
|
export default function TabOneScreen({ navigation }: RootTabScreenProps<'TabOne'>) {
|
||||||
|
return (
|
||||||
|
<View style={styles.container}>
|
||||||
|
<Text style={styles.title}>Tab One</Text>
|
||||||
|
<View style={styles.separator} lightColor="#eee" darkColor="rgba(255,255,255,0.1)" />
|
||||||
|
<EditScreenInfo path="/screens/TabOneScreen.tsx" />
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
container: {
|
||||||
|
flex: 1,
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
fontSize: 20,
|
||||||
|
fontWeight: 'bold',
|
||||||
|
},
|
||||||
|
separator: {
|
||||||
|
marginVertical: 30,
|
||||||
|
height: 1,
|
||||||
|
width: '80%',
|
||||||
|
},
|
||||||
|
});
|
@ -0,0 +1,31 @@
|
|||||||
|
import { StyleSheet } from 'react-native';
|
||||||
|
|
||||||
|
import EditScreenInfo from '../components/EditScreenInfo';
|
||||||
|
import { Text, View } from '../components/Themed';
|
||||||
|
|
||||||
|
export default function TabTwoScreen() {
|
||||||
|
return (
|
||||||
|
<View style={styles.container}>
|
||||||
|
<Text style={styles.title}>Tab Two</Text>
|
||||||
|
<View style={styles.separator} lightColor="#eee" darkColor="rgba(255,255,255,0.1)" />
|
||||||
|
<EditScreenInfo path="/screens/TabTwoScreen.tsx" />
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
container: {
|
||||||
|
flex: 1,
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
fontSize: 20,
|
||||||
|
fontWeight: 'bold',
|
||||||
|
},
|
||||||
|
separator: {
|
||||||
|
marginVertical: 30,
|
||||||
|
height: 1,
|
||||||
|
width: '80%',
|
||||||
|
},
|
||||||
|
});
|
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"extends": "expo/tsconfig.base",
|
||||||
|
"compilerOptions": {
|
||||||
|
"strict": true
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,35 @@
|
|||||||
|
/**
|
||||||
|
* Learn more about using TypeScript with React Navigation:
|
||||||
|
* https://reactnavigation.org/docs/typescript/
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { BottomTabScreenProps } from '@react-navigation/bottom-tabs';
|
||||||
|
import { CompositeScreenProps, NavigatorScreenParams } from '@react-navigation/native';
|
||||||
|
import { NativeStackScreenProps } from '@react-navigation/native-stack';
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
namespace ReactNavigation {
|
||||||
|
interface RootParamList extends RootStackParamList {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export type RootStackParamList = {
|
||||||
|
Root: NavigatorScreenParams<RootTabParamList> | undefined;
|
||||||
|
Modal: undefined;
|
||||||
|
NotFound: undefined;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type RootStackScreenProps<Screen extends keyof RootStackParamList> = NativeStackScreenProps<
|
||||||
|
RootStackParamList,
|
||||||
|
Screen
|
||||||
|
>;
|
||||||
|
|
||||||
|
export type RootTabParamList = {
|
||||||
|
TabOne: undefined;
|
||||||
|
TabTwo: undefined;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type RootTabScreenProps<Screen extends keyof RootTabParamList> = CompositeScreenProps<
|
||||||
|
BottomTabScreenProps<RootTabParamList, Screen>,
|
||||||
|
NativeStackScreenProps<RootStackParamList>
|
||||||
|
>;
|
Loading…
Reference in new issue