Iliya Zhechev commited on
Commit
0924f9b
1 Parent(s): 4960000

App initial commit with bare bones app

Browse files
app/.expo-shared/assets.json ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ {
2
+ "e997a5256149a4b76e6bfd6cbf519c5e5a0f1d278a3d8fa1253022b03c90473b": true,
3
+ "af683c96e0ffd2cf81287651c9433fa44debc1220ca7cb431fe482747f34a505": true,
4
+ "12bb71342c6255bbf50437ec8f4441c083f47cdb74bd89160c15e4f43e52a1cb": true,
5
+ "40b842e832070c58deac6aa9e08fa459302ee3f9da492c7e77d93d2fbf4a56fd": true
6
+ }
app/.gitignore ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ node_modules/
2
+ .expo/
3
+ dist/
4
+ npm-debug.*
5
+ *.jks
6
+ *.p8
7
+ *.p12
8
+ *.key
9
+ *.mobileprovision
10
+ *.orig.*
11
+ web-build/
12
+
13
+ # macOS
14
+ .DS_Store
app/App.tsx ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { StatusBar } from 'expo-status-bar';
2
+ import { SafeAreaProvider } from 'react-native-safe-area-context';
3
+
4
+ import useCachedResources from './hooks/useCachedResources';
5
+ import useColorScheme from './hooks/useColorScheme';
6
+ import Navigation from './navigation';
7
+
8
+ export default function App() {
9
+ const isLoadingComplete = useCachedResources();
10
+ const colorScheme = useColorScheme();
11
+
12
+ if (!isLoadingComplete) {
13
+ return null;
14
+ } else {
15
+ return (
16
+ <SafeAreaProvider>
17
+ <Navigation colorScheme={colorScheme} />
18
+ <StatusBar />
19
+ </SafeAreaProvider>
20
+ );
21
+ }
22
+ }
app/app.json ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "expo": {
3
+ "name": "text-brush",
4
+ "slug": "text-brush",
5
+ "version": "1.0.0",
6
+ "orientation": "portrait",
7
+ "icon": "./assets/images/icon.png",
8
+ "scheme": "myapp",
9
+ "userInterfaceStyle": "automatic",
10
+ "splash": {
11
+ "image": "./assets/images/splash.png",
12
+ "resizeMode": "contain",
13
+ "backgroundColor": "#ffffff"
14
+ },
15
+ "updates": {
16
+ "fallbackToCacheTimeout": 0
17
+ },
18
+ "assetBundlePatterns": [
19
+ "**/*"
20
+ ],
21
+ "ios": {
22
+ "supportsTablet": true
23
+ },
24
+ "android": {
25
+ "adaptiveIcon": {
26
+ "foregroundImage": "./assets/images/adaptive-icon.png",
27
+ "backgroundColor": "#ffffff"
28
+ }
29
+ },
30
+ "web": {
31
+ "favicon": "./assets/images/favicon.png"
32
+ }
33
+ }
34
+ }
app/assets/fonts/SpaceMono-Regular.ttf ADDED
Binary file (93.3 kB). View file
 
