Skip to content

Commit 632b03e

Browse files
@mlodyjesienin/example app UI (#386)
## Description Migrated example apps (llm, computervision) to expo router navigation. Added drawer navigation and menu for better UX. Fixed small issues regarding keyboard padding. ### Type of change - [x] Bug fix (non-breaking change which fixes an issue) - [x] New feature (non-breaking change which adds functionality) ### Tested on - [x] iOS - [x] Android ### Related issues Issue #224 ### Checklist - [x] I have performed a self-review of my code - [ ] I have commented my code, particularly in hard-to-understand areas, (not necessary) - [ ] I have updated the documentation accordingly, (not necessary) - [ ] My changes generate no new warnings --------- Co-authored-by: pweglik <36445788+pweglik@users.noreply.github.com>
1 parent 6b88b4b commit 632b03e

File tree

50 files changed

+2876
-2482
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+2876
-2482
lines changed

apps/computer-vision/App.tsx

Lines changed: 0 additions & 129 deletions
This file was deleted.
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { useIsFocused } from '@react-navigation/native';
2+
import { PropsWithChildren } from 'react';
3+
4+
export default function ScreenWrapper({ children }: PropsWithChildren) {
5+
const isFocused = useIsFocused();
6+
7+
return isFocused ? <>{children}</> : null;
8+
}

apps/computer-vision/android/app/src/main/AndroidManifest.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,12 @@
2020
<action android:name="android.intent.action.MAIN"/>
2121
<category android:name="android.intent.category.LAUNCHER"/>
2222
</intent-filter>
23+
<intent-filter>
24+
<action android:name="android.intent.action.VIEW"/>
25+
<category android:name="android.intent.category.DEFAULT"/>
26+
<category android:name="android.intent.category.BROWSABLE"/>
27+
<data android:scheme="rne-computer-vision"/>
28+
</intent-filter>
2329
</activity>
2430
</application>
2531
</manifest>

apps/computer-vision/android/app/src/main/res/values/styles.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
<resources xmlns:tools="http://schemas.android.com/tools">
22
<style name="AppTheme" parent="Theme.AppCompat.DayNight.NoActionBar">
33
<item name="android:editTextBackground">@drawable/rn_edit_text_material</item>
4-
<item name="android:windowOptOutEdgeToEdgeEnforcement" tools:targetApi="35">true</item>
54
<item name="colorPrimary">@color/colorPrimary</item>
65
<item name="android:statusBarColor">#ffffff</item>
6+
<item name="android:windowOptOutEdgeToEdgeEnforcement" tools:targetApi="35">true</item>
77
</style>
88
<style name="Theme.App.SplashScreen" parent="AppTheme">
99
<item name="android:windowBackground">@drawable/ic_launcher_background</item>

apps/computer-vision/app.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
"icon": "./assets/icons/icon.png",
88
"userInterfaceStyle": "light",
99
"newArchEnabled": true,
10+
"scheme": "rne-computer-vision",
1011
"splash": {
1112
"image": "./assets/icons/splash.png",
1213
"resizeMode": "contain",
@@ -29,6 +30,6 @@
2930
"web": {
3031
"favicon": "./assets/icons/favicon.png"
3132
},
32-
"plugins": ["expo-font"]
33+
"plugins": ["expo-font", "expo-router"]
3334
}
3435
}
Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
import { Drawer } from 'expo-router/drawer';
2+
import ColorPalette from '../colors';
3+
import React, { useState } from 'react';
4+
import { Text, StyleSheet, View } from 'react-native';
5+
6+
import {
7+
DrawerContentComponentProps,
8+
DrawerContentScrollView,
9+
DrawerItemList,
10+
} from '@react-navigation/drawer';
11+
import { GeneratingContext } from '../context';
12+
13+
interface CustomDrawerProps extends DrawerContentComponentProps {
14+
isGenerating: boolean;
15+
}
16+
17+
function CustomDrawerContent(props: CustomDrawerProps) {
18+
const { isGenerating, ...otherProps } = props;
19+
return (
20+
<DrawerContentScrollView {...otherProps}>
21+
{!isGenerating ? (
22+
<DrawerItemList {...otherProps} />
23+
) : (
24+
<View style={styles.centerContent}>
25+
<Text style={styles.mainText}>Model is generating...</Text>
26+
<Text style={styles.subText}>Interrupt before switching model</Text>
27+
</View>
28+
)}
29+
</DrawerContentScrollView>
30+
);
31+
}
32+
33+
export default function _layout() {
34+
const [isGenerating, setIsGenerating] = useState(false);
35+
36+
return (
37+
<GeneratingContext
38+
value={{
39+
setGlobalGenerating: (newState: boolean) => {
40+
setIsGenerating(newState);
41+
},
42+
}}
43+
>
44+
<Drawer
45+
drawerContent={(props) => (
46+
<CustomDrawerContent {...props} isGenerating={isGenerating} />
47+
)}
48+
screenOptions={{
49+
drawerActiveTintColor: ColorPalette.primary,
50+
drawerInactiveTintColor: '#888',
51+
headerTintColor: ColorPalette.primary,
52+
headerTitleStyle: { color: ColorPalette.primary },
53+
}}
54+
>
55+
<Drawer.Screen
56+
name="classification/index"
57+
options={{
58+
drawerLabel: 'Classification',
59+
title: 'Classification',
60+
headerTitleStyle: { color: ColorPalette.primary },
61+
}}
62+
/>
63+
<Drawer.Screen
64+
name="image_segmentation/index"
65+
options={{
66+
drawerLabel: 'Image Segmentation',
67+
title: 'Image Segmentation',
68+
headerTitleStyle: { color: ColorPalette.primary },
69+
}}
70+
/>
71+
<Drawer.Screen
72+
name="object_detection/index"
73+
options={{
74+
drawerLabel: 'Object Detection',
75+
title: 'Object Detection',
76+
headerTitleStyle: { color: ColorPalette.primary },
77+
}}
78+
/>
79+
<Drawer.Screen
80+
name="ocr/index"
81+
options={{
82+
drawerLabel: 'OCR',
83+
title: 'OCR',
84+
headerTitleStyle: { color: ColorPalette.primary },
85+
}}
86+
/>
87+
<Drawer.Screen
88+
name="ocr_vertical/index"
89+
options={{
90+
drawerLabel: 'OCR Vertical',
91+
title: 'Vertical OCR',
92+
headerTitleStyle: { color: ColorPalette.primary },
93+
}}
94+
/>
95+
<Drawer.Screen
96+
name="style_transfer/index"
97+
options={{
98+
drawerLabel: 'Style Transfer',
99+
title: 'Style Transfer',
100+
headerTitleStyle: { color: ColorPalette.primary },
101+
}}
102+
/>
103+
<Drawer.Screen
104+
name="index"
105+
options={{
106+
drawerLabel: () => null,
107+
title: 'Main Menu',
108+
drawerItemStyle: { display: 'none' },
109+
}}
110+
/>
111+
</Drawer>
112+
</GeneratingContext>
113+
);
114+
}
115+
116+
const styles = StyleSheet.create({
117+
centerContent: {
118+
flex: 1,
119+
justifyContent: 'center',
120+
alignItems: 'center',
121+
padding: 20,
122+
},
123+
mainText: {
124+
fontSize: 18,
125+
fontWeight: 'bold',
126+
marginBottom: 10,
127+
color: ColorPalette.primary,
128+
},
129+
subText: {
130+
fontSize: 14,
131+
color: ColorPalette.strongPrimary,
132+
},
133+
});

