add expo app

This commit is contained in:
Jorrin
2024-01-14 14:56:39 +01:00
parent 833a1c8ecd
commit 326ff1fe92
33 changed files with 11940 additions and 1507 deletions

View File

@@ -10,7 +10,6 @@ module.exports = {
'tests/*',
'/*.cjs',
'/*.js',
'/*.ts',
'/**/*.test.ts',
'test/*',
],

1
.github/SECURITY.md vendored
View File

@@ -10,5 +10,6 @@ Support is not provided for any forks or mirrors of movie-web.
## Reporting a Vulnerability
There are two ways you can contact the movie-web maintainers to report a vulnerability:
- Email [security@movie-web.app](mailto:security@movie-web.app)
- Report the vulnerability in the [movie-web Discord server](https://discord.movie-web.app)

1
.npmrc
View File

@@ -1,2 +1,3 @@
strict-peer-dependencies=false
auto-install-peers=true
node-linker=hoisted

1
.nvmrc Normal file
View File

@@ -0,0 +1 @@
20.10

31
apps/mobile/.eslintrc.js Normal file
View File

@@ -0,0 +1,31 @@
module.exports = {
extends: ['../../.eslintrc.js'],
ignorePatterns: ['/*.js', '/*.d.ts'],
overrides: [
{
files: ['*.ts', '*.tsx', '*.js', '*.jsx'],
rules: {},
},
{
files: ['*.ts', '*.tsx'],
rules: {},
},
{
files: ['*.js', '*.jsx'],
rules: {},
},
],
rules: {
'react/jsx-uses-react': 'off',
'react/react-in-jsx-scope': 'off',
'react/require-default-props': 'off',
'react/destructuring-assignment': 'off',
'react/jsx-filename-extension': [
'error',
{ extensions: ['.js', '.tsx', '.jsx'] },
],
'react/jsx-props-no-spreading': 'off',
'react/no-unstable-nested-components': 'off',
'no-use-before-define': 'off',
},
};

41
apps/mobile/.gitignore vendored Normal file
View File

@@ -0,0 +1,41 @@
# Learn more https://docs.github.com/en/get-started/getting-started-with-git/ignoring-files
# dependencies
node_modules/
# Expo
.expo/
dist/
web-build/
# Native
*.orig.*
*.jks
*.p8
*.p12
*.key
*.mobileprovision
# Metro
.metro-health-check*
# debug
npm-debug.*
yarn-debug.*
yarn-error.*
# macOS
.DS_Store
*.pem
# local env files
.env*.local
# typescript
*.tsbuildinfo
# @generated expo-cli sync-2b81b286409207a5da26e14c78851eb30d8ccbdb
# The following patterns were generated by expo-cli
expo-env.d.ts
# @end expo-cli

35
apps/mobile/app.json Normal file
View File

@@ -0,0 +1,35 @@
{
"expo": {
"name": "mobile",
"slug": "mobile",
"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"
},
"assetBundlePatterns": ["**/*"],
"ios": {
"supportsTablet": true
},
"android": {
"adaptiveIcon": {
"foregroundImage": "./assets/images/adaptive-icon.png",
"backgroundColor": "#ffffff"
}
},
"web": {
"bundler": "metro",
"output": "static",
"favicon": "./assets/images/favicon.png"
},
"plugins": ["expo-router"],
"experiments": {
"typedRoutes": true
}
}
}

View File

@@ -0,0 +1,56 @@
import FontAwesome from '@expo/vector-icons/FontAwesome';
import { Link, Tabs } from 'expo-router';
import { Pressable, useColorScheme } from 'react-native';
import Colors from '../../constants/Colors';
/**
* 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={28} style={{ marginBottom: -3 }} {...props} />;
}
export default function TabLayout() {
const colorScheme = useColorScheme();
return (
<Tabs
screenOptions={{
tabBarActiveTintColor: Colors[colorScheme ?? 'light'].tint,
}}
>
<Tabs.Screen
name="index"
options={{
title: 'Tab One',
tabBarIcon: ({ color }) => <TabBarIcon name="code" color={color} />,
headerRight: () => (
<Link href="/modal" asChild>
<Pressable>
{({ pressed }) => (
<FontAwesome
name="info-circle"
size={25}
color={Colors[colorScheme ?? 'light'].text}
style={{ marginRight: 15, opacity: pressed ? 0.5 : 1 }}
/>
)}
</Pressable>
</Link>
),
}}
/>
<Tabs.Screen
name="two"
options={{
title: 'Tab Two',
tabBarIcon: ({ color }) => <TabBarIcon name="code" color={color} />,
}}
/>
</Tabs>
);
}

View File

@@ -0,0 +1,35 @@
import { StyleSheet } from 'react-native';
import EditScreenInfo from '../../components/EditScreenInfo';
import { Text, View } from '../../components/Themed';
export default function TabOneScreen() {
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="app/(tabs)/index.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%',
},
});

View File

@@ -0,0 +1,35 @@
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="app/(tabs)/two.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%',
},
});

46
apps/mobile/app/+html.tsx Normal file
View File

@@ -0,0 +1,46 @@
import { ScrollViewStyleReset } from 'expo-router/html';
// This file is web-only and used to configure the root HTML for every
// web page during static rendering.
// The contents of this function only run in Node.js environments and
// do not have access to the DOM or browser APIs.
export default function Root({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<head>
<meta charSet="utf-8" />
<meta httpEquiv="X-UA-Compatible" content="IE=edge" />
{/*
This viewport disables scaling which makes the mobile website act more like a native app.
However this does reduce built-in accessibility. If you want to enable scaling, use this instead:
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover" />
*/}
<meta
name="viewport"
content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1.00001,viewport-fit=cover"
/>
{/*
Disable body scrolling on web. This makes ScrollView components work closer to how they do on native.
However, body scrolling is often nice to have for mobile web. If you want to enable it, remove this line.
*/}
<ScrollViewStyleReset />
{/* Using raw CSS styles as an escape-hatch to ensure the background color never flickers in dark-mode. */}
<style dangerouslySetInnerHTML={{ __html: responsiveBackground }} />
{/* Add any additional <head> elements that you want globally available on web... */}
</head>
<body>{children}</body>
</html>
);
}
const responsiveBackground = `
body {
background-color: #fff;
}
@media (prefers-color-scheme: dark) {
body {
background-color: #000;
}
}`;

