Skip to content

Commit 4aa3b9a

Browse files
authored
chore(example): app restructure (#119)
Restructures example apps into organized sections: - **demos/** - User-facing tutorials with marketplace links - **exercisers/** - Developer testing, edge cases, stress tests - **tests/** - Test runner UI (integrated from #106) - **reproducers/** - Bug reproduction (`local/` gitignored for throwaway files) Also wires up the 🔧 wrench menu "Run Tests" to navigate to TestsPage in both example and expo-example. <img width="300" alt="image" src="https://github.com/user-attachments/assets/c9afbfe3-cb68-4957-9256-2bdfb47d22d6" /> <img width="300" alt="image" src="https://github.com/user-attachments/assets/5e33696a-14f1-4d31-8f7e-681ba4a4ec63" />
1 parent 65bc6f1 commit 4aa3b9a

32 files changed

+803
-458
lines changed

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,3 +86,7 @@ android/generated
8686

8787
# ktlint binary cache
8888
.ktlint/
89+
90+
# Local reproducers (not checked in)
91+
example/src/reproducers/local/*
92+
!example/src/reproducers/local/.gitkeep

example/__tests__/rive.harness.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ describe('RiveFile Loading', () => {
1313

1414
it('fromURL works', async () => {
1515
const file = await RiveFileFactory.fromURL(
16-
'http://localhost:8081/assets/assets/rive/viewmodelproperty.riv',
16+
'https://cdn.rive.app/animations/vehicles.riv',
1717
undefined
1818
);
1919
expect(file).toBeDefined();

example/ios/Podfile.lock

Lines changed: 86 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -1755,6 +1755,30 @@ PODS:
17551755
- React-perflogger (= 0.79.2)
17561756
- React-utils (= 0.79.2)
17571757
- RiveRuntime (6.13.0)
1758+
- RNCAsyncStorage (2.2.0):
1759+
- DoubleConversion
1760+
- glog
1761+
- hermes-engine
1762+
- RCT-Folly (= 2024.11.18.00)
1763+
- RCTRequired
1764+
- RCTTypeSafety
1765+
- React-Core
1766+
- React-debug
1767+
- React-Fabric
1768+
- React-featureflags
1769+
- React-graphics
1770+
- React-hermes
1771+
- React-ImageManager
1772+
- React-jsi
1773+
- React-NativeModulesApple
1774+
- React-RCTFabric
1775+
- React-renderercss
1776+
- React-rendererdebug
1777+
- React-utils
1778+
- ReactCodegen
1779+
- ReactCommon/turbomodule/bridging
1780+
- ReactCommon/turbomodule/core
1781+
- Yoga
17581782
- RNCPicker (2.11.4):
17591783
- DoubleConversion
17601784
- glog
@@ -1880,7 +1904,7 @@ PODS:
18801904
- ReactCommon/turbomodule/core
18811905
- RNWorklets
18821906
- Yoga
1883-
- RNRive (0.1.4):
1907+
- RNRive (0.1.5):
18841908
- DoubleConversion
18851909
- glog
18861910
- hermes-engine
@@ -2057,6 +2081,7 @@ DEPENDENCIES:
20572081
- ReactAppDependencyProvider (from `build/generated/ios`)
20582082
- ReactCodegen (from `build/generated/ios`)
20592083
- ReactCommon/turbomodule/core (from `../node_modules/react-native/ReactCommon`)
2084+
- "RNCAsyncStorage (from `../node_modules/@react-native-async-storage/async-storage`)"
20602085
- "RNCPicker (from `../node_modules/@react-native-picker/picker`)"
20612086
- RNGestureHandler (from `../node_modules/react-native-gesture-handler`)
20622087
- RNReanimated (from `../node_modules/react-native-reanimated`)
@@ -2213,6 +2238,8 @@ EXTERNAL SOURCES:
22132238
:path: build/generated/ios
22142239
ReactCommon:
22152240
:path: "../node_modules/react-native/ReactCommon"
2241+
RNCAsyncStorage:
2242+
:path: "../node_modules/@react-native-async-storage/async-storage"
22162243
RNCPicker:
22172244
:path: "../node_modules/@react-native-picker/picker"
22182245
RNGestureHandler:
@@ -2234,78 +2261,79 @@ SPEC CHECKSUMS:
22342261
fmt: a40bb5bd0294ea969aaaba240a927bd33d878cdd
22352262
glog: 5683914934d5b6e4240e497e0f4a3b42d1854183
22362263
hermes-engine: 314be5250afa5692b57b4dd1705959e1973a8ebe
2237-
NitroModules: 0af9a8516f3d8f101976d60e1f34e2a22f401600
2238-
RCT-Folly: e78785aa9ba2ed998ea4151e314036f6c49e6d82
2264+
NitroModules: 7f50ee216f8403e8eb243acfc504f3f856d6914c
2265+
RCT-Folly: 36fe2295e44b10d831836cc0d1daec5f8abcf809
22392266
RCTDeprecation: 83ffb90c23ee5cea353bd32008a7bca100908f8c
22402267
RCTRequired: eb7c0aba998009f47a540bec9e9d69a54f68136e
22412268
RCTTypeSafety: 659ae318c09de0477fd27bbc9e140071c7ea5c93
22422269
React: c2d3aa44c49bb34e4dfd49d3ee92da5ebacc1c1c
22432270
React-callinvoker: 1bdfb7549b5af266d85757193b5069f60659ef9d
2244-
React-Core: 10597593fdbae06f0089881e025a172e51d4a769
2245-
React-CoreModules: 6907b255529dd46895cf687daa67b24484a612c2
2246-
React-cxxreact: a9f5b8180d6955bc3f6a3fcd657c4d9b4d95c1f6
2271+
React-Core: 7150cf9b6a5af063b37003062689f1691e79c020
2272+
React-CoreModules: 15a85e6665d61678942da6ae485b351f4c699049
2273+
React-cxxreact: 74f9de59259ac951923f5726aa14f0398f167af9
22472274
React-debug: e74e76912b91e08d580c481c34881899ccf63da9
2248-
React-defaultsnativemodule: 11f6ee2cf69bf3af9d0f28a6253def33d21b5266
2249-
React-domnativemodule: f940bbc4fa9e134190acbf3a4a9f95621b5a8f51
2250-
React-Fabric: 6f5c357bf3a42ff11f8844ad3fc7a1eb04f4b9de
2251-
React-FabricComponents: 10e0c0209822ac9e69412913a8af1ca33573379b
2252-
React-FabricImage: f582e764072dfa4715ae8c42979a5bace9cbcc12
2275+
React-defaultsnativemodule: 628285212bbd65417d40ad6a9f8781830fda6c98
2276+
React-domnativemodule: 185d9808198405c176784aaf33403d713bd24fb7
2277+
React-Fabric: c814804affbe1952e16149ddd20256e1bccae67e
2278+
React-FabricComponents: 81ef47d596966121784afec9924f9562a29b1691
2279+
React-FabricImage: f14f371d678aa557101def954ac3ba27e48948ff
22532280
React-featureflags: d5facceff8f8f6de430e0acecf4979a9a0839ba9
2254-
React-featureflagsnativemodule: a7dd141f1ef4b7c1331af0035689fbc742a49ff4
2255-
React-graphics: 36ae3407172c1c77cea29265d2b12b90aaef6aa0
2256-
React-hermes: 9116d4e6d07abeb519a2852672de087f44da8f12
2257-
React-idlecallbacksnativemodule: ae7f5ffc6cf2d2058b007b78248e5b08172ad5c3
2258-
React-ImageManager: 9daee0dc99ad6a001d4b9e691fbf37107e2b7b54
2259-
React-jserrorhandler: 1e6211581071edaf4ecd5303147328120c73f4dc
2260-
React-jsi: 753ba30c902f3a41fa7f956aca8eea3317a44ee6
2261-
React-jsiexecutor: 47520714aa7d9589c51c0f3713dfbfca4895d4f9
2262-
React-jsinspector: cfd27107f6d6f1076a57d88c932401251560fe5f
2263-
React-jsinspectortracing: 76a7d791f3c0c09a0d2bf6f46dfb0e79a4fcc0ac
2264-
React-jsitooling: 995e826570dd58f802251490486ebd3244a037ab
2265-
React-jsitracing: 094ae3d8c123cea67b50211c945b7c0443d3e97b
2266-
React-logger: 8edfcedc100544791cd82692ca5a574240a16219
2267-
React-Mapbuffer: c3f4b608e4a59dd2f6a416ef4d47a14400194468
2268-
React-microtasksnativemodule: 054f34e9b82f02bd40f09cebd4083828b5b2beb6
2269-
react-native-safe-area-context: 0b8555c40461feb7198e999912a3446602e7c601
2270-
React-NativeModulesApple: 2c4377e139522c3d73f5df582e4f051a838ff25e
2281+
React-featureflagsnativemodule: 96f0ab285382d95c90f663e02526a5ceefa95a11
2282+
React-graphics: 1a66ee0a3f093b125b853f6370296fadcaf6f233
2283+
React-hermes: 8b86e5f54a65ecb69cdf22b3a00a11562eda82d2
2284+
React-idlecallbacksnativemodule: 5c25ab145c602264d00cb26a397ab52e0efa031c
2285+
React-ImageManager: 15e34bd5ef1ac4a18e96660817ef70a7f99ee8c2
2286+
React-jserrorhandler: 02cdf2cd45350108be1ffd2b164578936dbbdff7
2287+
React-jsi: 6af1987cfbb1b6621664fdbf6c7b62bd4d38c923
2288+
React-jsiexecutor: 51f372998e0303585cb0317232b938d694663cbd
2289+
React-jsinspector: 3539ad976d073bfaa8a7d2fa9bef35e70e55033e
2290+
React-jsinspectortracing: e8dbacaf67c201f23052ca1c2bae2f7b84dec443
2291+
React-jsitooling: 95a34f41e3c249d42181de13b4f8d854f178ca9f
2292+
React-jsitracing: 25b029cf5cad488252d46da19dd8c4c134fd5fe4
2293+
React-logger: 368570a253f00879a1e4fea24ed4047e72e7bbf3
2294+
React-Mapbuffer: c04fcda1c6281fc0a6824c7dcc1633dd217ac1ec
2295+
React-microtasksnativemodule: ca2804a25fdcefffa0aa942aa23ab53b99614a34
2296+
react-native-safe-area-context: bc59472155ffb889a1ffe16c19a04c0cd451562b
2297+
React-NativeModulesApple: 452b86b29fae99ed0a4015dca3ad9cd222f88abf
22712298
React-oscompat: ef5df1c734f19b8003e149317d041b8ce1f7d29c
2272-
React-perflogger: 9a151e0b4c933c9205fd648c246506a83f31395d
2273-
React-performancetimeline: 5b0dfc0acba29ea0269ddb34cd6dd59d3b8a1c66
2299+
React-perflogger: 6fd2f6811533e9c19a61e855c3033eecbf4ad2a0
2300+
React-performancetimeline: abf31259d794c9274b3ea19c5016186925eec6c4
22742301
React-RCTActionSheet: a499b0d6d9793886b67ba3e16046a3fef2cdbbc3
2275-
React-RCTAnimation: cc64adc259aabc3354b73065e2231d796dfce576
2276-
React-RCTAppDelegate: 9d523da768f1c9e84c5f3b7e3624d097dfb0e16b
2277-
React-RCTBlob: e727f53eeefded7e6432eb76bd22b57bc880e5d1
2278-
React-RCTFabric: 58590aa4fdb4ad546c06a7449b486cf6844e991f
2279-
React-RCTFBReactNativeSpec: 9064c63d99e467a3893e328ba3612745c3c3a338
2280-
React-RCTImage: 7159cbdbb18a09d97ba1a611416eced75b3ccb29
2281-
React-RCTLinking: 46293afdb859bccc63e1d3dedc6901a3c04ef360
2282-
React-RCTNetwork: 4a6cd18f5bcd0363657789c64043123a896b1170
2283-
React-RCTRuntime: 5ab904fd749aa52f267ef771d265612582a17880
2284-
React-RCTSettings: 61e361dc85136d1cb0e148b7541993d2ee950ea7
2285-
React-RCTText: abd1e196c3167175e6baef18199c6d9d8ac54b4e
2286-
React-RCTVibration: 490e0dcb01a3fe4a0dfb7bc51ad5856d8b84f343
2302+
React-RCTAnimation: 2595dcb10a82216a511b54742f8c28d793852ac6
2303+
React-RCTAppDelegate: f03604b70f57c9469a84a159d8abecf793a5bcff
2304+
React-RCTBlob: e00f9b4e2f151938f4d9864cf33ebf24ac03328a
2305+
React-RCTFabric: 3945d116fd271598db262d4e6ed5691d431ed9e8
2306+
React-RCTFBReactNativeSpec: 0f4d4f0da938101f2ca9d5333a8f46e527ad2819
2307+
React-RCTImage: dac5e9f8ec476aefe6e60ee640ebc1dfaf1a4dbe
2308+
React-RCTLinking: 494b785a40d952a1dfbe712f43214376e5f0e408
2309+
React-RCTNetwork: b3d7c30cd21793e268db107dd0980cb61b3c1c44
2310+
React-RCTRuntime: a8ff419d437228e7b8a793b14f9d711e1cbb82af
2311+
React-RCTSettings: a060c7e381a3896104761b8eed7e284d95e37df3
2312+
React-RCTText: 4f272b72dbb61f390d8c8274528f9fdbff983806
2313+
React-RCTVibration: 0e5326220719aca12473d703aa46693e3b4ce67a
22872314
React-rendererconsistency: 351fdbc5c1fe4da24243d939094a80f0e149c7a1
2288-
React-renderercss: 3438814bee838ae7840a633ab085ac81699fd5cf
2289-
React-rendererdebug: 0ac2b9419ad6f88444f066d4b476180af311fb1e
2315+
React-renderercss: d333f2ada83969591100d91ec6b23ca2e17e1507
2316+
React-rendererdebug: 039e5949b72ba63c703de020701e3fd152434c61
22902317
React-rncore: 57ed480649bb678d8bdc386d20fee8bf2b0c307c
2291-
React-RuntimeApple: 8b7a9788f31548298ba1990620fe06b40de65ad7
2292-
React-RuntimeCore: e03d96fbd57ce69fd9bca8c925942194a5126dbc
2318+
React-RuntimeApple: 344a5e1105256000afabaa8df12c3e4cab880340
2319+
React-RuntimeCore: 0e48fb5e5160acc0334c7a723a42d42cef4b58b6
22932320
React-runtimeexecutor: d60846710facedd1edb70c08b738119b3ee2c6c2
2294-
React-RuntimeHermes: aab794755d9f6efd249b61f3af4417296904e3ba
2295-
React-runtimescheduler: c3cd124fa5db7c37f601ee49ca0d97019acd8788
2321+
React-RuntimeHermes: 064286a03871d932c99738e0f8ef854962ab4b99
2322+
React-runtimescheduler: e917ab17ae08c204af1ebf8f669b7e411b0220c8
22962323
React-timing: a90f4654cbda9c628614f9bee68967f1768bd6a5
2297-
React-utils: a612d50555b6f0f90c74b7d79954019ad47f5de6
2298-
ReactAppDependencyProvider: 04d5eb15eb46be6720e17a4a7fa92940a776e584
2299-
ReactCodegen: c63eda03ba1d94353fb97b031fc84f75a0d125ba
2300-
ReactCommon: 76d2dc87136d0a667678668b86f0fca0c16fdeb0
2324+
React-utils: 51c4e71608b8133fecc9a15801d244ae7bdf3758
2325+
ReactAppDependencyProvider: d5dcc564f129632276bd3184e60f053fcd574d6b
2326+
ReactCodegen: fda99a79c866370190e162083a35602fdc314e5d
2327+
ReactCommon: 4d0da92a5eb8da86c08e3ec34bd23ab439fb2461
23012328
RiveRuntime: 903690a5ba698b2a7e8d462e8aa7ceeba862614c
2302-
RNCPicker: 28c076ae12a1056269ec0305fe35fac3086c477d
2303-
RNGestureHandler: 6b39f4e43e4b3a0fb86de9531d090ff205a011d5
2304-
RNReanimated: 66b68ebe3baf7ec9e716bd059d700726f250d344
2305-
RNRive: 18b5afca5883b3511187e5024bb58849f74e49fa
2306-
RNWorklets: b1faafefb82d9f29c4018404a0fb33974b494a7b
2329+
RNCAsyncStorage: 2cf7d05f5b1bc38680b6c83971e535a6ae9c5bc7
2330+
RNCPicker: 83c74db2de8274d8a8f3e18d91dea174a708f8c4
2331+
RNGestureHandler: bff91bb5ab5688265c70f74180ef718b94f33fe3
2332+
RNReanimated: 9a24892f34ea317264883806d2e3de7ce34eab90
2333+
RNRive: 73aa1ec7d3ef4da1030e81643808adb538bc05ca
2334+
RNWorklets: ddf16938b1ed7e878563a4fc8a690968ef3d27f1
23072335
SocketRocket: d4aabe649be1e368d1318fdf28a022d714d65748
2308-
Yoga: c758bfb934100bb4bf9cbaccb52557cee35e8bdf
2336+
Yoga: 9f110fc4b7aa538663cba3c14cbb1c335f43c13f
23092337

23102338
PODFILE CHECKSUM: 6974e58448067deb1048e3b4490e929f624eea3c
23112339

example/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
"test:harness:android": "react-native-harness --harnessRunner android"
1313
},
1414
"dependencies": {
15+
"@react-native-async-storage/async-storage": "^2.1.2",
1516
"@react-native-picker/picker": "^2.11.4",
1617
"@react-navigation/native": "^7.1.9",
1718
"@react-navigation/stack": "^7.3.2",

example/src/App.tsx

Lines changed: 85 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,20 @@
1+
import { useEffect, useState } from 'react';
12
import {
23
View,
34
Text,
45
StyleSheet,
56
TouchableOpacity,
6-
ScrollView,
7+
ActionSheetIOS,
8+
Platform,
9+
Alert,
710
} from 'react-native';
8-
import { NavigationContainer } from '@react-navigation/native';
11+
import { NavigationContainer, useNavigation } from '@react-navigation/native';
912
import { createStackNavigator } from '@react-navigation/stack';
10-
import { PagesList } from './PagesList';
13+
import AsyncStorage from '@react-native-async-storage/async-storage';
14+
import { PagesList, type PageItem } from './PagesList';
15+
import { HomeMenu } from './shared/HomeMenu';
16+
17+
const LAST_OPENED_KEY = '@rive_example_last_opened';
1118

1219
type RootStackParamList = {
1320
Home: undefined;
@@ -17,22 +24,74 @@ type RootStackParamList = {
1724

1825
const Stack = createStackNavigator<RootStackParamList>();
1926

27+
function invokeGC() {
28+
if (typeof global.gc === 'function') {
29+
global.gc();
30+
Alert.alert('GC', 'Garbage collection invoked');
31+
} else {
32+
Alert.alert('GC', 'GC not available (Hermes debugger not attached)');
33+
}
34+
}
35+
36+
function HeaderMenuButton() {
37+
const navigation = useNavigation<any>();
38+
39+
const openTests = () => {
40+
navigation.navigate('TestsPage');
41+
};
42+
43+
const showDevMenu = () => {
44+
const options = ['Run Tests', 'Invoke GC', 'Cancel'];
45+
const cancelButtonIndex = 2;
46+
47+
if (Platform.OS === 'ios') {
48+
ActionSheetIOS.showActionSheetWithOptions(
49+
{ options, cancelButtonIndex },
50+
(buttonIndex) => {
51+
if (buttonIndex === 0) {
52+
openTests();
53+
} else if (buttonIndex === 1) {
54+
invokeGC();
55+
}
56+
}
57+
);
58+
} else {
59+
Alert.alert('Dev Menu', undefined, [
60+
{ text: 'Run Tests', onPress: openTests },
61+
{ text: 'Invoke GC', onPress: invokeGC },
62+
{ text: 'Cancel', style: 'cancel' },
63+
]);
64+
}
65+
};
66+
67+
return (
68+
<TouchableOpacity onPress={showDevMenu} style={styles.headerButton}>
69+
<Text style={styles.headerButtonText}>🔧</Text>
70+
</TouchableOpacity>
71+
);
72+
}
73+
2074
function HomeScreen({ navigation }: { navigation: any }) {
75+
const [lastOpened, setLastOpened] = useState<PageItem | null>(null);
76+
77+
useEffect(() => {
78+
AsyncStorage.getItem(LAST_OPENED_KEY).then((id) => {
79+
if (id) {
80+
const page = PagesList.find((p) => p.id === id);
81+
if (page) setLastOpened(page);
82+
}
83+
});
84+
}, []);
85+
86+
const handleNavigate = (id: string) => {
87+
AsyncStorage.setItem(LAST_OPENED_KEY, id);
88+
navigation.navigate(id);
89+
};
90+
2191
return (
22-
<ScrollView style={styles.container}>
23-
<Text style={styles.header}>Rive React Native Examples</Text>
24-
<View style={styles.buttonContainer}>
25-
{PagesList.map(({ id, name }) => (
26-
<TouchableOpacity
27-
key={id}
28-
style={styles.button}
29-
onPress={() => navigation.navigate(id)}
30-
>
31-
<Text style={styles.buttonText}>{name}</Text>
32-
</TouchableOpacity>
33-
))}
34-
</View>
35-
</ScrollView>
92+
<View style={styles.container}>
93+
<HomeMenu lastOpened={lastOpened} onNavigate={handleNavigate} />
94+
</View>
3695
);
3796
}
3897

@@ -53,7 +112,10 @@ export default function App() {
53112
<Stack.Screen
54113
name="Home"
55114
component={HomeScreen}
56-
options={{ title: 'Rive Examples' }}
115+
options={{
116+
title: 'Rive Examples',
117+
headerRight: HeaderMenuButton,
118+
}}
57119
/>
58120
{PagesList.map(({ id, component, name }) => (
59121
<Stack.Screen
@@ -73,26 +135,12 @@ const styles = StyleSheet.create({
73135
flex: 1,
74136
backgroundColor: '#fff',
75137
},
76-
header: {
77-
fontSize: 28,
78-
fontWeight: 'bold',
79-
textAlign: 'center',
80-
marginTop: 40,
81-
marginBottom: 30,
82-
},
83-
buttonContainer: {
84-
padding: 20,
85-
},
86-
button: {
87-
backgroundColor: '#007AFF',
88-
padding: 15,
89-
borderRadius: 10,
90-
marginBottom: 15,
138+
headerButton: {
139+
marginRight: 16,
140+
padding: 4,
91141
},
92-
buttonText: {
142+
headerButtonText: {
143+
fontSize: 22,
93144
color: '#fff',
94-
fontSize: 16,
95-
fontWeight: 'bold',
96-
textAlign: 'center',
97145
},
98146
});

0 commit comments

Comments
 (0)