Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 2 additions & 12 deletions .github/workflows/build-android-llm-example.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,21 +51,11 @@ jobs:
run: |
npm install -g @expo/cli
echo "$(npm prefix -g)/bin" >> $GITHUB_PATH
- name: Cache Expo prebuild
uses: actions/cache@v5
with:
path: ${{ env.WORKING_DIRECTORY }}/android
key: ${{ runner.os }}-expo-android-${{ hashFiles('${{ env.WORKING_DIRECTORY }}/app.json', '${{ env.WORKING_DIRECTORY }}/package.json') }}
restore-keys: |
${{ runner.os }}-expo-android-
- name: Generate native Android project
working-directory: ${{ env.WORKING_DIRECTORY }}
run: |
if [ ! -d "android" ]; then
npx expo prebuild --platform android --no-install
else
echo "Android project exists, skipping prebuild"
fi
rm -rf android
npx expo prebuild --platform android --no-install
- name: Cache Gradle
uses: actions/cache@v5
with:
Expand Down
6 changes: 3 additions & 3 deletions apps/bare-rn/android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@ react {
// The root of your project, i.e. where "package.json" lives. Default is '../..'
root = file("../../")
// The folder where the react-native NPM package is. Default is ../../node_modules/react-native
reactNativeDir = file("../../../../node_modules/react-native")
reactNativeDir = file("../../node_modules/react-native")
// The folder where the react-native Codegen package is. Default is ../../node_modules/@react-native/codegen
codegenDir = file("../../../../node_modules/@react-native/codegen")
codegenDir = file("../../node_modules/@react-native/codegen")
// The cli.js file which is the React Native CLI entrypoint. Default is ../../node_modules/react-native/cli.js
cliFile = file("../../../../node_modules/react-native/cli.js")
cliFile = file("../../node_modules/react-native/cli.js")

/* Variants */
// The list of variants to that are debuggable. For those we're going to
Expand Down
9 changes: 5 additions & 4 deletions apps/bare-rn/android/settings.gradle
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
pluginManagement { includeBuild("../../../node_modules/@react-native/gradle-plugin") }
pluginManagement { includeBuild("../node_modules/@react-native/gradle-plugin") }
plugins { id("com.facebook.react.settings") }
extensions.configure(com.facebook.react.ReactSettingsExtension){ ex ->
// node_modules are hoisted to the repo root in this yarn workspace
def cliFile = new File(settings.rootDir, "../../../node_modules/@react-native-community/cli/build/bin.js").absolutePath
// bare-rn pins its own React Native via installConfig.hoistingLimits in package.json,
// so its deps live in apps/bare-rn/node_modules/ rather than the workspace root.
def cliFile = new File(settings.rootDir, "../node_modules/@react-native-community/cli/build/bin.js").absolutePath
ex.autolinkLibrariesFromCommand(["node", cliFile, "config"], new File(settings.rootDir, "../"))
}
rootProject.name = 'bare_rn'
include ':app'
includeBuild('../../../node_modules/@react-native/gradle-plugin')
includeBuild('../node_modules/@react-native/gradle-plugin')
17 changes: 17 additions & 0 deletions apps/bare-rn/ios/Podfile
Original file line number Diff line number Diff line change
Expand Up @@ -30,5 +30,22 @@ target 'bare-rn' do
:mac_catalyst_enabled => false,
# :ccache_enabled => true
)

# Workaround for Xcode 26.4 + Apple clang 21's stricter consteval
# enforcement breaking fmt 9.x (vendored by RCT-Folly in RN 0.81.x).
# See facebook/react-native#55601, fmtlib/fmt#4740. Forcing the fmt and
# RCT-Folly pod targets to C++17 makes fmt's `__cplusplus >= 202002L`
# gate fail, so `FMT_CONSTEVAL` resolves to empty inside fmt's cached
# clang module — consumers (Yoga, React-performancetimeline, etc.) then
# import a non-consteval module and the basic_format_string call site
# compiles. Applies to fmt/RCT-Folly only; remove once upstream lands.
installer.pods_project.targets.each do |target|
next unless target.name == 'fmt' || target.name == 'RCT-Folly'
target.build_configurations.each do |config|
config.build_settings['CLANG_CXX_LANGUAGE_STANDARD'] = 'c++17'
config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= ['$(inherited)']
config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] << 'FMT_USE_CONSTEVAL=0'
end
end
end
end
6 changes: 6 additions & 0 deletions apps/bare-rn/metro.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@ const config = {
workspaceRoot, // Watch the entire monorepo
],
resolver: {
// Workspace packages (react-native-executorch, bare-resource-fetcher) declare
// their own `react` devDependency, so yarn installs a second React copy at
// packages/*/node_modules/react. Without disabling hierarchical lookup, Metro
// resolves `react` per-file and the bundle ends up with two React instances —
// useState's dispatcher comes back null at runtime.
disableHierarchicalLookup: true,
nodeModulesPaths: [
path.resolve(projectRoot, 'node_modules'),
path.resolve(workspaceRoot, 'node_modules'),
Expand Down
3 changes: 3 additions & 0 deletions apps/bare-rn/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,5 +42,8 @@
},
"engines": {
"node": ">=22"
},
"installConfig": {
"hoistingLimits": "workspaces"
}
}
46 changes: 45 additions & 1 deletion apps/computer-vision/app/_layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,59 @@ import { ExpoResourceFetcher } from 'react-native-executorch-expo-resource-fetch