apps/computer-vision/screens/ClassificationScreen.tsx renamed to apps/computer-vision/app/classification/index.tsx

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,25 @@
1-
import { useState } from 'react';
21
import Spinner from 'react-native-loading-spinner-overlay';
3-
import { BottomBar } from '../components/BottomBar';
4-
import { getImage } from '../utils';
2+
import { getImage } from '../../utils';
53
import { useClassification, EFFICIENTNET_V2_S } from 'react-native-executorch';
64
import { View, StyleSheet, Image, Text, ScrollView } from 'react-native';
5+
import { BottomBar } from '../../components/BottomBar';
6+
import React, { useContext, useEffect, useState } from 'react';
7+
import { GeneratingContext } from '../../context';
8+
import ScreenWrapper from '../../ScreenWrapper';
79

8-
export const ClassificationScreen = ({
9-
imageUri,
10-
setImageUri,
11-
}: {
12-
imageUri: string;
13-
setImageUri: (imageUri: string) => void;
14-
}) => {
10+
export default function ClassificationScreen() {
1511
const [results, setResults] = useState<{ label: string; score: number }[]>(
1612
[]
1713
);
14+
const [imageUri, setImageUri] = useState('');
1815

1916
const model = useClassification({
2017
modelSource: EFFICIENTNET_V2_S,
2118
});
19+
const { setGlobalGenerating } = useContext(GeneratingContext);
20+
useEffect(() => {
21+
setGlobalGenerating(model.isGenerating);
22+
}, [model.isGenerating, setGlobalGenerating]);
2223

2324
const handleCameraPress = async (isCamera: boolean) => {
2425
const image = await getImage(isCamera);
@@ -52,17 +53,16 @@ export const ClassificationScreen = ({
5253
/>
5354
);
5455
}
55-
5656
return (
57-
<>
57+
<ScreenWrapper>
5858
<View style={styles.imageContainer}>
5959
<Image
6060
style={styles.image}
6161
resizeMode="contain"
6262
source={
6363
imageUri
6464
? { uri: imageUri }
65-
: require('../assets/icons/executorch_logo.png')
65+
: require('../../assets/icons/executorch_logo.png')
6666
}
6767
/>
6868
{results.length > 0 && (
@@ -83,9 +83,9 @@ export const ClassificationScreen = ({
8383
handleCameraPress={handleCameraPress}
8484
runForward={runForward}
8585
/>
86-
</>
86+
</ScreenWrapper>
8787
);
88-
};
88+
}
8989

9090
const styles = StyleSheet.create({
9191
imageContainer: {

0 commit comments

Comments
 (0)