View File

@@ -0,0 +1,40 @@
import { Link, Stack } from 'expo-router';
import { StyleSheet } from 'react-native';
import { Text, View } from '../components/Themed';
export default function NotFoundScreen() {
return (
<>
<Stack.Screen options={{ title: 'Oops!' }} />
<View style={styles.container}>
<Text style={styles.title}>This screen doesn&apos;t exist.</Text>
<Link href="/" style={styles.link}>
<Text style={styles.linkText}>Go to home screen!</Text>
</Link>
</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',
},
});

View File

@@ -0,0 +1,62 @@
import FontAwesome from '@expo/vector-icons/FontAwesome';
import {
DarkTheme,
DefaultTheme,
ThemeProvider,
} from '@react-navigation/native';
import { useFonts } from 'expo-font';
import { SplashScreen, Stack } from 'expo-router';
import { useEffect } from 'react';
import { useColorScheme } from 'react-native';
export {
// Catch any errors thrown by the Layout component.
ErrorBoundary,
} from 'expo-router';
// eslint-disable-next-line camelcase
export const unstable_settings = {
// Ensure that reloading on `/modal` keeps a back button present.
initialRouteName: '(tabs)',
};
// Prevent the splash screen from auto-hiding before asset loading is complete.
SplashScreen.preventAutoHideAsync();
export default function RootLayout() {
const [loaded, error] = useFonts({
// eslint-disable-next-line global-require
SpaceMono: require('../assets/fonts/SpaceMono-Regular.ttf'),
...FontAwesome.font,
});
// Expo Router uses Error Boundaries to catch errors in the navigation tree.
useEffect(() => {
if (error) throw error;
}, [error]);
useEffect(() => {
if (loaded) {
SplashScreen.hideAsync();
}
}, [loaded]);
if (!loaded) {
return null;
}
return <RootLayoutNav />;
}
function RootLayoutNav() {
const colorScheme = useColorScheme();
return (
<ThemeProvider value={colorScheme === 'dark' ? DarkTheme : DefaultTheme}>
<Stack>
<Stack.Screen name="(tabs)" options={{ headerShown: false }} />
<Stack.Screen name="modal" options={{ presentation: 'modal' }} />
</Stack>
</ThemeProvider>
);
}

39
apps/mobile/app/modal.tsx Normal file
View File

@@ -0,0 +1,39 @@
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="app/modal.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%',
},
});

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

View File

@@ -0,0 +1,10 @@
module.exports = function (api) {
api.cache(true);
return {
presets: ['babel-preset-expo'],
plugins: [
// Required for expo-router
'expo-router/babel',
],
};
};

View File

@@ -0,0 +1,82 @@
import React from 'react';
import { StyleSheet } from 'react-native';
import { ExternalLink } from './ExternalLink';
import { MonoText } from './StyledText';
import { Text, View } from './Themed';
import Colors from '../constants/Colors';
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}>
<ExternalLink
style={styles.helpLink}
href="https://docs.expo.io/get-started/create-a-new-app/#opening-the-app-on-your-phonetablet"
>
<Text style={styles.helpLinkText} lightColor={Colors.light.tint}>
Tap here if your app doesn&apos;t automatically update after making
changes
</Text>
</ExternalLink>
</View>
</View>
);
}
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',
},
});

View File

@@ -0,0 +1,28 @@
import { Link } from 'expo-router';
import * as WebBrowser from 'expo-web-browser';
import React from 'react';
import { Platform } from 'react-native';
export function ExternalLink(
props: Omit<React.ComponentProps<typeof Link>, 'href'> & { href: string },
) {
return (
<Link
hrefAttrs={{
// On web, launch the link in a new tab.
target: '_blank',
}}
{...props}
// @ts-expect-error: External URLs are not typed.
href={props.href}
onPress={(e) => {
if (Platform.OS !== 'web') {
// Prevent the default behavior of linking to the default browser on native.
e.preventDefault();
// Open the link in an in-app browser.
WebBrowser.openBrowserAsync(props.href as string);
}
}}
/>
);
}