import ColorPalette from '../colors';
import React, { useState } from 'react';
import { Text, StyleSheet, View } from 'react-native';
import { Text, StyleSheet, View, TouchableOpacity } from 'react-native';

import {
DrawerContentComponentProps,
DrawerContentScrollView,
DrawerItemList,
} from '@react-navigation/drawer';
import { DrawerActions } from '@react-navigation/native';
import { useNavigation } from 'expo-router';
import Svg, { Rect } from 'react-native-svg';
import { GeneratingContext } from '../context';

initExecutorch({
resourceFetcher: ExpoResourceFetcher,
});

function HamburgerIcon({ tintColor }: { tintColor?: string }) {
const navigation = useNavigation();
return (
<TouchableOpacity
onPress={() => navigation.dispatch(DrawerActions.toggleDrawer())}
style={styles.hamburger}
>
<Svg width={24} height={24} viewBox="0 0 24 24">
<Rect
x={2}
y={4}
width={20}
height={2}
rx={1}
fill={tintColor ?? '#000'}
/>
<Rect
x={2}
y={11}
width={20}
height={2}
rx={1}
fill={tintColor ?? '#000'}
/>
<Rect
x={2}
y={18}
width={20}
height={2}
rx={1}
fill={tintColor ?? '#000'}
/>
</Svg>
</TouchableOpacity>
);
}

interface CustomDrawerProps extends DrawerContentComponentProps {
isGenerating: boolean;
}
Expand Down Expand Up @@ -57,6 +97,7 @@ export default function _layout() {
drawerInactiveTintColor: '#888',
headerTintColor: ColorPalette.primary,
headerTitleStyle: { color: ColorPalette.primary },
headerLeft: (props) => <HamburgerIcon tintColor={props.tintColor} />,
}}
>
<Drawer.Screen
Expand Down Expand Up @@ -146,6 +187,9 @@ export default function _layout() {
}

const styles = StyleSheet.create({
hamburger: {
marginLeft: 12,
},
centerContent: {
flex: 1,
justifyContent: 'center',
Expand Down
11 changes: 6 additions & 5 deletions apps/computer-vision/app/vision_camera/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -110,12 +110,13 @@ const TASKS: Task[] = [
},
];

const frameKillSwitch = createSynchronizable(false);
const cameraPositionSync = createSynchronizable<'front' | 'back'>('back');

export default function VisionCameraScreen() {
const insets = useSafeAreaInsets();
const router = useRouter();
const [frameKillSwitch] = useState(() => createSynchronizable(false));
const [cameraPositionSync] = useState(() =>
createSynchronizable<'front' | 'back'>('back')
);
const [activeTask, setActiveTask] = useState<TaskId>('classification');
const [activeModel, setActiveModel] = useState<ModelId>('classification');
const [canvasSize, setCanvasSize] = useState({ width: 1, height: 1 });
Expand Down Expand Up @@ -146,11 +147,11 @@ export default function VisionCameraScreen() {
frameKillSwitch.setBlocking(false);
}, 300);
return () => clearTimeout(id);
}, [activeModel]);
}, [activeModel, frameKillSwitch]);

useEffect(() => {
cameraPositionSync.setBlocking(cameraPosition);
}, [cameraPosition]);
}, [cameraPosition, cameraPositionSync]);

