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
279 changes: 125 additions & 154 deletions apps/Example.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,16 @@ import {
I18nManager,
Platform,
useColorScheme,
View,
Text,
} from 'react-native';
import {
NavigationContainer,
NavigationIndependentTree,
useTheme,
} from '@react-navigation/native';
import { StackNavigationProp } from '@react-navigation/stack';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
import RNRestart from 'react-native-restart';

import { ListItem, SettingsSwitch, ThemedText } from './src/shared';

import SimpleNativeStack from './src/screens/SimpleNativeStack';
import SwipeBackAnimation from './src/screens/SwipeBackAnimation';
import StackPresentation from './src/screens/StackPresentation';
Expand All @@ -34,10 +32,15 @@ import BarButtonItems from './src/screens/BarButtonItems';

import { GestureDetectorProvider } from 'react-native-screens/gesture-handler';
import { GestureHandlerRootView } from 'react-native-gesture-handler';

import * as Tests from './src/tests';
import { ScreensDarkTheme, ScreensLightTheme } from './src/shared/styling/adapter/react-navigation';

import LegacyTestsScreen from './src/tests/LegacyTestsScreen';
import SingleFeatureTests from './src/tests/single-feature-tests';
import ComponentIntegrationTests from './src/tests/component-integration-tests';
import { SafeAreaView } from 'react-native-safe-area-context';
import Colors from './src/shared/styling/Colors';
import { TestScenarioGroup, TestScenarioListItem, TestScenarioSettingsSwitch } from './src/tests/shared/landing-screen-components';