View File

@@ -0,0 +1,5 @@
import { Text, TextProps } from './Themed';
export function MonoText(props: TextProps) {
return <Text {...props} style={[props.style, { fontFamily: 'SpaceMono' }]} />;
}

View File

@@ -0,0 +1,50 @@
/**
* Learn more about Light and Dark modes:
* https://docs.expo.io/guides/color-schemes/
*/
import {
Text as DefaultText,
View as DefaultView,
useColorScheme,
} from 'react-native';
import Colors from '../constants/Colors';
type ThemeProps = {
lightColor?: string;
darkColor?: string;
};
export type TextProps = ThemeProps & DefaultText['props'];
export type ViewProps = ThemeProps & DefaultView['props'];
export function useThemeColor(
props: { light?: string; dark?: string },
colorName: keyof typeof Colors.light & keyof typeof Colors.dark,
) {
const theme = useColorScheme() ?? 'light';
const colorFromProps = props[theme];
if (colorFromProps) {
return colorFromProps;
}
return Colors[theme][colorName];
}
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} />;
}

View File

@@ -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,
},
};

View File

@@ -0,0 +1,27 @@
// Learn more https://docs.expo.io/guides/customizing-metro
const { getDefaultConfig } = require('expo/metro-config');
const path = require('path');
const projectRoot = __dirname;
const workspaceRoot = path.resolve(projectRoot, '../..');
/** @type {import('expo/metro-config').MetroConfig} */
const config = getDefaultConfig(projectRoot, {
// [Web-only]: Enables CSS support in Metro.
isCSSEnabled: true,
});
if (config.resolver) {
// 1. Watch all files within the monorepo
config.watchFolders = [workspaceRoot];
// 2. Let Metro know where to resolve packages and in what order
config.resolver.nodeModulesPaths = [
path.resolve(projectRoot, 'node_modules'),
path.resolve(workspaceRoot, 'node_modules'),
];
// 3. Force Metro to resolve (sub)dependencies only from the `nodeModulesPaths`
// TODO: This is supposed to be true, but I couldn't get it to work in the monorepo.
config.resolver.disableHierarchicalLookup = false;
}
module.exports = config;

55
apps/mobile/package.json Normal file
View File

@@ -0,0 +1,55 @@
{
"name": "mobile",
"main": "expo-router/entry",
"version": "1.0.0",
"scripts": {
"start": "expo start",
"android": "expo start --android",
"ios": "expo start --ios",
"web": "expo start --web",
"test": "jest --watchAll",
"lint": "eslint . --ext .js,.jsx,.ts,.tsx",
"format": "prettier --write ."
},
"jest": {
"preset": "jest-expo"
},
"dependencies": {
"@expo/vector-icons": "^13.0.0",
"@react-navigation/native": "^6.0.2",
"expo": "~49.0.15",
"expo-font": "~11.4.0",
"expo-linking": "~5.0.2",
"expo-router": "^2.0.0",
"expo-splash-screen": "~0.20.5",
"expo-status-bar": "~1.6.0",
"expo-system-ui": "~2.4.0",
"expo-web-browser": "~12.3.2",
"react": "18.2.0",
"react-dom": "18.2.0",
"react-native": "0.72.6",
"react-native-gesture-handler": "~2.12.0",
"react-native-safe-area-context": "4.6.3",
"react-native-screens": "~3.22.0",
"react-native-web": "~0.19.6"
},
"devDependencies": {
"@babel/core": "^7.20.0",
"@rnx-kit/metro-config": "^1.3.14",
"@rnx-kit/metro-resolver-symlinks": "^0.1.34",
"@types/react": "~18.2.14",
"eslint-plugin-react": "7.32.2",
"eslint-plugin-react-hooks": "4.6.0",
"jest": "^29.2.1",
"jest-expo": "~49.0.0",
"react-test-renderer": "18.2.0",
"typescript": "^5.1.3"
},
"overrides": {
"react-refresh": "~0.14.0"
},
"resolutions": {
"react-refresh": "~0.14.0"
},
"private": true
}

View File

@@ -0,0 +1,7 @@
{
"extends": ["../../tsconfig.base", "expo/tsconfig.base"],
"compilerOptions": {
"strict": true
},
"include": ["**/*.ts", "**/*.tsx", ".expo/types/**/*.ts", "expo-env.d.ts"]
}

0
packages/.gitkeep Normal file
View File

11552
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

3
pnpm-workspace.yaml Normal file
View File

@@ -0,0 +1,3 @@
packages:
- packages/*
- apps/*

View File

@@ -1,5 +1,4 @@
{
"compileOnSave": false,
"compilerOptions": {
"rootDir": ".",
"sourceMap": true,