const handleFpsChange = useCallback((newFps: number, newMs: number) => {
setFps(newFps);
Expand Down
8 changes: 3 additions & 5 deletions apps/computer-vision/components/BottomBar.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import ColorPalette from '../colors';
import FontAwesome from '@expo/vector-icons/FontAwesome';
import DeviceInfo from 'react-native-device-info';
import Constants from 'expo-constants';
import { View, TouchableOpacity, StyleSheet, Text } from 'react-native';
import { useSafeAreaInsets } from 'react-native-safe-area-context';

Expand All @@ -25,14 +25,12 @@ export const BottomBar = ({
<FontAwesome name="photo" size={24} color={ColorPalette.primary} />
</TouchableOpacity>
<TouchableOpacity
onPress={() =>
!DeviceInfo.isEmulatorSync() && handleCameraPress(true)
}
onPress={() => Constants.isDevice && handleCameraPress(true)}
>
<FontAwesome
name="camera"
size={24}
color={DeviceInfo.isEmulatorSync() ? '#888' : ColorPalette.primary}
color={Constants.isDevice ? ColorPalette.primary : '#888'}
/>
</TouchableOpacity>
</View>
Expand Down
45 changes: 23 additions & 22 deletions apps/computer-vision/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,32 +11,32 @@
"lint": "eslint . --ext .ts,.tsx --fix"
},
"dependencies": {
"@react-native/metro-config": "^0.81.5",
"@react-navigation/drawer": "^7.8.1",
"@react-navigation/native": "^7.1.28",
"@shopify/react-native-skia": "2.4.21",
"expo": "^54.0.27",
"expo-build-properties": "~1.0.10",
"expo-constants": "~18.0.11",
"expo-font": "~14.0.10",
"expo-linking": "~8.0.10",
"expo-router": "~6.0.17",
"expo-status-bar": "~3.0.9",
"metro-config": "^0.81.5",
"react": "19.1.0",
"react-native": "0.81.5",
"react-native-device-info": "^15.0.2",
"@expo/log-box": "~55.0.10",
"@react-native/metro-config": "^0.83.0",
"@react-navigation/drawer": "^7.9.4",
"@react-navigation/native": "^7.2.2",
"@shopify/react-native-skia": "2.6.2",
"expo": "^55.0.13",
"expo-build-properties": "~55.0.13",
"expo-constants": "~55.0.13",
"expo-font": "~55.0.6",
"expo-linking": "~55.0.12",
"expo-router": "~55.0.11",
"expo-status-bar": "~55.0.5",
"metro-config": "^0.83.0",
"react": "19.2.5",
"react-native": "0.83.4",
"react-native-executorch": "workspace:*",
"react-native-executorch-expo-resource-fetcher": "workspace:*",
"react-native-gesture-handler": "~2.28.0",
"react-native-image-picker": "^7.2.2",
"react-native-gesture-handler": "~2.31.1",
"react-native-image-picker": "^8.2.1",
"react-native-loading-spinner-overlay": "^3.0.1",
"react-native-nitro-image": "0.13.1",
"react-native-nitro-modules": "0.35.4",
"react-native-reanimated": "4.3.0",
"react-native-safe-area-context": "~5.6.0",
"react-native-screens": "~4.16.0",
"react-native-svg": "15.15.3",
"react-native-reanimated": "~4.3.0",
"react-native-safe-area-context": "~5.7.0",
"react-native-screens": "~4.24.0",
"react-native-svg": "15.15.4",
"react-native-svg-transformer": "^1.5.3",
"react-native-vision-camera": "^5.0.6",
"react-native-vision-camera-worklets": "^5.0.6",
Expand All @@ -45,7 +45,8 @@
"devDependencies": {
"@babel/core": "^7.29.0",
"@types/pngjs": "^6.0.5",
"@types/react": "~19.2.0"
"@types/react": "~19.2.0",
"babel-preset-expo": "~55.0.16"
},
"private": true
}
50 changes: 45 additions & 5 deletions apps/llm/app/_layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,54 @@ import { initExecutorch } from 'react-native-executorch';
import { ExpoResourceFetcher } from 'react-native-executorch-expo-resource-fetcher';
import ColorPalette from '../colors';
import React, { useState } from 'react';
import { Text, StyleSheet, View } from 'react-native';
import { Text, StyleSheet, View, TouchableOpacity } from 'react-native';
import {
DrawerContentComponentProps,
DrawerContentScrollView,
DrawerItemList,
DrawerToggleButton,
} from '@react-navigation/drawer';
import { DrawerActions } from '@react-navigation/native';
import { useNavigation } from 'expo-router';
import Svg, { Rect } from 'react-native-svg';
import { GeneratingContext } from '../context';

function HamburgerIcon({ tintColor }: { tintColor?: string }) {
const navigation = useNavigation();
return (
<TouchableOpacity
onPress={() => navigation.dispatch(DrawerActions.toggleDrawer())}
style={styles.hamburger}
>
<Svg width={24} height={24} viewBox="0 0 24 24">
<Rect
x={2}
y={4}
width={20}
height={2}
rx={1}
fill={tintColor ?? '#000'}
/>
<Rect
x={2}
y={11}
width={20}
height={2}
rx={1}
fill={tintColor ?? '#000'}
/>
<Rect
x={2}
y={18}
width={20}
height={2}
rx={1}
fill={tintColor ?? '#000'}
/>
</Svg>
</TouchableOpacity>
);
}

initExecutorch({
resourceFetcher: ExpoResourceFetcher,
});
Expand Down Expand Up @@ -56,9 +95,7 @@ export default function _layout() {
drawerInactiveTintColor: '#888',
headerTintColor: ColorPalette.primary,
headerTitleStyle: { color: ColorPalette.primary },
headerLeft: () => (
<DrawerToggleButton tintColor={ColorPalette.primary} />
),
headerLeft: (props) => <HamburgerIcon tintColor={props.tintColor} />,
}}
>
<Drawer.Screen
Expand Down Expand Up @@ -115,6 +152,9 @@ export default function _layout() {
}

const styles = StyleSheet.create({
hamburger: {
marginLeft: 12,
},
centerContent: {
flex: 1,
justifyContent: 'center',
Expand Down
Loading
Loading