app/assets/images/adaptive-icon.png ADDED
app/assets/images/favicon.png ADDED
app/assets/images/icon.png ADDED
app/assets/images/splash.png ADDED
app/babel.config.js ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ module.exports = function(api) {
2
+ api.cache(true);
3
+ return {
4
+ presets: ['babel-preset-expo']
5
+ };
6
+ };
app/components/EditScreenInfo.tsx ADDED
@@ -0,0 +1,79 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import * as WebBrowser from 'expo-web-browser';
2
+ import { StyleSheet, TouchableOpacity } from 'react-native';
3
+
4
+ import Colors from '../constants/Colors';
5
+ import { MonoText } from './StyledText';
6
+ import { Text, View } from './Themed';
7
+
8
+ export default function EditScreenInfo({ path }: { path: string }) {
9
+ return (
10
+ <View>
11
+ <View style={styles.getStartedContainer}>
12
+ <Text
13
+ style={styles.getStartedText}
14
+ lightColor="rgba(0,0,0,0.8)"
15
+ darkColor="rgba(255,255,255,0.8)">
16
+ Open up the code for this screen:
17
+ </Text>
18
+
19
+ <View
20
+ style={[styles.codeHighlightContainer, styles.homeScreenFilename]}
21
+ darkColor="rgba(255,255,255,0.05)"
22
+ lightColor="rgba(0,0,0,0.05)">
23
+ <MonoText>{path}</MonoText>
24
+ </View>
25
+
26
+ <Text
27
+ style={styles.getStartedText}
28
+ lightColor="rgba(0,0,0,0.8)"
29
+ darkColor="rgba(255,255,255,0.8)">
30
+ Change any of the text, save the file, and your app will automatically update.
31
+ </Text>
32
+ </View>
33
+
34
+ <View style={styles.helpContainer}>
35
+ <TouchableOpacity onPress={handleHelpPress} style={styles.helpLink}>
36
+ <Text style={styles.helpLinkText} lightColor={Colors.light.tint}>
37
+ Tap here if your app doesn't automatically update after making changes
38
+ </Text>
39
+ </TouchableOpacity>
40
+ </View>
41
+ </View>
42
+ );
43
+ }
44
+
45
+ function handleHelpPress() {
46
+ WebBrowser.openBrowserAsync(
47
+ 'https://docs.expo.io/get-started/create-a-new-app/#opening-the-app-on-your-phonetablet'
48
+ );
49
+ }
50
+
51
+ const styles = StyleSheet.create({
52
+ getStartedContainer: {
53
+ alignItems: 'center',
54
+ marginHorizontal: 50,
55
+ },
56
+ homeScreenFilename: {
57
+ marginVertical: 7,
58
+ },
59
+ codeHighlightContainer: {
60
+ borderRadius: 3,
61
+ paddingHorizontal: 4,
62
+ },
63
+ getStartedText: {
64
+ fontSize: 17,
65
+ lineHeight: 24,
66
+ textAlign: 'center',
67
+ },
68
+ helpContainer: {
69
+ marginTop: 15,
70
+ marginHorizontal: 20,
71
+ alignItems: 'center',
72
+ },
73
+ helpLink: {
74
+ paddingVertical: 15,
75
+ },
76
+ helpLinkText: {
77
+ textAlign: 'center',
78
+ },
79
+ });
app/components/StyledText.tsx ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ import { Text, TextProps } from './Themed';
2
+
3
+ export function MonoText(props: TextProps) {
4
+ return <Text {...props} style={[props.style, { fontFamily: 'space-mono' }]} />;
5
+ }
app/components/Themed.tsx ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * Learn more about Light and Dark modes:
3
+ * https://docs.expo.io/guides/color-schemes/
4
+ */
5
+
6
+ import { Text as DefaultText, View as DefaultView } from 'react-native';
7
+
8
+ import Colors from '../constants/Colors';
9
+ import useColorScheme from '../hooks/useColorScheme';
10
+
11
+ export function useThemeColor(
12
+ props: { light?: string; dark?: string },
13
+ colorName: keyof typeof Colors.light & keyof typeof Colors.dark
14
+ ) {
15
+ const theme = useColorScheme();
16
+ const colorFromProps = props[theme];
17
+
18
+ if (colorFromProps) {
19
+ return colorFromProps;
20
+ } else {
21
+ return Colors[theme][colorName];
22
+ }
23
+ }
24
+
25
+ type ThemeProps = {
26
+ lightColor?: string;
27
+ darkColor?: string;
28
+ };
29
+
30
+ export type TextProps = ThemeProps & DefaultText['props'];
31
+ export type ViewProps = ThemeProps & DefaultView['props'];
32
+
33
+ export function Text(props: TextProps) {
34
+ const { style, lightColor, darkColor, ...otherProps } = props;
35
+ const color = useThemeColor({ light: lightColor, dark: darkColor }, 'text');
36
+
37
+ return <DefaultText style={[{ color }, style]} {...otherProps} />;
38
+ }
39
+
40
+ export function View(props: ViewProps) {
41
+ const { style, lightColor, darkColor, ...otherProps } = props;
42
+ const backgroundColor = useThemeColor({ light: lightColor, dark: darkColor }, 'background');
43
+
44
+ return <DefaultView style={[{ backgroundColor }, style]} {...otherProps} />;
45
+ }
app/components/__tests__/StyledText-test.js ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ import * as React from 'react';
2
+ import renderer from 'react-test-renderer';
3
+
4
+ import { MonoText } from '../StyledText';
5
+
6
+ it(`renders correctly`, () => {
7
+ const tree = renderer.create(<MonoText>Snapshot test!</MonoText>).toJSON();
8
+
9
+ expect(tree).toMatchSnapshot();
10
+ });
app/constants/Colors.ts ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ const tintColorLight = '#2f95dc';
2
+ const tintColorDark = '#fff';
3
+
4
+ export default {
5
+ light: {
6
+ text: '#000',
7
+ background: '#fff',
8
+ tint: tintColorLight,
9
+ tabIconDefault: '#ccc',
10
+ tabIconSelected: tintColorLight,
11
+ },
12
+ dark: {
13
+ text: '#fff',
14
+ background: '#000',
15
+ tint: tintColorDark,
16
+ tabIconDefault: '#ccc',
17
+ tabIconSelected: tintColorDark,
18
+ },
19
+ };
app/constants/Layout.ts ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { Dimensions } from 'react-native';
2
+
3
+ const width = Dimensions.get('window').width;
4
+ const height = Dimensions.get('window').height;
5
+
6
+ export default {
7
+ window: {
8
+ width,
9
+ height,
10
+ },
11
+ isSmallDevice: width < 375,
12
+ };
app/hooks/useCachedResources.ts ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { FontAwesome } from '@expo/vector-icons';
2
+ import * as Font from 'expo-font';
3
+ import * as SplashScreen from 'expo-splash-screen';
4
+ import { useEffect, useState } from 'react';
5
+
6
+ export default function useCachedResources() {
7
+ const [isLoadingComplete, setLoadingComplete] = useState(false);
8
+
9
+ // Load any resources or data that we need prior to rendering the app
10
+ useEffect(() => {
11
+ async function loadResourcesAndDataAsync() {
12
+ try {
13
+ SplashScreen.preventAutoHideAsync();
14
+
15
+ // Load fonts
16
+ await Font.loadAsync({
17
+ ...FontAwesome.font,
18
+ 'space-mono': require('../assets/fonts/SpaceMono-Regular.ttf'),
19
+ });
20
+ } catch (e) {
21
+ // We might want to provide this error information to an error reporting service
22
+ console.warn(e);
23
+ } finally {
24
+ setLoadingComplete(true);
25
+ SplashScreen.hideAsync();
26
+ }
27
+ }
28
+
29
+ loadResourcesAndDataAsync();
30
+ }, []);
31
+
32
+ return isLoadingComplete;
33
+ }
app/hooks/useColorScheme.ts ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ import { ColorSchemeName, useColorScheme as _useColorScheme } from 'react-native';
2
+
3
+ // The useColorScheme value is always either light or dark, but the built-in
4
+ // type suggests that it can be null. This will not happen in practice, so this
5
+ // makes it a bit easier to work with.
6
+ export default function useColorScheme(): NonNullable<ColorSchemeName> {
7
+ return _useColorScheme() as NonNullable<ColorSchemeName>;
8
+ }
app/navigation/LinkingConfiguration.ts ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * Learn more about deep linking with React Navigation
3
+ * https://reactnavigation.org/docs/deep-linking
4
+ * https://reactnavigation.org/docs/configuring-links
5
+ */
6
+
7
+ import { LinkingOptions } from '@react-navigation/native';
8
+ import * as Linking from 'expo-linking';
9
+
10
+ import { RootStackParamList } from '../types';
11
+
12
+ const linking: LinkingOptions<RootStackParamList> = {
13
+ prefixes: [Linking.createURL('/')],
14
+ config: {
15
+ screens: {
16
+ Root: {
17
+ screens: {
18
+ TabOne: {
19
+ screens: {
20
+ TabOneScreen: 'one',
21
+ },
22
+ },
23
+ TabTwo: {
24
+ screens: {
25
+ TabTwoScreen: 'two',
26
+ },
27
+ },
28
+ },
29
+ },
30
+ Modal: 'modal',
31
+ NotFound: '*',
32
+ },
33
+ },
34
+ };
35
+
36
+ export default linking;
app/navigation/index.tsx ADDED
@@ -0,0 +1,107 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * If you are not familiar with React Navigation, refer to the "Fundamentals" guide:
3
+ * https://reactnavigation.org/docs/getting-started
4
+ *
5
+ */
6
+ import { FontAwesome } from '@expo/vector-icons';
7
+ import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
8
+ import { NavigationContainer, DefaultTheme, DarkTheme } from '@react-navigation/native';
9
+ import { createNativeStackNavigator } from '@react-navigation/native-stack';
10
+ import * as React from 'react';
11
+ import { ColorSchemeName, Pressable } from 'react-native';
12
+
13
+ import Colors from '../constants/Colors';
14
+ import useColorScheme from '../hooks/useColorScheme';
15
+ import ModalScreen from '../screens/ModalScreen';
16
+ import NotFoundScreen from '../screens/NotFoundScreen';
17
+ import TabOneScreen from '../screens/TabOneScreen';
18
+ import TabTwoScreen from '../screens/TabTwoScreen';
19
+ import { RootStackParamList, RootTabParamList, RootTabScreenProps } from '../types';
20
+ import LinkingConfiguration from './LinkingConfiguration';
21
+
22
+ export default function Navigation({ colorScheme }: { colorScheme: ColorSchemeName }) {
23
+ return (
24
+ <NavigationContainer
25
+ linking={LinkingConfiguration}
26
+ theme={colorScheme === 'dark' ? DarkTheme : DefaultTheme}>
27
+ <RootNavigator />
28
+ </NavigationContainer>
29
+ );
30
+ }
31
+
32
+ /**
33
+ * A root stack navigator is often used for displaying modals on top of all other content.
34
+ * https://reactnavigation.org/docs/modal
35
+ */
36
+ const Stack = createNativeStackNavigator<RootStackParamList>();
37
+
38
+ function RootNavigator() {
39
+ return (
40
+ <Stack.Navigator>
41
+ <Stack.Screen name="Root" component={BottomTabNavigator} options={{ headerShown: false }} />
42
+ <Stack.Screen name="NotFound" component={NotFoundScreen} options={{ title: 'Oops!' }} />
43
+ <Stack.Group screenOptions={{ presentation: 'modal' }}>
44
+ <Stack.Screen name="Modal" component={ModalScreen} />
45
+ </Stack.Group>
46
+ </Stack.Navigator>
47
+ );
48
+ }
49
+
50
+ /**
51
+ * A bottom tab navigator displays tab buttons on the bottom of the display to switch screens.
52
+ * https://reactnavigation.org/docs/bottom-tab-navigator
53
+ */
54
+ const BottomTab = createBottomTabNavigator<RootTabParamList>();
55
+
56
+ function BottomTabNavigator() {
57
+ const colorScheme = useColorScheme();
58
+
59
+ return (
60
+ <BottomTab.Navigator
61
+ initialRouteName="TabOne"
62
+ screenOptions={{
63
+ tabBarActiveTintColor: Colors[colorScheme].tint,
64
+ }}>
65
+ <BottomTab.Screen
66
+ name="TabOne"
67
+ component={TabOneScreen}
68
+ options={({ navigation }: RootTabScreenProps<'TabOne'>) => ({
69
+ title: 'Tab One',
70
+ tabBarIcon: ({ color }) => <TabBarIcon name="code" color={color} />,
71
+ headerRight: () => (
72
+ <Pressable
73
+ onPress={() => navigation.navigate('Modal')}
74
+ style={({ pressed }) => ({
75
+ opacity: pressed ? 0.5 : 1,
76
+ })}>
77
+ <FontAwesome
78
+ name="info-circle"
79
+ size={25}
80
+ color={Colors[colorScheme].text}
81
+ style={{ marginRight: 15 }}
82
+ />
83
+ </Pressable>
84
+ ),
85
+ })}
86
+ />
87
+ <BottomTab.Screen
88
+ name="TabTwo"
89
+ component={TabTwoScreen}
90
+ options={{
91
+ title: 'Tab Two',
92
+ tabBarIcon: ({ color }) => <TabBarIcon name="code" color={color} />,
93
+ }}
94
+ />
95
+ </BottomTab.Navigator>
96
+ );
97
+ }
98
+
99
+ /**
100
+ * You can explore the built-in icon families and icons on the web at https://icons.expo.fyi/
101
+ */
102
+ function TabBarIcon(props: {
103
+ name: React.ComponentProps<typeof FontAwesome>['name'];
104
+ color: string;
105
+ }) {
106
+ return <FontAwesome size={30} style={{ marginBottom: -3 }} {...props} />;
107
+ }
app/package-lock.json ADDED
The diff for this file is too large to render. See raw diff
 
