diff --git a/with-maestro/.eas/build/build-and-maestro-test.yml b/with-maestro/.eas/build/build-and-maestro-test.yml
index c204d794..8fe7361f 100644
--- a/with-maestro/.eas/build/build-and-maestro-test.yml
+++ b/with-maestro/.eas/build/build-and-maestro-test.yml
@@ -5,5 +5,5 @@ build:
- eas/maestro_test:
inputs:
flow_path: |
- maestro/home.yml
- maestro/expand_test.yml
+ maestro/dev_build/home.yml
+ maestro/dev_build/expand_test.yml
diff --git a/with-maestro/README.md b/with-maestro/README.md
index cfc7deac..49f8934d 100644
--- a/with-maestro/README.md
+++ b/with-maestro/README.md
@@ -7,9 +7,33 @@
-## 🚀 How to use
+> _Prerequisite:_ Install the Maestro app following [these instructions](https://maestro.mobile.dev/getting-started/installing-maestro).
+
+## 🚀 Quick start
- Install with `yarn` or `npm install`.
+
+## 🚀 Build and test locally with Expo Go
+
+- Start the app in Expo Go:
+ - Android: `yarn start` to start the packager, then press `a` to install and start Expo Go on Android
+ - iOS: `yarn start` to start the packager, then press `i` to install and start Expo Go on iOS
+- In a separate terminal, execute a Maestro test flow:
+ - Home screen test: `maestro test maestro/expo_go/home.yml`
+ - Expanding component test: `maestro test maestro/expo_go/expand_test.yml`
+- Once the test flow starts and Expo Go starts, select "Reload" or the app name from the Expo Go UI in the simulator/emulator. Once the dev menu is hidden and this app is visible, the test flow will continue.
+
+## 🚀 Build and test locally with a development build
+
+- Build the development build and start it on your simulator/emulator:
+ - Android: `yarn android`.
+ - iOS: `yarn ios`.
+- In a separate terminal, execute a Maestro test flow:
+ - Home screen test: `maestro test maestro/dev_build/home.yml`
+ - Expanding component test: `maestro test maestro/dev_build/expand_test.yml`
+
+## 🚀 Build and test on EAS
+
- Initialize the app as an EAS project with `eas init`.
- iOS:
- Start an EAS run to build and test the app with `eas build -e build-and-maestro-test -p ios`.
@@ -17,8 +41,9 @@
- Follow the [instructions to disable the new Android builds infrastructure for the EAS project](https://docs.expo.dev/build-reference/e2e-tests/#disable-new-android-builds-infrastructure).
- Start an EAS run to build and test the app with `eas build -e build-and-maestro-test -p android`.
-> _Note:_ The Maestro flows in the [maestro](./maestro/) folder must have the app's package name (Android) or bundle identifier (iOS) defined. To make this example work out of the box without changes, the [app.json](./app.json) and the Maestro flows are preconfigured with these values set to `dev.expo.eastestsexample`. In your actual development, these should be changed to the correct values for your app.
+> _Note:_ The Maestro flows in the [maestro/dev_build](./maestro/dev_build) folder must have the app's package name (Android) or bundle identifier (iOS) defined. To make this example work out of the box without changes, the [app.json](./app.json) and the Maestro flows for dev builds are preconfigured with these values set to `dev.expo.eastestsexample`. In your actual development, these should be changed to the correct values for your app.
## 📝 Further information
-See the Expo guide: [Run E2E Tests On EAS Build](https://docs.expo.dev/build-reference/e2e-tests/).
+- [Expo guide on E2E tests with EAS](https://docs.expo.dev/build-reference/e2e-tests/)
+- [Maestro guide on creating React Native tests](https://maestro.mobile.dev/platform-support/react-native)
diff --git a/with-maestro/app.json b/with-maestro/app.json
index a832bb01..9af42153 100644
--- a/with-maestro/app.json
+++ b/with-maestro/app.json
@@ -1,5 +1,6 @@
{
"expo": {
+ "scheme": "dev.expo.eastestsexample",
"plugins": [
"expo-router"
],
diff --git a/with-maestro/app/(tabs)/_layout.tsx b/with-maestro/app/(tabs)/_layout.tsx
index 22a49b62..2ae0ad2a 100644
--- a/with-maestro/app/(tabs)/_layout.tsx
+++ b/with-maestro/app/(tabs)/_layout.tsx
@@ -1,35 +1,32 @@
import { Tabs } from 'expo-router';
import React from 'react';
-import { TabBarIcon } from '@/components/navigation/TabBarIcon';
-import { Colors } from '@/constants/Colors';
-import { useColorScheme } from '@/hooks/useColorScheme';
-
export default function TabLayout() {
- const colorScheme = useColorScheme();
-
return (
+ }}
+ >
(
-
- ),
+ tabBarIcon: () => null,
+ tabBarLabelStyle: {
+ fontSize: 18,
+ },
}}
/>
(
-
- ),
+ tabBarIcon: () => null,
+ tabBarLabelStyle: {
+ fontSize: 18,
+ },
}}
/>
diff --git a/with-maestro/app/(tabs)/explore.tsx b/with-maestro/app/(tabs)/explore.tsx
index e480218a..e18a0142 100644
--- a/with-maestro/app/(tabs)/explore.tsx
+++ b/with-maestro/app/(tabs)/explore.tsx
@@ -1,102 +1,31 @@
-import Ionicons from '@expo/vector-icons/Ionicons';
-import { StyleSheet, Image, Platform } from 'react-native';
+import { StyleSheet, Text, SafeAreaView } from 'react-native';
import { Collapsible } from '@/components/Collapsible';
-import { ExternalLink } from '@/components/ExternalLink';
-import ParallaxScrollView from '@/components/ParallaxScrollView';
-import { ThemedText } from '@/components/ThemedText';
-import { ThemedView } from '@/components/ThemedView';
export default function TabTwoScreen() {
return (
- }>
-
- Explore
-
- This app includes example code to help you get started.
+
+ Explore
-
- This app has two screens:{' '}
- app/(tabs)/index.tsx and{' '}
- app/(tabs)/explore.tsx
-
-
- The layout file in app/(tabs)/_layout.tsx{' '}
- sets up the tab navigator.
-
-
- Learn more
-
+ This app has two screens
-
-
- You can open this project on Android, iOS, and the web. To open the web version, press{' '}
- w in the terminal running this project.
-
-
-
-
- For static images, you can use the @2x and{' '}
- @3x suffixes to provide files for
- different screen densities
-
-
-
- Learn more
-
-
-
-
- Open app/_layout.tsx to see how to load{' '}
-
- custom fonts such as this one.
-
-
-
- Learn more
-
-
-
-
- This template has light and dark mode support. The{' '}
- useColorScheme() hook lets you inspect
- what the user's current color scheme is, and so you can adjust UI colors accordingly.
-
-
- Learn more
-
-
-
-
- This template includes an example of an animated component. The{' '}
- components/HelloWave.tsx component uses
- the powerful react-native-reanimated library
- to create a waving hand animation.
-
- {Platform.select({
- ios: (
-
- The components/ParallaxScrollView.tsx{' '}
- component provides a parallax effect for the header image.
-
- ),
- })}
-
-
+
);
}
const styles = StyleSheet.create({
- headerImage: {
- color: '#808080',
- bottom: -90,
- left: -35,
- position: 'absolute',
- },
- titleContainer: {
- flexDirection: 'row',
+ container: {
+ flex: 1,
gap: 8,
+ width: '80%',
+ height: '80%',
+ marginTop: '20%',
+ marginLeft: '10%',
+ },
+ title: {
+ alignItems: 'center',
+ fontSize: 18,
+ fontWeight: 'bold',
+ marginBottom: 20,
},
});
diff --git a/with-maestro/app/(tabs)/index.tsx b/with-maestro/app/(tabs)/index.tsx
index 324aeb76..433dc79c 100644
--- a/with-maestro/app/(tabs)/index.tsx
+++ b/with-maestro/app/(tabs)/index.tsx
@@ -1,70 +1,26 @@
-import { Image, StyleSheet, Platform } from 'react-native';
-
-import { HelloWave } from '@/components/HelloWave';
-import ParallaxScrollView from '@/components/ParallaxScrollView';
-import { ThemedText } from '@/components/ThemedText';
-import { ThemedView } from '@/components/ThemedView';
+import { StyleSheet, Text, SafeAreaView } from 'react-native';
export default function HomeScreen() {
return (
-
- }>
-
- Welcome!
-
-
-
- Step 1: Try it
-
- Edit app/(tabs)/index.tsx to see changes.
- Press{' '}
-
- {Platform.select({ ios: 'cmd + d', android: 'cmd + m' })}
- {' '}
- to open developer tools.
-
-
-
- Step 2: Explore
-
- Tap the Explore tab to learn more about what's included in this starter app.
-
-
-
- Step 3: Get a fresh start
-
- When you're ready, run{' '}
- npm run reset-project to get a fresh{' '}
- app directory. This will move the current{' '}
- app to{' '}
- app-example.
-
-
-
+
+ Welcome!
+
);
}
const styles = StyleSheet.create({
- titleContainer: {
- flexDirection: 'row',
- alignItems: 'center',
+ container: {
+ flex: 1,
gap: 8,
+ width: '80%',
+ height: '80%',
+ marginTop: '20%',
+ marginLeft: '10%',
},
- stepContainer: {
- gap: 8,
- marginBottom: 8,
- },
- reactLogo: {
- height: 178,
- width: 290,
- bottom: 0,
- left: 0,
- position: 'absolute',
+ title: {
+ alignItems: 'center',
+ fontSize: 18,
+ fontWeight: 'bold',
+ marginBottom: 20,
},
});
diff --git a/with-maestro/app/(tabs)/tv_focus.tsx b/with-maestro/app/(tabs)/tv_focus.tsx
deleted file mode 100644
index 85553856..00000000
--- a/with-maestro/app/(tabs)/tv_focus.tsx
+++ /dev/null
@@ -1,73 +0,0 @@
-import Ionicons from '@expo/vector-icons/Ionicons';
-import { StyleSheet, Platform } from 'react-native';
-
-import { Collapsible } from '@/components/Collapsible';
-import ParallaxScrollView from '@/components/ParallaxScrollView';
-import { ThemedText } from '@/components/ThemedText';
-import { ThemedView } from '@/components/ThemedView';
-import { EventHandlingDemo } from '@/components/EventHandlingDemo';
-import { useScale } from '@/hooks/useScale';
-
-export default function FocusDemoScreen() {
- const styles = useFocusDemoScreenStyles();
- const scale = useScale();
- return (
-
- }
- >
-
- TV event handling demo
-
-
- Demo of focus handling and TV remote event handling in{' '}
- Pressable and{' '}
- Touchable components.
-
-
-
- On TV platforms, these components have "onFocus()" and "onBlur()"
- props, in addition to the usual "onPress()". These can be used to
- modify the style of the component when it is navigated to or navigated
- away from by the TV focus engine. In addition, the functional forms of
- the Pressable style prop and the Pressable content, which in React
- Native core take a "pressed" boolean parameter, can also take
- "focused" as a parameter on TV platforms.
-
-
- As you use the arrow keys to navigate around the screen, the demo uses
- the above props to update lists of recent events.
-
-
- {Platform.isTV ? (
-
- ) : (
-
- Run this on Apple TV or Android TV to see the demo.
-
- )}
-
- );
-}
-
-const useFocusDemoScreenStyles = function () {
- const scale = useScale();
- return StyleSheet.create({
- headerImage: {
- color: '#808080',
- bottom: -45 * scale,
- left: 0,
- position: 'absolute',
- },
- titleContainer: {
- flexDirection: 'row',
- gap: 8 * scale,
- },
- });
-};
diff --git a/with-maestro/app/+not-found.tsx b/with-maestro/app/+not-found.tsx
index 963b04fb..efa60df9 100644
--- a/with-maestro/app/+not-found.tsx
+++ b/with-maestro/app/+not-found.tsx
@@ -1,19 +1,16 @@
import { Link, Stack } from 'expo-router';
-import { StyleSheet } from 'react-native';
-
-import { ThemedText } from '@/components/ThemedText';
-import { ThemedView } from '@/components/ThemedView';
+import { StyleSheet, Text, View } from 'react-native';
export default function NotFoundScreen() {
return (
<>
-
- This screen doesn't exist.
+
+ This screen doesn't exist.
- Go to home screen!
+ Go to home screen!
-
+
>
);
}
diff --git a/with-maestro/app/_layout.tsx b/with-maestro/app/_layout.tsx
index 2e37cdd8..56c0d208 100644
--- a/with-maestro/app/_layout.tsx
+++ b/with-maestro/app/_layout.tsx
@@ -1,37 +1,10 @@
-import { DarkTheme, DefaultTheme, ThemeProvider } from '@react-navigation/native';
-import { useFonts } from 'expo-font';
import { Stack } from 'expo-router';
-import * as SplashScreen from 'expo-splash-screen';
-import { useEffect } from 'react';
-import 'react-native-reanimated';
-
-import { useColorScheme } from '@/hooks/useColorScheme';
-
-// Prevent the splash screen from auto-hiding before asset loading is complete.
-SplashScreen.preventAutoHideAsync();
export default function RootLayout() {
- const colorScheme = useColorScheme();
- const [loaded] = useFonts({
- SpaceMono: require('../assets/fonts/SpaceMono-Regular.ttf'),
- });
-
- useEffect(() => {
- if (loaded) {
- SplashScreen.hideAsync();
- }
- }, [loaded]);
-
- if (!loaded) {
- return null;
- }
-
return (
-
-
-
-
-
-
+
+
+
+
);
}
diff --git a/with-maestro/assets/fonts/SpaceMono-Regular.ttf b/with-maestro/assets/fonts/SpaceMono-Regular.ttf
deleted file mode 100755
index 28d7ff71..00000000
Binary files a/with-maestro/assets/fonts/SpaceMono-Regular.ttf and /dev/null differ
diff --git a/with-maestro/assets/images/adaptive-icon.png b/with-maestro/assets/images/adaptive-icon.png
deleted file mode 100644
index 03d6f6b6..00000000
Binary files a/with-maestro/assets/images/adaptive-icon.png and /dev/null differ
diff --git a/with-maestro/assets/images/favicon.png b/with-maestro/assets/images/favicon.png
deleted file mode 100644
index e75f697b..00000000
Binary files a/with-maestro/assets/images/favicon.png and /dev/null differ
diff --git a/with-maestro/assets/images/icon.png b/with-maestro/assets/images/icon.png
deleted file mode 100644
index a0b1526f..00000000
Binary files a/with-maestro/assets/images/icon.png and /dev/null differ
diff --git a/with-maestro/assets/images/partial-react-logo.png b/with-maestro/assets/images/partial-react-logo.png
deleted file mode 100644
index 66fd9570..00000000
Binary files a/with-maestro/assets/images/partial-react-logo.png and /dev/null differ
diff --git a/with-maestro/assets/images/react-logo.png b/with-maestro/assets/images/react-logo.png
deleted file mode 100644
index 9d72a9ff..00000000
Binary files a/with-maestro/assets/images/react-logo.png and /dev/null differ
diff --git a/with-maestro/assets/images/react-logo@2x.png b/with-maestro/assets/images/react-logo@2x.png
deleted file mode 100644
index 2229b130..00000000
Binary files a/with-maestro/assets/images/react-logo@2x.png and /dev/null differ
diff --git a/with-maestro/assets/images/react-logo@3x.png b/with-maestro/assets/images/react-logo@3x.png
deleted file mode 100644
index a99b2032..00000000
Binary files a/with-maestro/assets/images/react-logo@3x.png and /dev/null differ
diff --git a/with-maestro/assets/images/splash.png b/with-maestro/assets/images/splash.png
deleted file mode 100644
index 0e89705a..00000000
Binary files a/with-maestro/assets/images/splash.png and /dev/null differ
diff --git a/with-maestro/components/Collapsible.tsx b/with-maestro/components/Collapsible.tsx
index c326473d..ba4c410a 100644
--- a/with-maestro/components/Collapsible.tsx
+++ b/with-maestro/components/Collapsible.tsx
@@ -1,30 +1,24 @@
-import Ionicons from '@expo/vector-icons/Ionicons';
import { PropsWithChildren, useState } from 'react';
-import { StyleSheet, TouchableOpacity, useColorScheme } from 'react-native';
+import { StyleSheet, TouchableOpacity, Text, View } from 'react-native';
-import { ThemedText } from '@/components/ThemedText';
-import { ThemedView } from '@/components/ThemedView';
-import { Colors } from '@/constants/Colors';
-
-export function Collapsible({ children, title }: PropsWithChildren & { title: string }) {
+export function Collapsible({
+ children,
+ title,
+}: PropsWithChildren & { title: string }) {
const [isOpen, setIsOpen] = useState(false);
- const theme = useColorScheme() ?? 'light';
return (
-
+
setIsOpen((value) => !value)}
- activeOpacity={0.8}>
-
- {title}
+ activeOpacity={0.8}
+ >
+ {isOpen ? 'V' : '>'}
+ {title}
- {isOpen && {children}}
-
+ {isOpen && {children}}
+
);
}
diff --git a/with-maestro/components/EventHandlingDemo.tsx b/with-maestro/components/EventHandlingDemo.tsx
deleted file mode 100644
index ec8f5b88..00000000
--- a/with-maestro/components/EventHandlingDemo.tsx
+++ /dev/null
@@ -1,254 +0,0 @@
-import {
- StyleSheet,
- Text,
- View,
- useTVEventHandler,
- Platform,
- Pressable,
- TouchableHighlight,
- TouchableNativeFeedback,
- TouchableOpacity,
- GestureResponderEvent,
-} from 'react-native';
-import { useState } from 'react';
-
-import { ThemedText } from '@/components/ThemedText';
-import { ThemedView } from '@/components/ThemedView';
-import { useScale } from '@/hooks/useScale';
-import { useThemeColor } from '@/hooks/useThemeColor';
-
-export function EventHandlingDemo() {
- const [remoteEventLog, setRemoteEventLog] = useState([]);
- const [pressableEventLog, setPressableEventLog] = useState([]);
-
- const logWithAppendedEntry = (log: string[], entry: string) => {
- const limit = 3;
- const newEventLog = log.slice(0, limit - 1);
- newEventLog.unshift(entry);
- return newEventLog;
- };
-
- const updatePressableLog = (entry: string) => {
- setPressableEventLog((log) => logWithAppendedEntry(log, entry));
- };
-
- useTVEventHandler((event) => {
- const { eventType, eventKeyAction } = event;
- if (eventType !== 'focus' && eventType !== 'blur') {
- setRemoteEventLog((log) =>
- logWithAppendedEntry(
- log,
- `type=${eventType}, action=${
- eventKeyAction !== undefined ? eventKeyAction : ''
- }`,
- ),
- );
- }
- });
-
- const styles = useDemoStyles();
-
- return (
-
-
-
-
- {Platform.OS === 'android' ? (
-
- ) : null}
-
-
-
- Focus/press events
-
- {remoteEventLog.join('\n')}
-
-
-
- Remote control events
-
- {pressableEventLog.join('\n')}
-
-
-
-
- );
-}
-
-const PressableButton = (props: {
- title: string;
- log: (entry: string) => void;
-}) => {
- const styles = useDemoStyles();
-
- return (
- props.log(`${props.title} focus`)}
- onBlur={() => props.log(`${props.title} blur`)}
- onPress={() => props.log(`${props.title} pressed`)}
- onLongPress={(
- event: GestureResponderEvent & { eventKeyAction?: number },
- ) =>
- props.log(
- `${props.title} long press ${
- event.eventKeyAction === 0 ? 'start' : 'end'
- }`,
- )
- }
- style={({ pressed, focused }) =>
- pressed || focused ? styles.pressableFocused : styles.pressable
- }
- >
- {({ focused }) => {
- return (
-
- {focused ? `${props.title} focused` : props.title}
-
- );
- }}
-
- );
-};
-
-const TouchableOpacityButton = (props: {
- title: string;
- log: (entry: string) => void;
-}) => {
- const styles = useDemoStyles();
-
- return (
- props.log(`${props.title} focus`)}
- onBlur={() => props.log(`${props.title} blur`)}
- onPress={() => props.log(`${props.title} pressed`)}
- onLongPress={(
- event: GestureResponderEvent & { eventKeyAction?: number },
- ) =>
- props.log(
- `${props.title} long press ${
- event.eventKeyAction === 0 ? 'start' : 'end'
- }`,
- )
- }
- >
- {props.title}
-
- );
-};
-
-const TouchableHighlightButton = (props: {
- title: string;
- log: (entry: string) => void;
-}) => {
- const styles = useDemoStyles();
- const underlayColor = useThemeColor({}, 'tint');
-
- return (
- props.log(`${props.title} focus`)}
- onBlur={() => props.log(`${props.title} blur`)}
- onPress={() => props.log(`${props.title} pressed`)}
- onLongPress={(
- event: GestureResponderEvent & { eventKeyAction?: number },
- ) =>
- props.log(
- `${props.title} long press ${
- event.eventKeyAction === 0 ? 'start' : 'end'
- }`,
- )
- }
- >
- {props.title}
-
- );
-};
-
-const TouchableNativeFeedbackButton = (props: {
- title: string;
- log: (entry: string) => void;
-}) => {
- const styles = useDemoStyles();
-
- return (
- props.log(`${props.title} focus`)}
- onBlur={() => props.log(`${props.title} blur`)}
- onPress={() => props.log(`${props.title} pressed`)}
- onLongPress={(
- event: GestureResponderEvent & { eventKeyAction?: number },
- ) =>
- props.log(
- `${props.title} long press ${
- event.eventKeyAction === 0 ? 'start' : 'end'
- }`,
- )
- }
- >
-
- {props.title}
-
-
- );
-};
-
-const useDemoStyles = function () {
- const scale = useScale();
- const highlightColor = useThemeColor({}, 'link');
- const backgroundColor = useThemeColor({}, 'background');
- const tintColor = useThemeColor({}, 'tint');
- const textColor = useThemeColor({}, 'text');
- return StyleSheet.create({
- container: {
- flex: 1,
- alignItems: 'center',
- justifyContent: 'center',
- },
- logContainer: {
- flexDirection: 'row',
- padding: 5 * scale,
- margin: 5 * scale,
- alignItems: 'flex-start',
- justifyContent: 'flex-start',
- },
- logText: {
- height: 100 * scale,
- width: 200 * scale,
- fontSize: 10 * scale,
- margin: 5 * scale,
- alignSelf: 'flex-start',
- justifyContent: 'flex-start',
- },
- pressable: {
- borderColor: highlightColor,
- backgroundColor: textColor,
- borderWidth: 1,
- borderRadius: 5 * scale,
- margin: 5 * scale,
- },
- pressableFocused: {
- borderColor: highlightColor,
- backgroundColor: tintColor,
- borderWidth: 1,
- borderRadius: 5 * scale,
- margin: 5 * scale,
- },
- pressableText: {
- color: backgroundColor,
- fontSize: 15 * scale,
- },
- });
-};
diff --git a/with-maestro/components/ExternalLink.tsx b/with-maestro/components/ExternalLink.tsx
deleted file mode 100644
index 8f05675b..00000000
--- a/with-maestro/components/ExternalLink.tsx
+++ /dev/null
@@ -1,24 +0,0 @@
-import { Link } from 'expo-router';
-import { openBrowserAsync } from 'expo-web-browser';
-import { type ComponentProps } from 'react';
-import { Platform } from 'react-native';
-
-type Props = Omit, 'href'> & { href: string };
-
-export function ExternalLink({ href, ...rest }: Props) {
- return (
- {
- if (Platform.OS !== 'web') {
- // Prevent the default behavior of linking to the default browser on native.
- event.preventDefault();
- // Open the link in an in-app browser.
- await openBrowserAsync(href);
- }
- }}
- />
- );
-}
diff --git a/with-maestro/components/HelloWave.tsx b/with-maestro/components/HelloWave.tsx
deleted file mode 100644
index f4b6ea54..00000000
--- a/with-maestro/components/HelloWave.tsx
+++ /dev/null
@@ -1,37 +0,0 @@
-import { StyleSheet } from 'react-native';
-import Animated, {
- useSharedValue,
- useAnimatedStyle,
- withTiming,
- withRepeat,
- withSequence,
-} from 'react-native-reanimated';
-
-import { ThemedText } from '@/components/ThemedText';
-
-export function HelloWave() {
- const rotationAnimation = useSharedValue(0);
-
- rotationAnimation.value = withRepeat(
- withSequence(withTiming(25, { duration: 150 }), withTiming(0, { duration: 150 })),
- 4 // Run the animation 4 times
- );
-
- const animatedStyle = useAnimatedStyle(() => ({
- transform: [{ rotate: `${rotationAnimation.value}deg` }],
- }));
-
- return (
-
- 👋
-
- );
-}
-
-const styles = StyleSheet.create({
- text: {
- fontSize: 28,
- lineHeight: 32,
- marginTop: -6,
- },
-});
diff --git a/with-maestro/components/ParallaxScrollView.tsx b/with-maestro/components/ParallaxScrollView.tsx
deleted file mode 100644
index 0a354199..00000000
--- a/with-maestro/components/ParallaxScrollView.tsx
+++ /dev/null
@@ -1,76 +0,0 @@
-import type { PropsWithChildren, ReactElement } from 'react';
-import { StyleSheet, useColorScheme } from 'react-native';
-import Animated, {
- interpolate,
- useAnimatedRef,
- useAnimatedStyle,
- useScrollViewOffset,
-} from 'react-native-reanimated';
-
-import { ThemedView } from '@/components/ThemedView';
-
-const HEADER_HEIGHT = 250;
-
-type Props = PropsWithChildren<{
- headerImage: ReactElement;
- headerBackgroundColor: { dark: string; light: string };
-}>;
-
-export default function ParallaxScrollView({
- children,
- headerImage,
- headerBackgroundColor,
-}: Props) {
- const colorScheme = useColorScheme() ?? 'light';
- const scrollRef = useAnimatedRef();
- const scrollOffset = useScrollViewOffset(scrollRef);
-
- const headerAnimatedStyle = useAnimatedStyle(() => {
- return {
- transform: [
- {
- translateY: interpolate(
- scrollOffset.value,
- [-HEADER_HEIGHT, 0, HEADER_HEIGHT],
- [-HEADER_HEIGHT / 2, 0, HEADER_HEIGHT * 0.75]
- ),
- },
- {
- scale: interpolate(scrollOffset.value, [-HEADER_HEIGHT, 0, HEADER_HEIGHT], [2, 1, 1]),
- },
- ],
- };
- });
-
- return (
-
-
-
- {headerImage}
-
- {children}
-
-
- );
-}
-
-const styles = StyleSheet.create({
- container: {
- flex: 1,
- },
- header: {
- height: 250,
- overflow: 'hidden',
- },
- content: {
- flex: 1,
- padding: 32,
- gap: 16,
- overflow: 'hidden',
- },
-});
diff --git a/with-maestro/components/ThemedText.tsx b/with-maestro/components/ThemedText.tsx
deleted file mode 100644
index c0e1a78f..00000000
--- a/with-maestro/components/ThemedText.tsx
+++ /dev/null
@@ -1,60 +0,0 @@
-import { Text, type TextProps, StyleSheet } from 'react-native';
-
-import { useThemeColor } from '@/hooks/useThemeColor';
-
-export type ThemedTextProps = TextProps & {
- lightColor?: string;
- darkColor?: string;
- type?: 'default' | 'title' | 'defaultSemiBold' | 'subtitle' | 'link';
-};
-
-export function ThemedText({
- style,
- lightColor,
- darkColor,
- type = 'default',
- ...rest
-}: ThemedTextProps) {
- const color = useThemeColor({ light: lightColor, dark: darkColor }, 'text');
-
- return (
-
- );
-}
-
-const styles = StyleSheet.create({
- default: {
- fontSize: 16,
- lineHeight: 24,
- },
- defaultSemiBold: {
- fontSize: 16,
- lineHeight: 24,
- fontWeight: '600',
- },
- title: {
- fontSize: 32,
- fontWeight: 'bold',
- lineHeight: 32,
- },
- subtitle: {
- fontSize: 20,
- fontWeight: 'bold',
- },
- link: {
- lineHeight: 30,
- fontSize: 16,
- color: '#0a7ea4',
- },
-});
diff --git a/with-maestro/components/ThemedView.tsx b/with-maestro/components/ThemedView.tsx
deleted file mode 100644
index 4d2cb09d..00000000
--- a/with-maestro/components/ThemedView.tsx
+++ /dev/null
@@ -1,14 +0,0 @@
-import { View, type ViewProps } from 'react-native';
-
-import { useThemeColor } from '@/hooks/useThemeColor';
-
-export type ThemedViewProps = ViewProps & {
- lightColor?: string;
- darkColor?: string;
-};
-
-export function ThemedView({ style, lightColor, darkColor, ...otherProps }: ThemedViewProps) {
- const backgroundColor = useThemeColor({ light: lightColor, dark: darkColor }, 'background');
-
- return ;
-}
diff --git a/with-maestro/components/__tests__/ThemedText-test.tsx b/with-maestro/components/__tests__/ThemedText-test.tsx
deleted file mode 100644
index 1ac32250..00000000
--- a/with-maestro/components/__tests__/ThemedText-test.tsx
+++ /dev/null
@@ -1,10 +0,0 @@
-import * as React from 'react';
-import renderer from 'react-test-renderer';
-
-import { ThemedText } from '../ThemedText';
-
-it(`renders correctly`, () => {
- const tree = renderer.create(Snapshot test!).toJSON();
-
- expect(tree).toMatchSnapshot();
-});
diff --git a/with-maestro/components/__tests__/__snapshots__/ThemedText-test.tsx.snap b/with-maestro/components/__tests__/__snapshots__/ThemedText-test.tsx.snap
deleted file mode 100644
index b68e53e9..00000000
--- a/with-maestro/components/__tests__/__snapshots__/ThemedText-test.tsx.snap
+++ /dev/null
@@ -1,24 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`renders correctly 1`] = `
-
- Snapshot test!
-
-`;
diff --git a/with-maestro/components/navigation/TabBarIcon.tsx b/with-maestro/components/navigation/TabBarIcon.tsx
deleted file mode 100644
index b7302c3f..00000000
--- a/with-maestro/components/navigation/TabBarIcon.tsx
+++ /dev/null
@@ -1,9 +0,0 @@
-// You can explore the built-in icon families and icons on the web at https://icons.expo.fyi/
-
-import Ionicons from '@expo/vector-icons/Ionicons';
-import { type IconProps } from '@expo/vector-icons/build/createIconSet';
-import { type ComponentProps } from 'react';
-
-export function TabBarIcon({ style, ...rest }: IconProps['name']>) {
- return ;
-}
diff --git a/with-maestro/constants/Colors.ts b/with-maestro/constants/Colors.ts
deleted file mode 100644
index 14e67844..00000000
--- a/with-maestro/constants/Colors.ts
+++ /dev/null
@@ -1,26 +0,0 @@
-/**
- * Below are the colors that are used in the app. The colors are defined in the light and dark mode.
- * There are many other ways to style your app. For example, [Nativewind](https://www.nativewind.dev/), [Tamagui](https://tamagui.dev/), [unistyles](https://reactnativeunistyles.vercel.app), etc.
- */
-
-const tintColorLight = '#0a7ea4';
-const tintColorDark = '#fff';
-
-export const Colors = {
- light: {
- text: '#11181C',
- background: '#fff',
- tint: tintColorLight,
- icon: '#687076',
- tabIconDefault: '#687076',
- tabIconSelected: tintColorLight,
- },
- dark: {
- text: '#ECEDEE',
- background: '#151718',
- tint: tintColorDark,
- icon: '#9BA1A6',
- tabIconDefault: '#9BA1A6',
- tabIconSelected: tintColorDark,
- },
-};
diff --git a/with-maestro/constants/TextStyles.ts b/with-maestro/constants/TextStyles.ts
deleted file mode 100644
index 1295e9f0..00000000
--- a/with-maestro/constants/TextStyles.ts
+++ /dev/null
@@ -1,39 +0,0 @@
-/**
- * Below are text styles used in the app, primarily in the ThemedText component.
- */
-
-import { TextStyle } from 'react-native';
-
-export const textStyles = function (
- scale: number,
- linkColor: string,
-): {
- [key: string]: TextStyle & { fontSize: number; lineHeight: number };
-} {
- return {
- default: {
- fontSize: 16 * scale,
- lineHeight: 24 * scale,
- },
- defaultSemiBold: {
- fontSize: 16 * scale,
- lineHeight: 24 * scale,
- fontWeight: '600',
- },
- title: {
- fontSize: 32 * scale,
- fontWeight: 'bold',
- lineHeight: 32 * scale,
- },
- subtitle: {
- fontSize: 20 * scale,
- lineHeight: 20 * scale,
- fontWeight: 'bold',
- },
- link: {
- lineHeight: 30 * scale,
- fontSize: 16 * scale,
- color: linkColor,
- },
- };
-};
diff --git a/with-maestro/eas.json b/with-maestro/eas.json
index ec65eafe..829af28d 100644
--- a/with-maestro/eas.json
+++ b/with-maestro/eas.json
@@ -1,6 +1,7 @@
{
"cli": {
- "version": ">= 3.15.1"
+ "version": ">= 12.1.0",
+ "appVersionSource": "remote"
},
"build": {
"build-and-maestro-test": {
@@ -14,6 +15,19 @@
"simulator": true,
"image": "latest"
}
+ },
+ "development": {
+ "developmentClient": true,
+ "distribution": "internal"
+ },
+ "preview": {
+ "distribution": "internal"
+ },
+ "production": {
+ "autoIncrement": true
}
+ },
+ "submit": {
+ "production": {}
}
}
diff --git a/with-maestro/hooks/useColorScheme.ts b/with-maestro/hooks/useColorScheme.ts
deleted file mode 100644
index 17e3c63e..00000000
--- a/with-maestro/hooks/useColorScheme.ts
+++ /dev/null
@@ -1 +0,0 @@
-export { useColorScheme } from 'react-native';
diff --git a/with-maestro/hooks/useColorScheme.web.ts b/with-maestro/hooks/useColorScheme.web.ts
deleted file mode 100644
index 6dcd80d3..00000000
--- a/with-maestro/hooks/useColorScheme.web.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-// NOTE: The default React Native styling doesn't support server rendering.
-// Server rendered styles should not change between the first render of the HTML
-// and the first render on the client. Typically, web developers will use CSS media queries
-// to render different styles on the client and server, these aren't directly supported in React Native
-// but can be achieved using a styling library like Nativewind.
-export function useColorScheme() {
- return 'light';
-}
diff --git a/with-maestro/hooks/useScale.ts b/with-maestro/hooks/useScale.ts
deleted file mode 100644
index ea2e3e11..00000000
--- a/with-maestro/hooks/useScale.ts
+++ /dev/null
@@ -1,6 +0,0 @@
-import { Platform, useWindowDimensions } from 'react-native';
-
-export function useScale(): number {
- const { width } = useWindowDimensions();
- return Platform.isTV ? width / 1000 : 1;
-}
diff --git a/with-maestro/hooks/useScale.web.ts b/with-maestro/hooks/useScale.web.ts
deleted file mode 100644
index ea142642..00000000
--- a/with-maestro/hooks/useScale.web.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-export function useScale(): number {
- return 1.0;
-}
diff --git a/with-maestro/hooks/useTextStyles.ts b/with-maestro/hooks/useTextStyles.ts
deleted file mode 100644
index cf752b47..00000000
--- a/with-maestro/hooks/useTextStyles.ts
+++ /dev/null
@@ -1,9 +0,0 @@
-import { textStyles } from '@/constants/TextStyles';
-import { useThemeColor } from './useThemeColor';
-import { useScale } from './useScale';
-
-export function useTextStyles() {
- const linkColor = useThemeColor({}, 'link');
- const scale = useScale() ?? 1.0;
- return textStyles(scale, linkColor);
-}
diff --git a/with-maestro/hooks/useThemeColor.ts b/with-maestro/hooks/useThemeColor.ts
deleted file mode 100644
index ae43b47b..00000000
--- a/with-maestro/hooks/useThemeColor.ts
+++ /dev/null
@@ -1,22 +0,0 @@
-/**
- * Learn more about light and dark modes:
- * https://docs.expo.dev/guides/color-schemes/
- */
-
-import { useColorScheme } from 'react-native';
-
-import { Colors } from '@/constants/Colors';
-
-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;
- } else {
- return Colors[theme][colorName];
- }
-}
diff --git a/with-maestro/maestro/expand_test.yml b/with-maestro/maestro/dev_build/expand_test.yml
similarity index 100%
rename from with-maestro/maestro/expand_test.yml
rename to with-maestro/maestro/dev_build/expand_test.yml
diff --git a/with-maestro/maestro/home.yml b/with-maestro/maestro/dev_build/home.yml
similarity index 100%
rename from with-maestro/maestro/home.yml
rename to with-maestro/maestro/dev_build/home.yml
diff --git a/with-maestro/maestro/expo_go/expand_test.yml b/with-maestro/maestro/expo_go/expand_test.yml
new file mode 100644
index 00000000..5ab3647a
--- /dev/null
+++ b/with-maestro/maestro/expo_go/expand_test.yml
@@ -0,0 +1,6 @@
+appId: host.exp.Exponent # This is the app ID for testing with Expo Go.
+---
+- launchApp
+- tapOn: 'Explore.*'
+- tapOn: '.*File-based routing'
+- assertVisible: 'This app has two screens.*'
diff --git a/with-maestro/maestro/expo_go/home.yml b/with-maestro/maestro/expo_go/home.yml
new file mode 100644
index 00000000..39ad3372
--- /dev/null
+++ b/with-maestro/maestro/expo_go/home.yml
@@ -0,0 +1,4 @@
+appId: host.exp.Exponent # This is the app ID for testing with Expo Go.
+---
+- launchApp
+- assertVisible: 'Welcome!'
diff --git a/with-maestro/package.json b/with-maestro/package.json
index 1294919d..76770ad5 100644
--- a/with-maestro/package.json
+++ b/with-maestro/package.json
@@ -5,7 +5,6 @@
"scripts": {
"prebuild": "expo prebuild --clean",
"start": "expo start",
- "reset-project": "node ./scripts/reset-project.js",
"android": "expo run:android",
"ios": "expo run:ios",
"web": "expo start --web",
@@ -16,25 +15,21 @@
"preset": "jest-expo"
},
"dependencies": {
- "@expo/vector-icons": "^14.0.2",
"@react-navigation/native": "^6.0.2",
"expo": "~51.0.28",
"expo-constants": "~16.0.2",
"expo-font": "~12.0.9",
"expo-linking": "~6.3.1",
"expo-router": "~3.5.23",
- "expo-splash-screen": "~0.27.5",
"expo-status-bar": "~1.12.1",
"expo-system-ui": "~3.0.7",
- "expo-web-browser": "~13.0.3",
"react": "18.2.0",
"react-dom": "18.2.0",
"react-native": "0.74.5",
"react-native-gesture-handler": "~2.16.1",
"react-native-reanimated": "~3.10.1",
"react-native-safe-area-context": "4.10.5",
- "react-native-screens": "3.31.1",
- "react-native-web": "~0.19.10"
+ "react-native-screens": "3.31.1"
},
"devDependencies": {
"@babel/core": "^7.20.0",
diff --git a/with-maestro/scripts/reset-project.js b/with-maestro/scripts/reset-project.js
deleted file mode 100755
index 4512e162..00000000
--- a/with-maestro/scripts/reset-project.js
+++ /dev/null
@@ -1,73 +0,0 @@
-#!/usr/bin/env node
-
-/**
- * This script is used to reset the project to a blank state.
- * It moves the /app directory to /app-example and creates a new /app directory with an index.tsx and _layout.tsx file.
- * You can remove the `reset-project` script from package.json and safely delete this file after running it.
- */
-
-const fs = require('fs');
-const path = require('path');
-
-const root = process.cwd();
-const oldDirPath = path.join(root, 'app');
-const newDirPath = path.join(root, 'app-example');
-const newAppDirPath = path.join(root, 'app');
-
-const indexContent = `import { Text, View } from "react-native";
-
-export default function Index() {
- return (
-
- Edit app/index.tsx to edit this screen.
-
- );
-}
-`;
-
-const layoutContent = `import { Stack } from "expo-router";
-
-export default function RootLayout() {
- return (
-
-
-
- );
-}
-`;
-
-fs.rename(oldDirPath, newDirPath, (error) => {
- if (error) {
- return console.error(`Error renaming directory: ${error}`);
- }
- console.log('/app moved to /app-example.');
-
- fs.mkdir(newAppDirPath, { recursive: true }, (error) => {
- if (error) {
- return console.error(`Error creating new app directory: ${error}`);
- }
- console.log('New /app directory created.');
-
- const indexPath = path.join(newAppDirPath, 'index.tsx');
- fs.writeFile(indexPath, indexContent, (error) => {
- if (error) {
- return console.error(`Error creating index.tsx: ${error}`);
- }
- console.log('app/index.tsx created.');
-
- const layoutPath = path.join(newAppDirPath, '_layout.tsx');
- fs.writeFile(layoutPath, layoutContent, (error) => {
- if (error) {
- return console.error(`Error creating _layout.tsx: ${error}`);
- }
- console.log('app/_layout.tsx created.');
- });
- });
- });
-});