function isPlatformReady(name: keyof typeof SCREENS) {
if (Platform.isTV) {
return !!SCREENS[name].isTVOSReady;
Expand All @@ -46,16 +49,12 @@ function isPlatformReady(name: keyof typeof SCREENS) {
return true;
}

function isTestSectionEnabled() {
return true;
}

const SCREENS: Record<
string,
{
title: string;
component: () => React.JSX.Element;
type: 'example' | 'playground' | 'test';
type: 'example' | 'playground';
isTVOSReady?: boolean;
}
> = {
Expand Down Expand Up @@ -135,159 +134,108 @@ const SCREENS: Record<
},
};

if (isTestSectionEnabled()) {
Object.keys(Tests).forEach(testName => {
SCREENS[testName] = {
title: testName,
component: () => {
const TestComponent = Tests[testName as keyof typeof Tests];
return (
<NavigationIndependentTree>
<TestComponent />
</NavigationIndependentTree>
);
},
type: 'test',
};
});
}

const screens = Object.keys(SCREENS);
const examples = screens.filter(name => SCREENS[name].type === 'example');
const playgrounds = screens.filter(name => SCREENS[name].type === 'playground');
const issueRegex = /Test(?<issue>\d+)(?<case>.*)/
const tests = isTestSectionEnabled()
? screens
.filter(name => SCREENS[name].type === 'test')
.sort((name1, name2) => {
const spec1 = issueRegex.exec(name1)?.groups
const spec2 = issueRegex.exec(name2)?.groups

const testNumber1 = parseInt(spec1?.issue as string)
const testNumber2 = parseInt(spec2?.issue as string)

if (Number.isNaN(testNumber1) && Number.isNaN(testNumber2)) {
return 0;
} else if (Number.isNaN(testNumber1)) {
return 1;
} else if (Number.isNaN(testNumber2)) {
return -1;
} else if (testNumber1 !== testNumber2) {
return testNumber1 - testNumber2;
} else if ((spec1?.case as string) < (spec2?.case as string)) {
return -1;
} else {
return (spec1?.case as string) > (spec2?.case as string) ? 1 : 0;
}
})
: [];

type RootStackParamList = {
Main: undefined;
Tests: undefined;
SingleFeatureTests: undefined;
ComponentIntegrationTests: undefined;
LegacyTests: undefined;
} & {
[P in keyof typeof SCREENS]: undefined;
};

const Stack = createNativeStackNavigator<RootStackParamList>();

interface MainScreenProps {
navigation: StackNavigationProp<RootStackParamList, 'Main'>;
}

const MainScreen = ({ navigation }: MainScreenProps): React.JSX.Element => {
function MainScreen() {
const { toggleTheme } = useContext(ThemeToggle);
const isDark = useTheme().dark;
const [searchQuery, setSearchQuery] = React.useState('');
const [searchBarEnabled, setSearchBarEnabled] = React.useState(false);
const titleStyle = isDark ? styles.titleDark : styles.title;

React.useLayoutEffect(() => {
if (searchBarEnabled) {
navigation.setOptions({
headerSearchBarOptions: {
onChangeText: (event) => setSearchQuery(event.nativeEvent.text),
},
});
} else {
setSearchQuery('');
navigation.setOptions({
headerSearchBarOptions: undefined,
});
}
}, [navigation, searchBarEnabled]);
return (
<SafeAreaView
edges={{ top: 'maximum', bottom: 'maximum' }}
style={{ backgroundColor: isDark ? "#000000" : Colors.White }}
>
<ScrollView
testID="root-screen-examples-scrollview"
style={styles.container}
>
<View style={{ marginBottom: 20 }}>
<Text style={titleStyle}>Welcome to</Text>
<Text style={[titleStyle, { fontWeight: 'bold' }]}>react-native-screens</Text>
</View>

const searchFilter = React.useCallback(
(name: string) =>
searchQuery === '' ||
name.toLowerCase().includes(searchQuery.toLowerCase()),
[searchQuery],
);
<View style={styles.group}>
<TestScenarioSettingsSwitch
label="Right to left"
value={I18nManager.isRTL}
onValueChange={() => {
I18nManager.forceRTL(!I18nManager.isRTL);
RNRestart.Restart();
}}
testID="root-screen-switch-rtl"
/>
<TestScenarioSettingsSwitch
label="Dark mode"
value={isDark}
onValueChange={toggleTheme}
testID="root-screen-switch-dark-mode"
/>
</View>

const filteredExamples = examples.filter(searchFilter);
const filteredPlaygrounds = playgrounds.filter(searchFilter);
const filteredTests = tests.filter(searchFilter);
<Text style={titleStyle}>Examples</Text>

return (
<ScrollView testID="root-screen-examples-scrollview" contentInsetAdjustmentBehavior="automatic">
<SettingsSwitch
style={styles.switch}
label="Right to left"
value={I18nManager.isRTL}
onValueChange={() => {
I18nManager.forceRTL(!I18nManager.isRTL);
RNRestart.Restart();
}}
testID="root-screen-switch-rtl"
/>
<SettingsSwitch
style={styles.switch}
label="Dark mode"
value={isDark}
onValueChange={toggleTheme}
/>
<SettingsSwitch
style={styles.switch}
label="Search bar"
value={searchBarEnabled}
onValueChange={() => setSearchBarEnabled(!searchBarEnabled)}
testID="root-screen-switch-search-bar"
/>
<ThemedText style={styles.label} testID="root-screen-examples-header">
Examples
</ThemedText>
{filteredExamples.map(name => (
<ListItem
key={name}
testID={`root-screen-example-${name}`}
title={SCREENS[name].title}
onPress={() => navigation.navigate(name)}
disabled={!isPlatformReady(name)}
/>
))}
<ThemedText style={styles.label}>Playgrounds</ThemedText>
{filteredPlaygrounds.map(name => (
<ListItem
key={name}
testID={`root-screen-playground-${name}`}
title={SCREENS[name].title}
onPress={() => navigation.navigate(name)}
disabled={!isPlatformReady(name)}
/>
))}
{isTestSectionEnabled() && (
<ThemedText style={styles.label}>Tests</ThemedText>
)}
{isTestSectionEnabled() &&
filteredTests.map(name => (
<ListItem
key={name}
testID={`root-screen-tests-${name}`}
title={SCREENS[name].title}
onPress={() => navigation.navigate(name)}
disabled={false}
<TestScenarioGroup>
{examples.map(name => (
<TestScenarioListItem
key={name}
testID={`root-screen-example-${name}`}
title={SCREENS[name].title}
route={name}
disabled={!isPlatformReady(name)}
/>
))}
</TestScenarioGroup>

<Text style={titleStyle}>Playgrounds</Text>

<TestScenarioGroup>
{playgrounds.map(name => (
<TestScenarioListItem
key={name}
testID={`root-screen-playground-${name}`}
title={SCREENS[name].title}
route={name}
disabled={!isPlatformReady(name)}
/>
))}
</TestScenarioGroup>

<Text style={titleStyle}>Looking for more?</Text>

<View style={[styles.group, { marginTop: 20 }]}>
<TestScenarioListItem
testID="root-screen-single-feature-tests"
title="Single Feature Tests"
route="SingleFeatureTests"
/>
<TestScenarioListItem
testID="root-screen-component-integration-tests"
title="Component Integration Tests"
route="ComponentIntegrationTests"
/>
))}
</ScrollView>
<TestScenarioListItem
testID="root-screen-legacy-tests"
title="Legacy Tests"
route="LegacyTests"
/>
</View>
</ScrollView>
</SafeAreaView>
);
};

Expand All @@ -310,10 +258,7 @@ const ExampleApp = (): React.JSX.Element => {
screenOptions={{ statusBarStyle: isDark ? 'light' : 'dark' }}>
<Stack.Screen
name="Main"
options={{
title: `${Platform.isTV ? '📺' : '📱'
} React Native Screens Examples`,
}}
options={{ headerShown: false }}
component={MainScreen}
/>
{Object.keys(SCREENS).map(name => (
Expand All @@ -324,6 +269,24 @@ const ExampleApp = (): React.JSX.Element => {
options={{ headerShown: false }}
/>
))}
<Stack.Screen
key="SingleFeatureTests"
name="SingleFeatureTests"
options={{ headerShown: false }}
component={SingleFeatureTests}
/>
<Stack.Screen
key="ComponentIntegrationTests"
name="ComponentIntegrationTests"
options={{ headerShown: false }}
component={ComponentIntegrationTests}
/>
<Stack.Screen
key="LegacyTests"
name="LegacyTests"
options={{ headerShown: false }}
component={LegacyTestsScreen}
/>
</Stack.Navigator>
</NavigationContainer>
</ThemeToggle.Provider>
Expand All @@ -333,13 +296,21 @@ const ExampleApp = (): React.JSX.Element => {
};

const styles = StyleSheet.create({
label: {
fontSize: 15,
margin: 10,
marginTop: 15,
container: {
padding: 20,
},
group: {
flex: 1,
gap: 20,
marginBottom: 20,
},
title: {
fontSize: 32,
color: Colors.NavyLight100,
},
switch: {
marginTop: 15,
titleDark: {
fontSize: 32,
color: Colors.GreenDark60,
},
});

Expand Down
Loading