app/package.json ADDED
@@ -0,0 +1,47 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "text-brush",
3
+ "version": "1.0.0",
4
+ "main": "node_modules/expo/AppEntry.js",
5
+ "scripts": {
6
+ "start": "expo start",
7
+ "android": "expo start --android",
8
+ "ios": "expo start --ios",
9
+ "web": "expo start --web",
10
+ "test": "jest --watchAll"
11
+ },
12
+ "jest": {
13
+ "preset": "jest-expo"
14
+ },
15
+ "dependencies": {
16
+ "@expo/vector-icons": "^13.0.0",
17
+ "@expo/webpack-config": "^0.17.0",
18
+ "@react-navigation/bottom-tabs": "^6.0.5",
19
+ "@react-navigation/native": "^6.0.2",
20
+ "@react-navigation/native-stack": "^6.1.0",
21
+ "expo": "~46.0.13",
22
+ "expo-asset": "~8.6.1",
23
+ "expo-constants": "~13.2.4",
24
+ "expo-font": "~10.2.1",
25
+ "expo-linking": "~3.2.2",
26
+ "expo-splash-screen": "~0.16.2",
27
+ "expo-status-bar": "~1.4.0",
28
+ "expo-system-ui": "~1.3.0",
29
+ "expo-web-browser": "~11.0.0",
30
+ "react": "18.0.0",
31
+ "react-dom": "18.0.0",
32
+ "react-native": "0.69.6",
33
+ "react-native-safe-area-context": "4.3.1",
34
+ "react-native-screens": "~3.15.0",
35
+ "react-native-web": "~0.18.7"
36
+ },
37
+ "devDependencies": {
38
+ "@babel/core": "^7.12.9",
39
+ "@types/react": "~18.0.14",
40
+ "@types/react-native": "~0.69.1",
41
+ "jest": "^26.6.3",
42
+ "jest-expo": "~44.0.1",
43
+ "react-test-renderer": "18.0.0",
44
+ "typescript": "~4.3.5"
45
+ },
46
+ "private": true
47
+ }
app/screens/ModalScreen.tsx ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { StatusBar } from 'expo-status-bar';
2
+ import { Platform, StyleSheet } from 'react-native';
3
+
4
+ import EditScreenInfo from '../components/EditScreenInfo';
5
+ import { Text, View } from '../components/Themed';
6
+
7
+ export default function ModalScreen() {
8
+ return (
9
+ <View style={styles.container}>
10
+ <Text style={styles.title}>Modal</Text>
11
+ <View style={styles.separator} lightColor="#eee" darkColor="rgba(255,255,255,0.1)" />
12
+ <EditScreenInfo path="/screens/ModalScreen.tsx" />
13
+
14
+ {/* Use a light status bar on iOS to account for the black space above the modal */}
15
+ <StatusBar style={Platform.OS === 'ios' ? 'light' : 'auto'} />
16
+ </View>
17
+ );
18
+ }
19
+
20
+ const styles = StyleSheet.create({
21
+ container: {
22
+ flex: 1,
23
+ alignItems: 'center',
24
+ justifyContent: 'center',
25
+ },
26
+ title: {
27
+ fontSize: 20,
28
+ fontWeight: 'bold',
29
+ },
30
+ separator: {
31
+ marginVertical: 30,
32
+ height: 1,
33
+ width: '80%',
34
+ },
35
+ });
app/screens/NotFoundScreen.tsx ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { StyleSheet, TouchableOpacity } from 'react-native';
2
+
3
+ import { Text, View } from '../components/Themed';
4
+ import { RootStackScreenProps } from '../types';
5
+
6
+ export default function NotFoundScreen({ navigation }: RootStackScreenProps<'NotFound'>) {
7
+ return (
8
+ <View style={styles.container}>
9
+ <Text style={styles.title}>This screen doesn't exist.</Text>
10
+ <TouchableOpacity onPress={() => navigation.replace('Root')} style={styles.link}>
11
+ <Text style={styles.linkText}>Go to home screen!</Text>
12
+ </TouchableOpacity>
13
+ </View>
14
+ );
15
+ }
16
+
17
+ const styles = StyleSheet.create({
18
+ container: {
19
+ flex: 1,
20
+ alignItems: 'center',
21
+ justifyContent: 'center',
22
+ padding: 20,
23
+ },
24
+ title: {
25
+ fontSize: 20,
26
+ fontWeight: 'bold',
27
+ },
28
+ link: {
29
+ marginTop: 15,
30
+ paddingVertical: 15,
31
+ },
32
+ linkText: {
33
+ fontSize: 14,
34
+ color: '#2e78b7',
35
+ },
36
+ });
app/screens/TabOneScreen.tsx ADDED
@@ -0,0 +1,106 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { useState } from 'react';
2
+ import { ActivityIndicator, Button, Image, StyleSheet, TextInput } from 'react-native';
3
+
4
+ import { Text, View } from '../components/Themed';
5
+ import { RootTabScreenProps } from '../types';
6
+
7
+ function blobToBase64(blob: Blob): Promise<string | ArayBuffer> {
8
+ return new Promise((resolve, reject) => {
9
+ const reader = new FileReader();
10
+ reader.onloadend = () => resolve(reader.result);
11
+ reader.readAsDataURL(blob);
12
+ reader.onerror = error => reject(error)
13
+ });
14
+ }
15
+ export default function TabOneScreen({ navigation }: RootTabScreenProps<'TabOne'>) {
16
+ const [text, setText] = useState('');
17
+ const [imageData, setImageData] = useState<string | null>(null);
18
+ const [isLoading, setIsLoading] = useState<bool>(false);
19
+
20
+ const onPress = () => {
21
+ const prompt = text;
22
+ const seed = 1337;
23
+ const steps = 30;
24
+ const url = `http://78.83.125.177:5000/generate-image?seed=${seed}&steps=${steps}&prompt=${prompt}`;
25
+ // const url = 'http://localhost:3000/ava.jpeg'
26
+ console.log('fetching');
27
+ setIsLoading(true);
28
+ fetch(url)
29
+ .then(async response => {
30
+ // debugger;
31
+ const blob = await response.blob();
32
+ const base64Blob = await blobToBase64(blob)
33
+ const validBlob = "data:image/png;base64," + base64Blob.substr(base64Blob.indexOf(',') + 1);
34
+ setImageData(validBlob);
35
+ console.log('done!');
36
+ setIsLoading(false);
37
+ })
38
+ .catch(error => {
39
+ console.error(error);
40
+ setIsLoading(false);
41
+ });
42
+ }
43
+
44
+ return (
45
+ <View style={styles.container}>
46
+ <Text style={styles.title}>Generate AI Image</Text>
47
+ <TextInput
48
+ style={styles.input}
49
+ placeholder="Write a prompt! (e.g. cute cat on mars)"
50
+ onChangeText={newText => setText(newText)}
51
+ onSubmitEditing={_ => onPress()}
52
+ defaultValue={text}
53
+ />
54
+ <Button title="Generate" onPress={onPress}></Button>
55
+ <View style={styles.separator} lightColor="#eee" darkColor="rgba(255,255,255,0.1)" />
56
+ {imageData && <Image source={{uri: imageData, scale: 1}} style={styles.image} />}
57
+
58
+ {isLoading && (
59
+ <View style={styles.loading}>
60
+ <ActivityIndicator size='large' />
61
+ </View>
62
+ )}
63
+ </View>
64
+ );
65
+ }
66
+
67
+ const styles = StyleSheet.create({
68
+ image: {
69
+ width: 512,
70
+ height: 512,
71
+ maxWidth: '100%',
72
+ resizeMode: 'contain',
73
+ },
74
+ input: {
75
+ borderWidth: 3,
76
+ borderRadius: 3,
77
+ padding: '10px',
78
+ width: '100%',
79
+ margin: '10px',
80
+ },
81
+ container: {
82
+ padding: 10,
83
+ flex: 1,
84
+ alignItems: 'center',
85
+ justifyContent: 'center',
86
+ },
87
+ title: {
88
+ fontSize: 20,
89
+ fontWeight: 'bold',
90
+ },
91
+ separator: {
92
+ marginVertical: 30,
93
+ height: 1,
94
+ width: '80%',
95
+ },
96
+ loading: {
97
+ backgroundColor: 'rgba(255, 255, 255, 0.5)',
98
+ position: 'absolute',
99
+ left: 0,
100
+ right: 0,
101
+ top: 0,
102
+ bottom: 0,
103
+ alignItems: 'center',
104
+ justifyContent: 'center'
105
+ },
106
+ });
app/screens/TabTwoScreen.tsx ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { StyleSheet } from 'react-native';
2
+
3
+ import EditScreenInfo from '../components/EditScreenInfo';
4
+ import { Text, View } from '../components/Themed';
5
+
6
+ export default function TabTwoScreen() {
7
+ return (
8
+ <View style={styles.container}>
9
+ <Text style={styles.title}>Tab Two</Text>
10
+ <View style={styles.separator} lightColor="#eee" darkColor="rgba(255,255,255,0.1)" />
11
+ <EditScreenInfo path="/screens/TabTwoScreen.tsx" />
12
+ </View>
13
+ );
14
+ }
15
+
16
+ const styles = StyleSheet.create({
17
+ container: {
18
+ flex: 1,
19
+ alignItems: 'center',
20
+ justifyContent: 'center',
21
+ },
22
+ title: {
23
+ fontSize: 20,
24
+ fontWeight: 'bold',
25
+ },
26
+ separator: {
27
+ marginVertical: 30,
28
+ height: 1,
29
+ width: '80%',
30
+ },
31
+ });
app/tsconfig.json ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ {
2
+ "extends": "expo/tsconfig.base",
3
+ "compilerOptions": {
4
+ "strict": true
5
+ }
6
+ }
app/types.tsx ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * Learn more about using TypeScript with React Navigation:
3
+ * https://reactnavigation.org/docs/typescript/
4
+ */
5
+
6
+ import { BottomTabScreenProps } from '@react-navigation/bottom-tabs';
7
+ import { CompositeScreenProps, NavigatorScreenParams } from '@react-navigation/native';
8
+ import { NativeStackScreenProps } from '@react-navigation/native-stack';
9
+
10
+ declare global {
11
+ namespace ReactNavigation {
12
+ interface RootParamList extends RootStackParamList {}
13
+ }
14
+ }
15
+
16
+ export type RootStackParamList = {
17
+ Root: NavigatorScreenParams<RootTabParamList> | undefined;
18
+ Modal: undefined;
19
+ NotFound: undefined;
20
+ };
21
+
22
+ export type RootStackScreenProps<Screen extends keyof RootStackParamList> = NativeStackScreenProps<
23
+ RootStackParamList,
24
+ Screen
25
+ >;
26
+
27
+ export type RootTabParamList = {
28
+ TabOne: undefined;
29
+ TabTwo: undefined;
30
+ };
31
+
32
+ export type RootTabScreenProps<Screen extends keyof RootTabParamList> = CompositeScreenProps<
33
+ BottomTabScreenProps<RootTabParamList, Screen>,
34
+ NativeStackScreenProps<RootStackParamList>
35
+ >;