From 0f790ce4e94946427f079410ab2f0feb7ab40073 Mon Sep 17 00:00:00 2001 From: LJ <81748770+elle-j@users.noreply.github.com> Date: Mon, 9 Oct 2023 13:18:46 +0200 Subject: [PATCH] Refactor preexisting example app with focus on offline support (#6172) * Set up RN project. * Move files from 'example' into this new project. * Remove example from workspaces. * Align on how to open Realms. * Export colors as named. * Move 'LoginScreen' to screens directory. * Align the use of function components. * Refactor task manager to separate business and view concerns. * Remove unnecessary app wrapper after the refactor. * Refactor 'OfflineModeButton' to separate business and view concerns. * Update comments about the use of the babel plugin. * Add backend (App Services App). * Write README. * Update styles to match our React and Electron apps. * Improve accessibility. * Update intro text. * Show the returned error message on the login screen. * Pass user ID instead of using 'useUser()' to allow 'AppNonSync' to run. * Update README. * Update TS docs. * Remove previous commented out metro config. * Specify RN CLI Quickstart in README. * Update README. --- example/.eslintrc.js | 4 - example/.node-version | 1 - example/.prettierrc.js | 7 - example/.watchmanconfig | 1 - example/Gemfile.lock | 100 - .../app/src/main/res/values/strings.xml | 3 - .../android/gradle/wrapper/gradle-wrapper.jar | Bin 59821 -> 0 bytes example/android/settings.gradle | 4 - example/app.json | 4 - example/app/AppNonSync.tsx | 22 - example/app/AppSync.tsx | 64 - example/app/AppWrapperNonSync.tsx | 26 - example/app/AppWrapperSync.tsx | 48 - example/app/components/AddTaskForm.tsx | 71 - example/app/components/IntroText.tsx | 51 - example/app/components/LoginScreen.tsx | 130 - example/app/components/OfflineModeButton.tsx | 42 - example/app/components/TaskItem.tsx | 81 - example/app/components/TaskList.tsx | 44 - example/app/components/TaskManager.tsx | 121 - example/app/models/Task.ts | 22 - example/app/models/index.ts | 3 - example/app/styles/button.ts | 20 - example/app/styles/colors.ts | 10 - example/app/styles/shadows.ts | 17 - example/babel.config.js | 7 - example/index.js | 19 - example/ios/Podfile.lock | 635 - .../xcshareddata/IDEWorkspaceChecks.plist | 8 - example/metro.config.js | 6 - example/sync.config.js | 6 - examples/rn-todo-list/README.md | 218 + examples/rn-todo-list/backend/README.md | 7 + .../backend/auth/custom_user_data.json | 3 + .../rn-todo-list/backend/auth/providers.json | 22 + .../TodoList/Task/relationships.json | 1 + .../mongodb-atlas/TodoList/Task/rules.json | 23 + .../mongodb-atlas/TodoList/Task/schema.json | 28 + .../data_sources/mongodb-atlas/config.json | 10 + .../mongodb-atlas/default_rule.json | 17 + .../backend/environments/development.json | 3 + .../backend/environments/no-environment.json | 3 + .../backend/environments/production.json | 3 + .../rn-todo-list/backend/environments/qa.json | 3 + .../backend/environments/testing.json | 3 + .../backend/functions/config.json | 1 + .../rn-todo-list/backend/graphql/config.json | 4 + .../backend/http_endpoints/config.json | 1 + .../rn-todo-list/backend/realm_config.json | 7 + .../rn-todo-list/backend/sync/config.json | 19 + .../rn-todo-list/frontend}/.bundle/config | 0 examples/rn-todo-list/frontend/.eslintrc.js | 22 + .../rn-todo-list/frontend}/.gitignore | 3 + examples/rn-todo-list/frontend/.prettierrc.js | 25 + .../rn-todo-list/frontend}/.ruby-version | 0 .../rn-todo-list/frontend/.watchmanconfig | 1 + .../rn-todo-list/frontend}/Gemfile | 4 +- examples/rn-todo-list/frontend/README.md | 5 + .../frontend/__tests__/App.test.tsx | 5 +- .../frontend}/android/app/build.gradle | 61 +- .../frontend}/android/app/debug.keystore | Bin .../frontend}/android/app/proguard-rules.pro | 0 .../android/app/src/debug/AndroidManifest.xml | 0 .../ReactNativeFlipper.java | 2 +- .../android/app/src/main/AndroidManifest.xml | 0 .../com/examplerntodolist}/MainActivity.java | 9 +- .../examplerntodolist}/MainApplication.java | 2 +- .../res/drawable/rn_edit_text_material.xml | 2 +- .../src/main/res/mipmap-hdpi/ic_launcher.png | Bin .../res/mipmap-hdpi/ic_launcher_round.png | Bin .../src/main/res/mipmap-mdpi/ic_launcher.png | Bin .../res/mipmap-mdpi/ic_launcher_round.png | Bin .../src/main/res/mipmap-xhdpi/ic_launcher.png | Bin .../res/mipmap-xhdpi/ic_launcher_round.png | Bin .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin .../res/mipmap-xxhdpi/ic_launcher_round.png | Bin .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin .../res/mipmap-xxxhdpi/ic_launcher_round.png | Bin .../app/src/main/res/values/strings.xml | 3 + .../app/src/main/res/values/styles.xml | 0 .../ReactNativeFlipper.java | 2 +- .../frontend}/android/build.gradle | 2 +- .../frontend}/android/gradle.properties | 2 +- .../android/gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 61574 bytes .../gradle/wrapper/gradle-wrapper.properties | 3 +- .../rn-todo-list/frontend}/android/gradlew | 18 +- .../frontend}/android/gradlew.bat | 15 +- .../frontend/android/settings.gradle | 4 + examples/rn-todo-list/frontend/app.json | 4 + .../rn-todo-list/frontend/app/AppNonSync.tsx | 49 + .../rn-todo-list/frontend/app/AppSync.tsx | 89 + .../app/assets/atlas-app-services.png | Bin 0 -> 40752 bytes .../app/assets/screenshot-login-and-tasks.png | Bin 0 -> 1119276 bytes .../frontend/app/components/AddTaskForm.tsx | 93 + .../frontend/app/components/IntroText.tsx | 89 + .../app/components/OfflineModeButton.tsx | 42 + .../frontend/app/components/SwitchPanel.tsx | 57 + .../frontend/app/components/TaskItem.tsx | 128 + .../frontend/app/components/TaskList.tsx | 62 + .../frontend/app/hooks/useSyncConnection.ts | 64 + .../frontend/app/hooks/useTaskManager.ts | 124 + .../rn-todo-list/frontend/app/models/Task.ts | 43 + .../rn-todo-list/frontend/app/models/index.ts | 23 + .../frontend/app/screens/LoginScreen.tsx | 174 + .../frontend/app/screens/TaskScreen.tsx | 78 + .../frontend/app/screens/TaskScreenSync.tsx | 105 + .../frontend/app/styles/colors.ts | 27 + .../rn-todo-list/frontend/babel.config.js | 25 + examples/rn-todo-list/frontend/index.js | 36 + .../rn-todo-list/frontend}/ios/.xcode.env | 0 .../project.pbxproj | 189 +- .../xcschemes/ExampleRnTodoList.xcscheme | 24 +- .../contents.xcworkspacedata | 2 +- .../ios/ExampleRnTodoList}/AppDelegate.h | 0 .../ios/ExampleRnTodoList}/AppDelegate.mm | 12 +- .../AppIcon.appiconset/Contents.json | 0 .../Images.xcassets/Contents.json | 0 .../ios/ExampleRnTodoList}/Info.plist | 2 +- .../LaunchScreen.storyboard | 2 +- .../frontend/ios/ExampleRnTodoList}/main.m | 0 .../ExampleRnTodoListTests.m | 4 +- .../ios/ExampleRnTodoListTests}/Info.plist | 0 .../rn-todo-list/frontend}/ios/Podfile | 17 +- .../rn-todo-list/frontend/ios/Podfile.lock | 725 + examples/rn-todo-list/frontend/jest.config.js | 21 + .../rn-todo-list/frontend/metro.config.js | 29 + .../rn-todo-list/frontend/package-lock.json | 20356 ++++++++++++++++ .../rn-todo-list/frontend}/package.json | 26 +- examples/rn-todo-list/frontend/sync.config.js | 24 + .../rn-todo-list/frontend}/tsconfig.json | 0 package-lock.json | 398 +- package.json | 1 - 132 files changed, 23134 insertions(+), 2153 deletions(-) delete mode 100644 example/.eslintrc.js delete mode 100644 example/.node-version delete mode 100644 example/.prettierrc.js delete mode 100644 example/.watchmanconfig delete mode 100644 example/Gemfile.lock delete mode 100644 example/android/app/src/main/res/values/strings.xml delete mode 100644 example/android/gradle/wrapper/gradle-wrapper.jar delete mode 100644 example/android/settings.gradle delete mode 100644 example/app.json delete mode 100644 example/app/AppNonSync.tsx delete mode 100644 example/app/AppSync.tsx delete mode 100644 example/app/AppWrapperNonSync.tsx delete mode 100644 example/app/AppWrapperSync.tsx delete mode 100644 example/app/components/AddTaskForm.tsx delete mode 100644 example/app/components/IntroText.tsx delete mode 100644 example/app/components/LoginScreen.tsx delete mode 100644 example/app/components/OfflineModeButton.tsx delete mode 100644 example/app/components/TaskItem.tsx delete mode 100644 example/app/components/TaskList.tsx delete mode 100644 example/app/components/TaskManager.tsx delete mode 100644 example/app/models/Task.ts delete mode 100644 example/app/models/index.ts delete mode 100644 example/app/styles/button.ts delete mode 100644 example/app/styles/colors.ts delete mode 100644 example/app/styles/shadows.ts delete mode 100644 example/babel.config.js delete mode 100644 example/index.js delete mode 100644 example/ios/Podfile.lock delete mode 100644 example/ios/RealmExample.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist delete mode 100644 example/metro.config.js delete mode 100644 example/sync.config.js create mode 100644 examples/rn-todo-list/README.md create mode 100644 examples/rn-todo-list/backend/README.md create mode 100644 examples/rn-todo-list/backend/auth/custom_user_data.json create mode 100644 examples/rn-todo-list/backend/auth/providers.json create mode 100644 examples/rn-todo-list/backend/data_sources/mongodb-atlas/TodoList/Task/relationships.json create mode 100644 examples/rn-todo-list/backend/data_sources/mongodb-atlas/TodoList/Task/rules.json create mode 100644 examples/rn-todo-list/backend/data_sources/mongodb-atlas/TodoList/Task/schema.json create mode 100644 examples/rn-todo-list/backend/data_sources/mongodb-atlas/config.json create mode 100644 examples/rn-todo-list/backend/data_sources/mongodb-atlas/default_rule.json create mode 100644 examples/rn-todo-list/backend/environments/development.json create mode 100644 examples/rn-todo-list/backend/environments/no-environment.json create mode 100644 examples/rn-todo-list/backend/environments/production.json create mode 100644 examples/rn-todo-list/backend/environments/qa.json create mode 100644 examples/rn-todo-list/backend/environments/testing.json create mode 100644 examples/rn-todo-list/backend/functions/config.json create mode 100644 examples/rn-todo-list/backend/graphql/config.json create mode 100644 examples/rn-todo-list/backend/http_endpoints/config.json create mode 100644 examples/rn-todo-list/backend/realm_config.json create mode 100644 examples/rn-todo-list/backend/sync/config.json rename {example => examples/rn-todo-list/frontend}/.bundle/config (100%) create mode 100644 examples/rn-todo-list/frontend/.eslintrc.js rename {example => examples/rn-todo-list/frontend}/.gitignore (97%) create mode 100644 examples/rn-todo-list/frontend/.prettierrc.js rename {example => examples/rn-todo-list/frontend}/.ruby-version (100%) create mode 100644 examples/rn-todo-list/frontend/.watchmanconfig rename {example => examples/rn-todo-list/frontend}/Gemfile (53%) create mode 100644 examples/rn-todo-list/frontend/README.md rename example/__tests__/App-test.tsx => examples/rn-todo-list/frontend/__tests__/App.test.tsx (65%) rename {example => examples/rn-todo-list/frontend}/android/app/build.gradle (64%) rename {example => examples/rn-todo-list/frontend}/android/app/debug.keystore (100%) rename {example => examples/rn-todo-list/frontend}/android/app/proguard-rules.pro (100%) rename {example => examples/rn-todo-list/frontend}/android/app/src/debug/AndroidManifest.xml (100%) rename {example/android/app/src/debug/java/com/realmexample => examples/rn-todo-list/frontend/android/app/src/debug/java/com/examplerntodolist}/ReactNativeFlipper.java (99%) rename {example => examples/rn-todo-list/frontend}/android/app/src/main/AndroidManifest.xml (100%) rename {example/android/app/src/main/java/com/realmexample => examples/rn-todo-list/frontend/android/app/src/main/java/com/examplerntodolist}/MainActivity.java (74%) rename {example/android/app/src/main/java/com/realmexample => examples/rn-todo-list/frontend/android/app/src/main/java/com/examplerntodolist}/MainApplication.java (98%) rename {example => examples/rn-todo-list/frontend}/android/app/src/main/res/drawable/rn_edit_text_material.xml (99%) rename {example => examples/rn-todo-list/frontend}/android/app/src/main/res/mipmap-hdpi/ic_launcher.png (100%) rename {example => examples/rn-todo-list/frontend}/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png (100%) rename {example => examples/rn-todo-list/frontend}/android/app/src/main/res/mipmap-mdpi/ic_launcher.png (100%) rename {example => examples/rn-todo-list/frontend}/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png (100%) rename {example => examples/rn-todo-list/frontend}/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png (100%) rename {example => examples/rn-todo-list/frontend}/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png (100%) rename {example => examples/rn-todo-list/frontend}/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png (100%) rename {example => examples/rn-todo-list/frontend}/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png (100%) rename {example => examples/rn-todo-list/frontend}/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png (100%) rename {example => examples/rn-todo-list/frontend}/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png (100%) create mode 100644 examples/rn-todo-list/frontend/android/app/src/main/res/values/strings.xml rename {example => examples/rn-todo-list/frontend}/android/app/src/main/res/values/styles.xml (100%) rename {example/android/app/src/release/java/com/realmexample => examples/rn-todo-list/frontend/android/app/src/release/java/com/examplerntodolist}/ReactNativeFlipper.java (95%) rename {example => examples/rn-todo-list/frontend}/android/build.gradle (90%) rename {example => examples/rn-todo-list/frontend}/android/gradle.properties (98%) create mode 100644 examples/rn-todo-list/frontend/android/gradle/wrapper/gradle-wrapper.jar rename {example => examples/rn-todo-list/frontend}/android/gradle/wrapper/gradle-wrapper.properties (83%) rename {example => examples/rn-todo-list/frontend}/android/gradlew (93%) rename {example => examples/rn-todo-list/frontend}/android/gradlew.bat (86%) create mode 100644 examples/rn-todo-list/frontend/android/settings.gradle create mode 100644 examples/rn-todo-list/frontend/app.json create mode 100644 examples/rn-todo-list/frontend/app/AppNonSync.tsx create mode 100644 examples/rn-todo-list/frontend/app/AppSync.tsx create mode 100644 examples/rn-todo-list/frontend/app/assets/atlas-app-services.png create mode 100644 examples/rn-todo-list/frontend/app/assets/screenshot-login-and-tasks.png create mode 100644 examples/rn-todo-list/frontend/app/components/AddTaskForm.tsx create mode 100644 examples/rn-todo-list/frontend/app/components/IntroText.tsx create mode 100644 examples/rn-todo-list/frontend/app/components/OfflineModeButton.tsx create mode 100644 examples/rn-todo-list/frontend/app/components/SwitchPanel.tsx create mode 100644 examples/rn-todo-list/frontend/app/components/TaskItem.tsx create mode 100644 examples/rn-todo-list/frontend/app/components/TaskList.tsx create mode 100644 examples/rn-todo-list/frontend/app/hooks/useSyncConnection.ts create mode 100644 examples/rn-todo-list/frontend/app/hooks/useTaskManager.ts create mode 100644 examples/rn-todo-list/frontend/app/models/Task.ts create mode 100644 examples/rn-todo-list/frontend/app/models/index.ts create mode 100644 examples/rn-todo-list/frontend/app/screens/LoginScreen.tsx create mode 100644 examples/rn-todo-list/frontend/app/screens/TaskScreen.tsx create mode 100644 examples/rn-todo-list/frontend/app/screens/TaskScreenSync.tsx create mode 100644 examples/rn-todo-list/frontend/app/styles/colors.ts create mode 100644 examples/rn-todo-list/frontend/babel.config.js create mode 100644 examples/rn-todo-list/frontend/index.js rename {example => examples/rn-todo-list/frontend}/ios/.xcode.env (100%) rename {example/ios/RealmExample.xcodeproj => examples/rn-todo-list/frontend/ios/ExampleRnTodoList.xcodeproj}/project.pbxproj (67%) rename example/ios/RealmExample.xcodeproj/xcshareddata/xcschemes/RealmExample.xcscheme => examples/rn-todo-list/frontend/ios/ExampleRnTodoList.xcodeproj/xcshareddata/xcschemes/ExampleRnTodoList.xcscheme (78%) rename {example/ios/RealmExample.xcworkspace => examples/rn-todo-list/frontend/ios/ExampleRnTodoList.xcworkspace}/contents.xcworkspacedata (77%) rename {example/ios/RealmExample => examples/rn-todo-list/frontend/ios/ExampleRnTodoList}/AppDelegate.h (100%) rename {example/ios/RealmExample => examples/rn-todo-list/frontend/ios/ExampleRnTodoList}/AppDelegate.mm (62%) rename {example/ios/RealmExample => examples/rn-todo-list/frontend/ios/ExampleRnTodoList}/Images.xcassets/AppIcon.appiconset/Contents.json (100%) rename {example/ios/RealmExample => examples/rn-todo-list/frontend/ios/ExampleRnTodoList}/Images.xcassets/Contents.json (100%) rename {example/ios/RealmExample => examples/rn-todo-list/frontend/ios/ExampleRnTodoList}/Info.plist (97%) rename {example/ios/RealmExample => examples/rn-todo-list/frontend/ios/ExampleRnTodoList}/LaunchScreen.storyboard (94%) rename {example/ios/RealmExample => examples/rn-todo-list/frontend/ios/ExampleRnTodoList}/main.m (100%) rename example/ios/RealmExampleTests/RealmExampleTests.m => examples/rn-todo-list/frontend/ios/ExampleRnTodoListTests/ExampleRnTodoListTests.m (95%) rename {example/ios/RealmExampleTests => examples/rn-todo-list/frontend/ios/ExampleRnTodoListTests}/Info.plist (100%) rename {example => examples/rn-todo-list/frontend}/ios/Podfile (77%) create mode 100644 examples/rn-todo-list/frontend/ios/Podfile.lock create mode 100644 examples/rn-todo-list/frontend/jest.config.js create mode 100644 examples/rn-todo-list/frontend/metro.config.js create mode 100644 examples/rn-todo-list/frontend/package-lock.json rename {example => examples/rn-todo-list/frontend}/package.json (60%) create mode 100644 examples/rn-todo-list/frontend/sync.config.js rename {example => examples/rn-todo-list/frontend}/tsconfig.json (100%) diff --git a/example/.eslintrc.js b/example/.eslintrc.js deleted file mode 100644 index 40c6dcd05f..0000000000 --- a/example/.eslintrc.js +++ /dev/null @@ -1,4 +0,0 @@ -module.exports = { - root: true, - extends: '@react-native-community', -}; diff --git a/example/.node-version b/example/.node-version deleted file mode 100644 index b6a7d89c68..0000000000 --- a/example/.node-version +++ /dev/null @@ -1 +0,0 @@ -16 diff --git a/example/.prettierrc.js b/example/.prettierrc.js deleted file mode 100644 index 2b540746a7..0000000000 --- a/example/.prettierrc.js +++ /dev/null @@ -1,7 +0,0 @@ -module.exports = { - arrowParens: 'avoid', - bracketSameLine: true, - bracketSpacing: false, - singleQuote: true, - trailingComma: 'all', -}; diff --git a/example/.watchmanconfig b/example/.watchmanconfig deleted file mode 100644 index 9e26dfeeb6..0000000000 --- a/example/.watchmanconfig +++ /dev/null @@ -1 +0,0 @@ -{} \ No newline at end of file diff --git a/example/Gemfile.lock b/example/Gemfile.lock deleted file mode 100644 index cc5d8137fa..0000000000 --- a/example/Gemfile.lock +++ /dev/null @@ -1,100 +0,0 @@ -GEM - remote: https://rubygems.org/ - specs: - CFPropertyList (3.0.6) - rexml - activesupport (6.1.7.2) - concurrent-ruby (~> 1.0, >= 1.0.2) - i18n (>= 1.6, < 2) - minitest (>= 5.1) - tzinfo (~> 2.0) - zeitwerk (~> 2.3) - addressable (2.8.1) - public_suffix (>= 2.0.2, < 6.0) - algoliasearch (1.27.5) - httpclient (~> 2.8, >= 2.8.3) - json (>= 1.5.1) - atomos (0.1.3) - claide (1.1.0) - cocoapods (1.11.3) - addressable (~> 2.8) - claide (>= 1.0.2, < 2.0) - cocoapods-core (= 1.11.3) - cocoapods-deintegrate (>= 1.0.3, < 2.0) - cocoapods-downloader (>= 1.4.0, < 2.0) - cocoapods-plugins (>= 1.0.0, < 2.0) - cocoapods-search (>= 1.0.0, < 2.0) - cocoapods-trunk (>= 1.4.0, < 2.0) - cocoapods-try (>= 1.1.0, < 2.0) - colored2 (~> 3.1) - escape (~> 0.0.4) - fourflusher (>= 2.3.0, < 3.0) - gh_inspector (~> 1.0) - molinillo (~> 0.8.0) - nap (~> 1.0) - ruby-macho (>= 1.0, < 3.0) - xcodeproj (>= 1.21.0, < 2.0) - cocoapods-core (1.11.3) - activesupport (>= 5.0, < 7) - addressable (~> 2.8) - algoliasearch (~> 1.0) - concurrent-ruby (~> 1.1) - fuzzy_match (~> 2.0.4) - nap (~> 1.0) - netrc (~> 0.11) - public_suffix (~> 4.0) - typhoeus (~> 1.0) - cocoapods-deintegrate (1.0.5) - cocoapods-downloader (1.6.3) - cocoapods-plugins (1.0.0) - nap - cocoapods-search (1.0.1) - cocoapods-trunk (1.6.0) - nap (>= 0.8, < 2.0) - netrc (~> 0.11) - cocoapods-try (1.2.0) - colored2 (3.1.2) - concurrent-ruby (1.2.0) - escape (0.0.4) - ethon (0.16.0) - ffi (>= 1.15.0) - ffi (1.15.5) - fourflusher (2.3.1) - fuzzy_match (2.0.4) - gh_inspector (1.1.3) - httpclient (2.8.3) - i18n (1.12.0) - concurrent-ruby (~> 1.0) - json (2.6.3) - minitest (5.17.0) - molinillo (0.8.0) - nanaimo (0.3.0) - nap (1.1.0) - netrc (0.11.0) - public_suffix (4.0.7) - rexml (3.2.5) - ruby-macho (2.5.1) - typhoeus (1.4.0) - ethon (>= 0.9.0) - tzinfo (2.0.6) - concurrent-ruby (~> 1.0) - xcodeproj (1.22.0) - CFPropertyList (>= 2.3.3, < 4.0) - atomos (~> 0.1.3) - claide (>= 1.0.2, < 2.0) - colored2 (~> 3.1) - nanaimo (~> 0.3.0) - rexml (~> 3.2.4) - zeitwerk (2.6.7) - -PLATFORMS - ruby - -DEPENDENCIES - cocoapods (~> 1.11, >= 1.11.3) - -RUBY VERSION - ruby 2.7.6p219 - -BUNDLED WITH - 2.1.4 diff --git a/example/android/app/src/main/res/values/strings.xml b/example/android/app/src/main/res/values/strings.xml deleted file mode 100644 index 1049fe7bd3..0000000000 --- a/example/android/app/src/main/res/values/strings.xml +++ /dev/null @@ -1,3 +0,0 @@ - - RealmExample - diff --git a/example/android/gradle/wrapper/gradle-wrapper.jar b/example/android/gradle/wrapper/gradle-wrapper.jar deleted file mode 100644 index 41d9927a4d4fb3f96a785543079b8df6723c946b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 59821 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 diff --git a/example/android/settings.gradle b/example/android/settings.gradle deleted file mode 100644 index d6de414b1c..0000000000 --- a/example/android/settings.gradle +++ /dev/null @@ -1,4 +0,0 @@ -rootProject.name = 'RealmExample' -apply from: file("../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesSettingsGradle(settings) -include ':app' -includeBuild('../../node_modules/react-native-gradle-plugin') diff --git a/example/app.json b/example/app.json deleted file mode 100644 index b29f45af6c..0000000000 --- a/example/app.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "name": "RealmExample", - "displayName": "RealmExample" -} \ No newline at end of file diff --git a/example/app/AppNonSync.tsx b/example/app/AppNonSync.tsx deleted file mode 100644 index e4e93b4a27..0000000000 --- a/example/app/AppNonSync.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import React from 'react'; - -import {Task} from './models/Task'; -import {TaskManager} from './components/TaskManager'; - -import {useQuery} from '@realm/react'; - -export const AppNonSync = () => { - const [showDone, setShowDone] = React.useState(false); - const tasks = useQuery( - Task, - collection => - showDone - ? collection.sorted('createdAt') - : collection.filtered('isComplete == false').sorted('createdAt'), - [showDone], - ); - - return ( - - ); -}; diff --git a/example/app/AppSync.tsx b/example/app/AppSync.tsx deleted file mode 100644 index a34ba257c8..0000000000 --- a/example/app/AppSync.tsx +++ /dev/null @@ -1,64 +0,0 @@ -import React, {useEffect, useState} from 'react'; -import {useApp, useAuth, useQuery, useRealm, useUser} from '@realm/react'; -import {Pressable, StyleSheet, Text} from 'react-native'; - -import {Task} from './models/Task'; -import {TaskManager} from './components/TaskManager'; -import {buttonStyles} from './styles/button'; -import {shadows} from './styles/shadows'; -import colors from './styles/colors'; -import {OfflineModeButton} from './components/OfflineModeButton'; - -export const AppSync: React.FC = () => { - const realm = useRealm(); - const user = useUser(); - const app = useApp(); - const {logOut} = useAuth(); - const [showDone, setShowDone] = useState(false); - const tasks = useQuery( - Task, - collection => - showDone - ? collection.sorted('createdAt') - : collection.filtered('isComplete == false').sorted('createdAt'), - [showDone], - ); - - useEffect(() => { - realm.subscriptions.update(mutableSubs => { - mutableSubs.add(tasks); - }); - }, [realm, tasks]); - - return ( - <> - Syncing with app id: {app.id} - - - {`Logout ${user?.profile.email}`} - - - - ); -}; - -const styles = StyleSheet.create({ - idText: { - color: '#999', - paddingHorizontal: 20, - }, - authButton: { - ...buttonStyles.button, - ...shadows, - backgroundColor: colors.purpleDark, - }, - authButtonText: { - ...buttonStyles.text, - }, -}); diff --git a/example/app/AppWrapperNonSync.tsx b/example/app/AppWrapperNonSync.tsx deleted file mode 100644 index 39eb6bf243..0000000000 --- a/example/app/AppWrapperNonSync.tsx +++ /dev/null @@ -1,26 +0,0 @@ -import React from 'react'; -import {SafeAreaView, StyleSheet} from 'react-native'; - -import colors from './styles/colors'; -import {AppNonSync} from './AppNonSync'; - -import {RealmProvider} from '@realm/react'; -import {schemas} from './models'; - -export const AppWrapperNonSync = () => { - // If sync is disabled, setup the app without any sync functionality and return early - return ( - - - - - - ); -}; - -const styles = StyleSheet.create({ - screen: { - flex: 1, - backgroundColor: colors.darkBlue, - }, -}); diff --git a/example/app/AppWrapperSync.tsx b/example/app/AppWrapperSync.tsx deleted file mode 100644 index 954e5744c6..0000000000 --- a/example/app/AppWrapperSync.tsx +++ /dev/null @@ -1,48 +0,0 @@ -import React from 'react'; -import {AppProvider, UserProvider} from '@realm/react'; -import {SafeAreaView, StyleSheet} from 'react-native'; - -import {schemas} from './models'; -import {LoginScreen} from './components/LoginScreen'; -import colors from './styles/colors'; -import {AppSync} from './AppSync'; - -import {RealmProvider} from '@realm/react'; -import {OpenRealmBehaviorType, OpenRealmTimeOutBehavior} from 'realm'; - -export const AppWrapperSync: React.FC<{ - appId: string; -}> = ({appId}) => { - // If we are logged in, add the sync configuration the the RealmProvider and render the app - return ( - - - }> - - - - - - - ); -}; - -const styles = StyleSheet.create({ - screen: { - flex: 1, - backgroundColor: colors.darkBlue, - }, -}); - -export default AppWrapperSync; diff --git a/example/app/components/AddTaskForm.tsx b/example/app/components/AddTaskForm.tsx deleted file mode 100644 index 4fb09b64c3..0000000000 --- a/example/app/components/AddTaskForm.tsx +++ /dev/null @@ -1,71 +0,0 @@ -import React, {useState} from 'react'; -import { - View, - Text, - TextInput, - Pressable, - Platform, - StyleSheet, -} from 'react-native'; - -import {buttonStyles} from '../styles/button'; -import colors from '../styles/colors'; -import {shadows} from '../styles/shadows'; - -type AddTaskFormProps = { - onSubmit: (description: string) => void; -}; - -export const AddTaskForm: React.FC = ({onSubmit}) => { - const [description, setDescription] = useState(''); - - const handleSubmit = () => { - onSubmit(description); - setDescription(''); - }; - - return ( - - - - - - - ); -}; - -const styles = StyleSheet.create({ - form: { - height: 50, - marginBottom: 20, - flexDirection: 'row', - ...shadows, - }, - textInput: { - flex: 1, - paddingHorizontal: 15, - paddingVertical: Platform.OS === 'ios' ? 15 : 0, - borderRadius: 5, - backgroundColor: colors.white, - fontSize: 17, - }, - submit: { - ...buttonStyles.button, - width: 50, - height: '100%', - paddingHorizontal: 0, - paddingVertical: 0, - marginLeft: 20, - marginRight: 0, - }, - icon: { - ...buttonStyles.text, - }, -}); diff --git a/example/app/components/IntroText.tsx b/example/app/components/IntroText.tsx deleted file mode 100644 index b54ebd8e06..0000000000 --- a/example/app/components/IntroText.tsx +++ /dev/null @@ -1,51 +0,0 @@ -import React from 'react'; -import {View, Text, Pressable, StyleSheet} from 'react-native'; -// @ts-ignore openURLInBrowser will open the url in your machine browser. (This isn't currently typed in React Native) -import openURLInBrowser from 'react-native/Libraries/Core/Devtools/openURLInBrowser'; - -import colors from '../styles/colors'; - -export const IntroText = () => { - return ( - - - Welcome to the Realm React Native TypeScript Template - - - Start adding a task using the form at the top of the screen to see how - they are created in Realm. You can also toggle the task status or remove - it from the list. - - - Learn more about the React Native Realm SDK at: - - - openURLInBrowser('https://docs.mongodb.com/realm/sdk/react-native/') - }> - - docs.mongodb.com/realm/sdk/react-native - - - - ); -}; - -const styles = StyleSheet.create({ - content: { - flex: 1, - marginHorizontal: 20, - justifyContent: 'center', - }, - paragraph: { - marginVertical: 10, - textAlign: 'center', - color: 'white', - fontSize: 17, - fontWeight: '500', - }, - link: { - color: colors.purple, - fontWeight: 'bold', - }, -}); diff --git a/example/app/components/LoginScreen.tsx b/example/app/components/LoginScreen.tsx deleted file mode 100644 index dd780e84d1..0000000000 --- a/example/app/components/LoginScreen.tsx +++ /dev/null @@ -1,130 +0,0 @@ -import React, {useEffect, useState} from 'react'; -import {View, Text, StyleSheet, TextInput, Pressable} from 'react-native'; -import colors from '../styles/colors'; -import {shadows} from '../styles/shadows'; -import {buttonStyles} from '../styles/button'; -import {AuthOperationName, useAuth, useEmailPasswordAuth} from '@realm/react'; - -export const LoginScreen = () => { - const {result, logInWithEmailPassword} = useAuth(); - const {register} = useEmailPasswordAuth(); - const [email, setEmail] = useState(''); - const [password, setPassword] = useState(''); - - // Automatically log in after registration - useEffect(() => { - if (result.success && result.operation === AuthOperationName.Register) { - logInWithEmailPassword({email, password}); - } - }, [result, logInWithEmailPassword, email, password]); - - return ( - - - - - - - - {result?.error?.operation === - AuthOperationName.LogInWithEmailPassword && ( - - There was an error logging in, please try again{' '} - - )} - {result?.error?.operation === AuthOperationName.Register && ( - - There was an error registering, please try again - - )} - - logInWithEmailPassword({email, password})} - style={[styles.button, result.pending && styles.buttonDisabled]} - disabled={result.pending}> - Login - - - register({email, password})} - style={[ - styles.button, - result.pending && styles.buttonDisabled, - styles.registerButton, - ]} - disabled={result.pending}> - Register - - - - ); -}; - -const styles = StyleSheet.create({ - content: { - flex: 1, - alignItems: 'center', - justifyContent: 'center', - backgroundColor: colors.darkBlue, - }, - - inputContainer: { - padding: 10, - alignSelf: 'stretch', - marginHorizontal: 10, - }, - - error: { - textAlign: 'center', - marginTop: 10, - marginBottom: 10, - fontSize: 14, - color: colors.white, - }, - - input: { - borderWidth: 1, - borderColor: colors.gray, - padding: 10, - height: 50, - marginVertical: 8, - backgroundColor: colors.white, - borderRadius: 5, - ...shadows, - }, - - buttons: { - marginTop: 16, - flexDirection: 'row', - }, - - button: { - ...buttonStyles.button, - ...shadows, - }, - - buttonDisabled: { - opacity: 0.5, - }, - - registerButton: { - backgroundColor: colors.purpleDark, - }, -}); diff --git a/example/app/components/OfflineModeButton.tsx b/example/app/components/OfflineModeButton.tsx deleted file mode 100644 index 4795490e20..0000000000 --- a/example/app/components/OfflineModeButton.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import React, {useState} from 'react'; -import {StyleSheet, Switch, Text, View} from 'react-native'; -import {useRealm} from '@realm/react'; - -export function OfflineModeButton() { - const realm = useRealm(); - - const [pauseSync, togglePauseSync] = useState(false); - - return ( - - Disable Sync - { - if (!pauseSync && realm.syncSession?.state === 'active') { - realm.syncSession.pause(); - togglePauseSync(true); - } else if (pauseSync && realm.syncSession?.state === 'inactive') { - realm.syncSession.resume(); - togglePauseSync(false); - } - }} - value={realm.syncSession?.state === 'inactive'} - /> - - ); -} - -const styles = StyleSheet.create({ - icon: {padding: 12}, - toggleRow: { - flexDirection: 'row', - alignItems: 'center', - padding: 12, - }, - toggleText: { - flex: 1, - fontSize: 16, - color: '#fff', - fontWeight: 'bold', - }, -}); diff --git a/example/app/components/TaskItem.tsx b/example/app/components/TaskItem.tsx deleted file mode 100644 index 95aae8ec1d..0000000000 --- a/example/app/components/TaskItem.tsx +++ /dev/null @@ -1,81 +0,0 @@ -import React from 'react'; -import Realm from 'realm'; -import {View, Text, Pressable, StyleSheet} from 'react-native'; - -import {shadows} from '../styles/shadows'; -import colors from '../styles/colors'; -import {Task} from '../models/Task'; - -type TaskItemProps = { - task: Task & Realm.Object; - onToggleStatus: () => void; - onDelete: () => void; -}; - -export const TaskItem = React.memo( - ({task, onToggleStatus, onDelete}) => { - return ( - - - {task.isComplete ? '✓' : '○'} - - - - {task.description} - - - - Delete - - - ); - }, -); - -const styles = StyleSheet.create({ - task: { - height: 50, - alignSelf: 'stretch', - flexDirection: 'row', - marginVertical: 8, - backgroundColor: colors.white, - borderRadius: 5, - ...shadows, - }, - descriptionContainer: { - flex: 1, - justifyContent: 'center', - }, - description: { - paddingHorizontal: 10, - color: colors.black, - fontSize: 17, - }, - status: { - width: 50, - height: '100%', - justifyContent: 'center', - borderTopLeftRadius: 5, - borderBottomLeftRadius: 5, - backgroundColor: colors.gray, - }, - completed: { - backgroundColor: colors.purple, - }, - deleteButton: { - justifyContent: 'center', - }, - deleteText: { - marginHorizontal: 10, - color: colors.gray, - fontSize: 17, - }, - icon: { - color: colors.white, - textAlign: 'center', - fontSize: 17, - fontWeight: 'bold', - }, -}); diff --git a/example/app/components/TaskList.tsx b/example/app/components/TaskList.tsx deleted file mode 100644 index 054fdf2f4d..0000000000 --- a/example/app/components/TaskList.tsx +++ /dev/null @@ -1,44 +0,0 @@ -import React from 'react'; -import {View, FlatList, StyleSheet} from 'react-native'; -import {Realm} from '@realm/react'; - -import {Task} from '../models/Task'; -import {TaskItem} from './TaskItem'; - -type TaskListProps = { - tasks: Realm.Results; - onToggleTaskStatus: (task: Task & Realm.Object) => void; - onDeleteTask: (task: Task & Realm.Object) => void; -}; - -export const TaskList: React.FC = ({ - tasks, - onToggleTaskStatus, - onDeleteTask, -}) => { - return ( - - task._id.toString()} - renderItem={({item}) => ( - onToggleTaskStatus(item)} - onDelete={() => onDeleteTask(item)} - // Don't spread the Realm item as such: {...item} - /> - )} - /> - - ); -}; - -const styles = StyleSheet.create({ - listContainer: { - flex: 1, - justifyContent: 'center', - }, -}); - -export default TaskList; diff --git a/example/app/components/TaskManager.tsx b/example/app/components/TaskManager.tsx deleted file mode 100644 index 22d95955db..0000000000 --- a/example/app/components/TaskManager.tsx +++ /dev/null @@ -1,121 +0,0 @@ -import React, {useCallback} from 'react'; -import {View, StyleSheet, Switch, Text} from 'react-native'; - -import {Task} from '../models/Task'; -import {IntroText} from './IntroText'; -import {AddTaskForm} from './AddTaskForm'; -import TaskList from './TaskList'; - -import {useRealm} from '@realm/react'; -import {shadows} from '../styles/shadows'; - -export const TaskManager: React.FC<{ - tasks: Realm.Results; - userId?: string; - setShowDone: (showDone: boolean) => void; - showDone: boolean; -}> = ({tasks, userId, setShowDone, showDone}) => { - const realm = useRealm(); - - const handleAddTask = useCallback( - (description: string): void => { - if (!description) { - return; - } - - // Everything in the function passed to "realm.write" is a transaction and will - // hence succeed or fail together. A transcation is the smallest unit of transfer - // in Realm so we want to be mindful of how much we put into one single transaction - // and split them up if appropriate (more commonly seen server side). Since clients - // may occasionally be online during short time spans we want to increase the probability - // of sync participants to successfully sync everything in the transaction, otherwise - // no changes propagate and the transaction needs to start over when connectivity allows. - realm.write(() => { - return realm.create(Task, { - description, - userId: userId ?? 'SYNC_DISABLED', - }); - }); - }, - [realm, userId], - ); - - const handleToggleTaskStatus = useCallback( - (task: Task & Realm.Object): void => { - realm.write(() => { - // Normally when updating a record in a NoSQL or SQL database, we have to type - // a statement that will later be interpreted and used as instructions for how - // to update the record. But in RealmDB, the objects are "live" because they are - // actually referencing the object's location in memory on the device (memory mapping). - // So rather than typing a statement, we modify the object directly by changing - // the property values. If the changes adhere to the schema, Realm will accept - // this new version of the object and wherever this object is being referenced - // locally will also see the changes "live". - task.isComplete = !task.isComplete; - }); - - // Alternatively if passing the ID as the argument to handleToggleTaskStatus: - // realm?.write(() => { - // const task = realm?.objectForPrimaryKey('Task', id); // If the ID is passed as an ObjectId - // const task = realm?.objectForPrimaryKey('Task', Realm.BSON.ObjectId(id)); // If the ID is passed as a string - // task.isComplete = !task.isComplete; - // }); - }, - [realm], - ); - - const handleDeleteTask = useCallback( - (task: Task & Realm.Object): void => { - realm.write(() => { - realm.delete(task); - - // Alternatively if passing the ID as the argument to handleDeleteTask: - // realm?.delete(realm?.objectForPrimaryKey('Task', id)); - }); - }, - [realm], - ); - - return ( - <> - - - {tasks.length === 0 ? ( - - ) : ( - - )} - - - Show Completed? - setShowDone(!showDone)} /> - - - ); -}; - -const styles = StyleSheet.create({ - content: { - flex: 1, - paddingTop: 20, - paddingHorizontal: 20, - }, - switchPanel: { - flexDirection: 'row', - backgroundColor: '#fff', - padding: 10, - borderRadius: 5, - marginHorizontal: 10, - marginBottom: 10, - ...shadows, - }, - switchPanelText: { - flex: 1, - fontSize: 16, - padding: 5, - }, -}); diff --git a/example/app/models/Task.ts b/example/app/models/Task.ts deleted file mode 100644 index 054201bac6..0000000000 --- a/example/app/models/Task.ts +++ /dev/null @@ -1,22 +0,0 @@ -// This TS version of the Task model shows how to create Realm objects using -// TypeScript syntax, using `@realm/babel-plugin` -// (https://github.com/realm/realm-js/blob/main/packages/babel-plugin/). -// -// If you are not using TypeScript and `@realm/babel-plugin`, you instead need -// to defining a schema on the class - see `Task.js` in the Realm example app -// for an example of this. - -import Realm, {BSON} from 'realm'; - -// To use a class as a Realm object type in Typescript with the `@realm/babel-plugin` plugin, -// simply define the properties on the class with the correct type and the plugin will convert -// it to a Realm schema automatically. -export class Task extends Realm.Object { - _id: BSON.ObjectId = new BSON.ObjectId(); - description!: string; - isComplete: boolean = false; - createdAt: Date = new Date(); - userId!: string; - - static primaryKey = '_id'; -} diff --git a/example/app/models/index.ts b/example/app/models/index.ts deleted file mode 100644 index d8e88c0efe..0000000000 --- a/example/app/models/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -import {Task} from './Task'; - -export const schemas = [Task]; diff --git a/example/app/styles/button.ts b/example/app/styles/button.ts deleted file mode 100644 index 28a096664d..0000000000 --- a/example/app/styles/button.ts +++ /dev/null @@ -1,20 +0,0 @@ -import {StyleSheet} from 'react-native'; -import colors from './colors'; - -export const buttonStyles: StyleSheet.NamedStyles = { - button: { - paddingVertical: 10, - paddingHorizontal: 20, - justifyContent: 'center', - alignItems: 'center', - marginHorizontal: 10, - borderRadius: 5, - backgroundColor: colors.purple, - }, - text: { - color: colors.white, - textAlign: 'center', - fontSize: 17, - fontWeight: 'bold', - }, -}; diff --git a/example/app/styles/colors.ts b/example/app/styles/colors.ts deleted file mode 100644 index 5956c5d54c..0000000000 --- a/example/app/styles/colors.ts +++ /dev/null @@ -1,10 +0,0 @@ -const colors = { - darkBlue: '#2A3642', - purple: '#6E60F9', - purpleDark: '#4238a6', - gray: '#B5B5B5', - white: '#FFFFFF', - black: '#000000', -}; - -export default colors; diff --git a/example/app/styles/shadows.ts b/example/app/styles/shadows.ts deleted file mode 100644 index 105c24848c..0000000000 --- a/example/app/styles/shadows.ts +++ /dev/null @@ -1,17 +0,0 @@ -import {Platform} from 'react-native'; -import colors from './colors'; - -export const shadows = Platform.select({ - ios: { - shadowColor: colors.black, - shadowOffset: { - width: 0, - height: 4, - }, - shadowOpacity: 0.7, - shadowRadius: 3, - }, - android: { - elevation: 3, - }, -}); diff --git a/example/babel.config.js b/example/babel.config.js deleted file mode 100644 index 4723d5e693..0000000000 --- a/example/babel.config.js +++ /dev/null @@ -1,7 +0,0 @@ -module.exports = { - presets: ['module:metro-react-native-babel-preset'], - plugins: [ - '@realm/babel-plugin', - ['@babel/plugin-proposal-decorators', {legacy: true}], - ], -}; diff --git a/example/index.js b/example/index.js deleted file mode 100644 index 4872b460a6..0000000000 --- a/example/index.js +++ /dev/null @@ -1,19 +0,0 @@ -/** - * @format - */ -import 'react-native-get-random-values'; -import React from 'react'; -import {AppRegistry} from 'react-native'; -import {AppWrapperNonSync} from './app/AppWrapperNonSync'; -import {AppWrapperSync} from './app/AppWrapperSync'; -import {name as appName} from './app.json'; -import {SYNC_CONFIG} from './sync.config'; - -const App = () => - SYNC_CONFIG.enabled ? ( - - ) : ( - - ); - -AppRegistry.registerComponent(appName, () => App); diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock deleted file mode 100644 index e6a209b1ce..0000000000 --- a/example/ios/Podfile.lock +++ /dev/null @@ -1,635 +0,0 @@ -PODS: - - boost (1.76.0) - - CocoaAsyncSocket (7.6.5) - - DoubleConversion (1.1.6) - - FBLazyVector (0.71.7) - - FBReactNativeSpec (0.71.7): - - RCT-Folly (= 2021.07.22.00) - - RCTRequired (= 0.71.7) - - RCTTypeSafety (= 0.71.7) - - React-Core (= 0.71.7) - - React-jsi (= 0.71.7) - - ReactCommon/turbomodule/core (= 0.71.7) - - Flipper (0.125.0): - - Flipper-Folly (~> 2.6) - - Flipper-RSocket (~> 1.4) - - Flipper-Boost-iOSX (1.76.0.1.11) - - Flipper-DoubleConversion (3.2.0.1) - - Flipper-Fmt (7.1.7) - - Flipper-Folly (2.6.10): - - Flipper-Boost-iOSX - - Flipper-DoubleConversion - - Flipper-Fmt (= 7.1.7) - - Flipper-Glog - - libevent (~> 2.1.12) - - OpenSSL-Universal (= 1.1.1100) - - Flipper-Glog (0.5.0.5) - - Flipper-PeerTalk (0.0.4) - - Flipper-RSocket (1.4.3): - - Flipper-Folly (~> 2.6) - - FlipperKit (0.125.0): - - FlipperKit/Core (= 0.125.0) - - FlipperKit/Core (0.125.0): - - Flipper (~> 0.125.0) - - FlipperKit/CppBridge - - FlipperKit/FBCxxFollyDynamicConvert - - FlipperKit/FBDefines - - FlipperKit/FKPortForwarding - - SocketRocket (~> 0.6.0) - - FlipperKit/CppBridge (0.125.0): - - Flipper (~> 0.125.0) - - FlipperKit/FBCxxFollyDynamicConvert (0.125.0): - - Flipper-Folly (~> 2.6) - - FlipperKit/FBDefines (0.125.0) - - FlipperKit/FKPortForwarding (0.125.0): - - CocoaAsyncSocket (~> 7.6) - - Flipper-PeerTalk (~> 0.0.4) - - FlipperKit/FlipperKitHighlightOverlay (0.125.0) - - FlipperKit/FlipperKitLayoutHelpers (0.125.0): - - FlipperKit/Core - - FlipperKit/FlipperKitHighlightOverlay - - FlipperKit/FlipperKitLayoutTextSearchable - - FlipperKit/FlipperKitLayoutIOSDescriptors (0.125.0): - - FlipperKit/Core - - FlipperKit/FlipperKitHighlightOverlay - - FlipperKit/FlipperKitLayoutHelpers - - YogaKit (~> 1.18) - - FlipperKit/FlipperKitLayoutPlugin (0.125.0): - - FlipperKit/Core - - FlipperKit/FlipperKitHighlightOverlay - - FlipperKit/FlipperKitLayoutHelpers - - FlipperKit/FlipperKitLayoutIOSDescriptors - - FlipperKit/FlipperKitLayoutTextSearchable - - YogaKit (~> 1.18) - - FlipperKit/FlipperKitLayoutTextSearchable (0.125.0) - - FlipperKit/FlipperKitNetworkPlugin (0.125.0): - - FlipperKit/Core - - FlipperKit/FlipperKitReactPlugin (0.125.0): - - FlipperKit/Core - - FlipperKit/FlipperKitUserDefaultsPlugin (0.125.0): - - FlipperKit/Core - - FlipperKit/SKIOSNetworkPlugin (0.125.0): - - FlipperKit/Core - - FlipperKit/FlipperKitNetworkPlugin - - fmt (6.2.1) - - glog (0.3.5) - - hermes-engine (0.71.7): - - hermes-engine/Pre-built (= 0.71.7) - - hermes-engine/Pre-built (0.71.7) - - libevent (2.1.12) - - OpenSSL-Universal (1.1.1100) - - RCT-Folly (2021.07.22.00): - - boost - - DoubleConversion - - fmt (~> 6.2.1) - - glog - - RCT-Folly/Default (= 2021.07.22.00) - - RCT-Folly/Default (2021.07.22.00): - - boost - - DoubleConversion - - fmt (~> 6.2.1) - - glog - - RCT-Folly/Futures (2021.07.22.00): - - boost - - DoubleConversion - - fmt (~> 6.2.1) - - glog - - libevent - - RCTRequired (0.71.7) - - RCTTypeSafety (0.71.7): - - FBLazyVector (= 0.71.7) - - RCTRequired (= 0.71.7) - - React-Core (= 0.71.7) - - React (0.71.7): - - React-Core (= 0.71.7) - - React-Core/DevSupport (= 0.71.7) - - React-Core/RCTWebSocket (= 0.71.7) - - React-RCTActionSheet (= 0.71.7) - - React-RCTAnimation (= 0.71.7) - - React-RCTBlob (= 0.71.7) - - React-RCTImage (= 0.71.7) - - React-RCTLinking (= 0.71.7) - - React-RCTNetwork (= 0.71.7) - - React-RCTSettings (= 0.71.7) - - React-RCTText (= 0.71.7) - - React-RCTVibration (= 0.71.7) - - React-callinvoker (0.71.7) - - React-Codegen (0.71.7): - - FBReactNativeSpec - - hermes-engine - - RCT-Folly - - RCTRequired - - RCTTypeSafety - - React-Core - - React-jsi - - React-jsiexecutor - - ReactCommon/turbomodule/bridging - - ReactCommon/turbomodule/core - - React-Core (0.71.7): - - glog - - hermes-engine - - RCT-Folly (= 2021.07.22.00) - - React-Core/Default (= 0.71.7) - - React-cxxreact (= 0.71.7) - - React-hermes - - React-jsi (= 0.71.7) - - React-jsiexecutor (= 0.71.7) - - React-perflogger (= 0.71.7) - - Yoga - - React-Core/CoreModulesHeaders (0.71.7): - - glog - - hermes-engine - - RCT-Folly (= 2021.07.22.00) - - React-Core/Default - - React-cxxreact (= 0.71.7) - - React-hermes - - React-jsi (= 0.71.7) - - React-jsiexecutor (= 0.71.7) - - React-perflogger (= 0.71.7) - - Yoga - - React-Core/Default (0.71.7): - - glog - - hermes-engine - - RCT-Folly (= 2021.07.22.00) - - React-cxxreact (= 0.71.7) - - React-hermes - - React-jsi (= 0.71.7) - - React-jsiexecutor (= 0.71.7) - - React-perflogger (= 0.71.7) - - Yoga - - React-Core/DevSupport (0.71.7): - - glog - - hermes-engine - - RCT-Folly (= 2021.07.22.00) - - React-Core/Default (= 0.71.7) - - React-Core/RCTWebSocket (= 0.71.7) - - React-cxxreact (= 0.71.7) - - React-hermes - - React-jsi (= 0.71.7) - - React-jsiexecutor (= 0.71.7) - - React-jsinspector (= 0.71.7) - - React-perflogger (= 0.71.7) - - Yoga - - React-Core/RCTActionSheetHeaders (0.71.7): - - glog - - hermes-engine - - RCT-Folly (= 2021.07.22.00) - - React-Core/Default - - React-cxxreact (= 0.71.7) - - React-hermes - - React-jsi (= 0.71.7) - - React-jsiexecutor (= 0.71.7) - - React-perflogger (= 0.71.7) - - Yoga - - React-Core/RCTAnimationHeaders (0.71.7): - - glog - - hermes-engine - - RCT-Folly (= 2021.07.22.00) - - React-Core/Default - - React-cxxreact (= 0.71.7) - - React-hermes - - React-jsi (= 0.71.7) - - React-jsiexecutor (= 0.71.7) - - React-perflogger (= 0.71.7) - - Yoga - - React-Core/RCTBlobHeaders (0.71.7): - - glog - - hermes-engine - - RCT-Folly (= 2021.07.22.00) - - React-Core/Default - - React-cxxreact (= 0.71.7) - - React-hermes - - React-jsi (= 0.71.7) - - React-jsiexecutor (= 0.71.7) - - React-perflogger (= 0.71.7) - - Yoga - - React-Core/RCTImageHeaders (0.71.7): - - glog - - hermes-engine - - RCT-Folly (= 2021.07.22.00) - - React-Core/Default - - React-cxxreact (= 0.71.7) - - React-hermes - - React-jsi (= 0.71.7) - - React-jsiexecutor (= 0.71.7) - - React-perflogger (= 0.71.7) - - Yoga - - React-Core/RCTLinkingHeaders (0.71.7): - - glog - - hermes-engine - - RCT-Folly (= 2021.07.22.00) - - React-Core/Default - - React-cxxreact (= 0.71.7) - - React-hermes - - React-jsi (= 0.71.7) - - React-jsiexecutor (= 0.71.7) - - React-perflogger (= 0.71.7) - - Yoga - - React-Core/RCTNetworkHeaders (0.71.7): - - glog - - hermes-engine - - RCT-Folly (= 2021.07.22.00) - - React-Core/Default - - React-cxxreact (= 0.71.7) - - React-hermes - - React-jsi (= 0.71.7) - - React-jsiexecutor (= 0.71.7) - - React-perflogger (= 0.71.7) - - Yoga - - React-Core/RCTSettingsHeaders (0.71.7): - - glog - - hermes-engine - - RCT-Folly (= 2021.07.22.00) - - React-Core/Default - - React-cxxreact (= 0.71.7) - - React-hermes - - React-jsi (= 0.71.7) - - React-jsiexecutor (= 0.71.7) - - React-perflogger (= 0.71.7) - - Yoga - - React-Core/RCTTextHeaders (0.71.7): - - glog - - hermes-engine - - RCT-Folly (= 2021.07.22.00) - - React-Core/Default - - React-cxxreact (= 0.71.7) - - React-hermes - - React-jsi (= 0.71.7) - - React-jsiexecutor (= 0.71.7) - - React-perflogger (= 0.71.7) - - Yoga - - React-Core/RCTVibrationHeaders (0.71.7): - - glog - - hermes-engine - - RCT-Folly (= 2021.07.22.00) - - React-Core/Default - - React-cxxreact (= 0.71.7) - - React-hermes - - React-jsi (= 0.71.7) - - React-jsiexecutor (= 0.71.7) - - React-perflogger (= 0.71.7) - - Yoga - - React-Core/RCTWebSocket (0.71.7): - - glog - - hermes-engine - - RCT-Folly (= 2021.07.22.00) - - React-Core/Default (= 0.71.7) - - React-cxxreact (= 0.71.7) - - React-hermes - - React-jsi (= 0.71.7) - - React-jsiexecutor (= 0.71.7) - - React-perflogger (= 0.71.7) - - Yoga - - React-CoreModules (0.71.7): - - RCT-Folly (= 2021.07.22.00) - - RCTTypeSafety (= 0.71.7) - - React-Codegen (= 0.71.7) - - React-Core/CoreModulesHeaders (= 0.71.7) - - React-jsi (= 0.71.7) - - React-RCTBlob - - React-RCTImage (= 0.71.7) - - ReactCommon/turbomodule/core (= 0.71.7) - - React-cxxreact (0.71.7): - - boost (= 1.76.0) - - DoubleConversion - - glog - - hermes-engine - - RCT-Folly (= 2021.07.22.00) - - React-callinvoker (= 0.71.7) - - React-jsi (= 0.71.7) - - React-jsinspector (= 0.71.7) - - React-logger (= 0.71.7) - - React-perflogger (= 0.71.7) - - React-runtimeexecutor (= 0.71.7) - - React-hermes (0.71.7): - - DoubleConversion - - glog - - hermes-engine - - RCT-Folly (= 2021.07.22.00) - - RCT-Folly/Futures (= 2021.07.22.00) - - React-cxxreact (= 0.71.7) - - React-jsi - - React-jsiexecutor (= 0.71.7) - - React-jsinspector (= 0.71.7) - - React-perflogger (= 0.71.7) - - React-jsi (0.71.7): - - boost (= 1.76.0) - - DoubleConversion - - glog - - hermes-engine - - RCT-Folly (= 2021.07.22.00) - - React-jsiexecutor (0.71.7): - - DoubleConversion - - glog - - hermes-engine - - RCT-Folly (= 2021.07.22.00) - - React-cxxreact (= 0.71.7) - - React-jsi (= 0.71.7) - - React-perflogger (= 0.71.7) - - React-jsinspector (0.71.7) - - React-logger (0.71.7): - - glog - - react-native-get-random-values (1.9.0): - - React-Core - - React-perflogger (0.71.7) - - React-RCTActionSheet (0.71.7): - - React-Core/RCTActionSheetHeaders (= 0.71.7) - - React-RCTAnimation (0.71.7): - - RCT-Folly (= 2021.07.22.00) - - RCTTypeSafety (= 0.71.7) - - React-Codegen (= 0.71.7) - - React-Core/RCTAnimationHeaders (= 0.71.7) - - React-jsi (= 0.71.7) - - ReactCommon/turbomodule/core (= 0.71.7) - - React-RCTAppDelegate (0.71.7): - - RCT-Folly - - RCTRequired - - RCTTypeSafety - - React-Core - - ReactCommon/turbomodule/core - - React-RCTBlob (0.71.7): - - hermes-engine - - RCT-Folly (= 2021.07.22.00) - - React-Codegen (= 0.71.7) - - React-Core/RCTBlobHeaders (= 0.71.7) - - React-Core/RCTWebSocket (= 0.71.7) - - React-jsi (= 0.71.7) - - React-RCTNetwork (= 0.71.7) - - ReactCommon/turbomodule/core (= 0.71.7) - - React-RCTImage (0.71.7): - - RCT-Folly (= 2021.07.22.00) - - RCTTypeSafety (= 0.71.7) - - React-Codegen (= 0.71.7) - - React-Core/RCTImageHeaders (= 0.71.7) - - React-jsi (= 0.71.7) - - React-RCTNetwork (= 0.71.7) - - ReactCommon/turbomodule/core (= 0.71.7) - - React-RCTLinking (0.71.7): - - React-Codegen (= 0.71.7) - - React-Core/RCTLinkingHeaders (= 0.71.7) - - React-jsi (= 0.71.7) - - ReactCommon/turbomodule/core (= 0.71.7) - - React-RCTNetwork (0.71.7): - - RCT-Folly (= 2021.07.22.00) - - RCTTypeSafety (= 0.71.7) - - React-Codegen (= 0.71.7) - - React-Core/RCTNetworkHeaders (= 0.71.7) - - React-jsi (= 0.71.7) - - ReactCommon/turbomodule/core (= 0.71.7) - - React-RCTSettings (0.71.7): - - RCT-Folly (= 2021.07.22.00) - - RCTTypeSafety (= 0.71.7) - - React-Codegen (= 0.71.7) - - React-Core/RCTSettingsHeaders (= 0.71.7) - - React-jsi (= 0.71.7) - - ReactCommon/turbomodule/core (= 0.71.7) - - React-RCTText (0.71.7): - - React-Core/RCTTextHeaders (= 0.71.7) - - React-RCTVibration (0.71.7): - - RCT-Folly (= 2021.07.22.00) - - React-Codegen (= 0.71.7) - - React-Core/RCTVibrationHeaders (= 0.71.7) - - React-jsi (= 0.71.7) - - ReactCommon/turbomodule/core (= 0.71.7) - - React-runtimeexecutor (0.71.7): - - React-jsi (= 0.71.7) - - ReactCommon/turbomodule/bridging (0.71.7): - - DoubleConversion - - glog - - hermes-engine - - RCT-Folly (= 2021.07.22.00) - - React-callinvoker (= 0.71.7) - - React-Core (= 0.71.7) - - React-cxxreact (= 0.71.7) - - React-jsi (= 0.71.7) - - React-logger (= 0.71.7) - - React-perflogger (= 0.71.7) - - ReactCommon/turbomodule/core (0.71.7): - - DoubleConversion - - glog - - hermes-engine - - RCT-Folly (= 2021.07.22.00) - - React-callinvoker (= 0.71.7) - - React-Core (= 0.71.7) - - React-cxxreact (= 0.71.7) - - React-jsi (= 0.71.7) - - React-logger (= 0.71.7) - - React-perflogger (= 0.71.7) - - RealmJS (12.0.0): - - React - - SocketRocket (0.6.0) - - Yoga (1.14.0) - - YogaKit (1.18.1): - - Yoga (~> 1.14) - -DEPENDENCIES: - - boost (from `../../node_modules/react-native/third-party-podspecs/boost.podspec`) - - DoubleConversion (from `../../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec`) - - FBLazyVector (from `../../node_modules/react-native/Libraries/FBLazyVector`) - - FBReactNativeSpec (from `../../node_modules/react-native/React/FBReactNativeSpec`) - - Flipper (= 0.125.0) - - Flipper-Boost-iOSX (= 1.76.0.1.11) - - Flipper-DoubleConversion (= 3.2.0.1) - - Flipper-Fmt (= 7.1.7) - - Flipper-Folly (= 2.6.10) - - Flipper-Glog (= 0.5.0.5) - - Flipper-PeerTalk (= 0.0.4) - - Flipper-RSocket (= 1.4.3) - - FlipperKit (= 0.125.0) - - FlipperKit/Core (= 0.125.0) - - FlipperKit/CppBridge (= 0.125.0) - - FlipperKit/FBCxxFollyDynamicConvert (= 0.125.0) - - FlipperKit/FBDefines (= 0.125.0) - - FlipperKit/FKPortForwarding (= 0.125.0) - - FlipperKit/FlipperKitHighlightOverlay (= 0.125.0) - - FlipperKit/FlipperKitLayoutPlugin (= 0.125.0) - - FlipperKit/FlipperKitLayoutTextSearchable (= 0.125.0) - - FlipperKit/FlipperKitNetworkPlugin (= 0.125.0) - - FlipperKit/FlipperKitReactPlugin (= 0.125.0) - - FlipperKit/FlipperKitUserDefaultsPlugin (= 0.125.0) - - FlipperKit/SKIOSNetworkPlugin (= 0.125.0) - - glog (from `../../node_modules/react-native/third-party-podspecs/glog.podspec`) - - hermes-engine (from `../../node_modules/react-native/sdks/hermes-engine/hermes-engine.podspec`) - - libevent (~> 2.1.12) - - OpenSSL-Universal (= 1.1.1100) - - RCT-Folly (from `../../node_modules/react-native/third-party-podspecs/RCT-Folly.podspec`) - - RCTRequired (from `../../node_modules/react-native/Libraries/RCTRequired`) - - RCTTypeSafety (from `../../node_modules/react-native/Libraries/TypeSafety`) - - React (from `../../node_modules/react-native/`) - - React-callinvoker (from `../../node_modules/react-native/ReactCommon/callinvoker`) - - React-Codegen (from `build/generated/ios`) - - React-Core (from `../../node_modules/react-native/`) - - React-Core/DevSupport (from `../../node_modules/react-native/`) - - React-Core/RCTWebSocket (from `../../node_modules/react-native/`) - - React-CoreModules (from `../../node_modules/react-native/React/CoreModules`) - - React-cxxreact (from `../../node_modules/react-native/ReactCommon/cxxreact`) - - React-hermes (from `../../node_modules/react-native/ReactCommon/hermes`) - - React-jsi (from `../../node_modules/react-native/ReactCommon/jsi`) - - React-jsiexecutor (from `../../node_modules/react-native/ReactCommon/jsiexecutor`) - - React-jsinspector (from `../../node_modules/react-native/ReactCommon/jsinspector`) - - React-logger (from `../../node_modules/react-native/ReactCommon/logger`) - - react-native-get-random-values (from `../node_modules/react-native-get-random-values`) - - React-perflogger (from `../../node_modules/react-native/ReactCommon/reactperflogger`) - - React-RCTActionSheet (from `../../node_modules/react-native/Libraries/ActionSheetIOS`) - - React-RCTAnimation (from `../../node_modules/react-native/Libraries/NativeAnimation`) - - React-RCTAppDelegate (from `../../node_modules/react-native/Libraries/AppDelegate`) - - React-RCTBlob (from `../../node_modules/react-native/Libraries/Blob`) - - React-RCTImage (from `../../node_modules/react-native/Libraries/Image`) - - React-RCTLinking (from `../../node_modules/react-native/Libraries/LinkingIOS`) - - React-RCTNetwork (from `../../node_modules/react-native/Libraries/Network`) - - React-RCTSettings (from `../../node_modules/react-native/Libraries/Settings`) - - React-RCTText (from `../../node_modules/react-native/Libraries/Text`) - - React-RCTVibration (from `../../node_modules/react-native/Libraries/Vibration`) - - React-runtimeexecutor (from `../../node_modules/react-native/ReactCommon/runtimeexecutor`) - - ReactCommon/turbomodule/core (from `../../node_modules/react-native/ReactCommon`) - - RealmJS (from `../../node_modules/realm`) - - Yoga (from `../../node_modules/react-native/ReactCommon/yoga`) - -SPEC REPOS: - trunk: - - CocoaAsyncSocket - - Flipper - - Flipper-Boost-iOSX - - Flipper-DoubleConversion - - Flipper-Fmt - - Flipper-Folly - - Flipper-Glog - - Flipper-PeerTalk - - Flipper-RSocket - - FlipperKit - - fmt - - libevent - - OpenSSL-Universal - - SocketRocket - - YogaKit - -EXTERNAL SOURCES: - boost: - :podspec: "../../node_modules/react-native/third-party-podspecs/boost.podspec" - DoubleConversion: - :podspec: "../../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec" - FBLazyVector: - :path: "../../node_modules/react-native/Libraries/FBLazyVector" - FBReactNativeSpec: - :path: "../../node_modules/react-native/React/FBReactNativeSpec" - glog: - :podspec: "../../node_modules/react-native/third-party-podspecs/glog.podspec" - hermes-engine: - :podspec: "../../node_modules/react-native/sdks/hermes-engine/hermes-engine.podspec" - RCT-Folly: - :podspec: "../../node_modules/react-native/third-party-podspecs/RCT-Folly.podspec" - RCTRequired: - :path: "../../node_modules/react-native/Libraries/RCTRequired" - RCTTypeSafety: - :path: "../../node_modules/react-native/Libraries/TypeSafety" - React: - :path: "../../node_modules/react-native/" - React-callinvoker: - :path: "../../node_modules/react-native/ReactCommon/callinvoker" - React-Codegen: - :path: build/generated/ios - React-Core: - :path: "../../node_modules/react-native/" - React-CoreModules: - :path: "../../node_modules/react-native/React/CoreModules" - React-cxxreact: - :path: "../../node_modules/react-native/ReactCommon/cxxreact" - React-hermes: - :path: "../../node_modules/react-native/ReactCommon/hermes" - React-jsi: - :path: "../../node_modules/react-native/ReactCommon/jsi" - React-jsiexecutor: - :path: "../../node_modules/react-native/ReactCommon/jsiexecutor" - React-jsinspector: - :path: "../../node_modules/react-native/ReactCommon/jsinspector" - React-logger: - :path: "../../node_modules/react-native/ReactCommon/logger" - react-native-get-random-values: - :path: "../node_modules/react-native-get-random-values" - React-perflogger: - :path: "../../node_modules/react-native/ReactCommon/reactperflogger" - React-RCTActionSheet: - :path: "../../node_modules/react-native/Libraries/ActionSheetIOS" - React-RCTAnimation: - :path: "../../node_modules/react-native/Libraries/NativeAnimation" - React-RCTAppDelegate: - :path: "../../node_modules/react-native/Libraries/AppDelegate" - React-RCTBlob: - :path: "../../node_modules/react-native/Libraries/Blob" - React-RCTImage: - :path: "../../node_modules/react-native/Libraries/Image" - React-RCTLinking: - :path: "../../node_modules/react-native/Libraries/LinkingIOS" - React-RCTNetwork: - :path: "../../node_modules/react-native/Libraries/Network" - React-RCTSettings: - :path: "../../node_modules/react-native/Libraries/Settings" - React-RCTText: - :path: "../../node_modules/react-native/Libraries/Text" - React-RCTVibration: - :path: "../../node_modules/react-native/Libraries/Vibration" - React-runtimeexecutor: - :path: "../../node_modules/react-native/ReactCommon/runtimeexecutor" - ReactCommon: - :path: "../../node_modules/react-native/ReactCommon" - RealmJS: - :path: "../../node_modules/realm" - Yoga: - :path: "../../node_modules/react-native/ReactCommon/yoga" - -SPEC CHECKSUMS: - boost: 57d2868c099736d80fcd648bf211b4431e51a558 - CocoaAsyncSocket: 065fd1e645c7abab64f7a6a2007a48038fdc6a99 - DoubleConversion: 5189b271737e1565bdce30deb4a08d647e3f5f54 - FBLazyVector: a89a0525bc7ca174675045c2b492b5280d5a2470 - FBReactNativeSpec: ca1f6fb923ad03cad73fda95e9a6d1dd8de72ae2 - Flipper: 26fc4b7382499f1281eb8cb921e5c3ad6de91fe0 - Flipper-Boost-iOSX: fd1e2b8cbef7e662a122412d7ac5f5bea715403c - Flipper-DoubleConversion: 2dc99b02f658daf147069aad9dbd29d8feb06d30 - Flipper-Fmt: 60cbdd92fc254826e61d669a5d87ef7015396a9b - Flipper-Folly: 584845625005ff068a6ebf41f857f468decd26b3 - Flipper-Glog: 70c50ce58ddaf67dc35180db05f191692570f446 - Flipper-PeerTalk: 116d8f857dc6ef55c7a5a75ea3ceaafe878aadc9 - Flipper-RSocket: d9d9ade67cbecf6ac10730304bf5607266dd2541 - FlipperKit: cbdee19bdd4e7f05472a66ce290f1b729ba3cb86 - fmt: ff9d55029c625d3757ed641535fd4a75fedc7ce9 - glog: 04b94705f318337d7ead9e6d17c019bd9b1f6b1b - hermes-engine: 4438d2b8bf8bebaba1b1ac0451160bab59e491f8 - libevent: 4049cae6c81cdb3654a443be001fb9bdceff7913 - OpenSSL-Universal: ebc357f1e6bc71fa463ccb2fe676756aff50e88c - RCT-Folly: 424b8c9a7a0b9ab2886ffe9c3b041ef628fd4fb1 - RCTRequired: 5a4a30ac20c86eeadd6844a9328f78d4168cf9b2 - RCTTypeSafety: 279fc5861a89f0f37db3a585f27f971485b4b734 - React: 88307a9be3bd0e71a6822271cf28b84a587fb97f - React-callinvoker: 35fb980c454104ebe82f0afb9826830089248e08 - React-Codegen: a8dbde3b7476d5c19437d2adb9e8ea1b426b9595 - React-Core: 385cb6fa78762c6409ff39faeb0dd9ad664b6e84 - React-CoreModules: c2b7db313b04d9b71954ffd55d0c2e46bc40e9fb - React-cxxreact: 845fefb889132e5d004ff818f7a599e32c52e7d6 - React-hermes: 86135f35e1dd2dfccfb97afe96d0c06f6a3970c4 - React-jsi: 39c116aa6c3d6f3d9874eff6998a670b47882a28 - React-jsiexecutor: eaa5f71eb8f6861cf0e57f1a0f52aeb020d9e18e - React-jsinspector: 9885f6f94d231b95a739ef7bb50536fb87ce7539 - React-logger: 3f8ebad1be1bf3299d1ab6d7f971802d7395c7ef - react-native-get-random-values: dee677497c6a740b71e5612e8dbd83e7539ed5bb - React-perflogger: 2d505bbe298e3b7bacdd9e542b15535be07220f6 - React-RCTActionSheet: 0e96e4560bd733c9b37efbf68f5b1a47615892fb - React-RCTAnimation: fd138e26f120371c87e406745a27535e2c8a04ef - React-RCTAppDelegate: 4a9fd1230a98dc3d4382f8a934dc9f50834d8335 - React-RCTBlob: 38a7185f06a0ce8153a023e63b406a28d67b955d - React-RCTImage: 92b0966e7c1cadda889e961c474397ad5180e194 - React-RCTLinking: b80f8d0c6e94c54294b0048def51f57eaa9a27af - React-RCTNetwork: 491b0c65ac22edbd6695d12d084b4943103b009b - React-RCTSettings: 97af3e8abe0023349ec015910df3bda1a0380117 - React-RCTText: 33c85753bd714d527d2ae538dc56ec24c6783d84 - React-RCTVibration: 08f132cad9896458776f37c112e71d60aef1c6ae - React-runtimeexecutor: c5c89f8f543842dd864b63ded1b0bbb9c9445328 - ReactCommon: dbfbe2f7f3c5ce4ce44f43f2fd0d5950d1eb67c5 - RealmJS: fd89f477b8469188d45243c85bad4e0936d74457 - SocketRocket: fccef3f9c5cedea1353a9ef6ada904fde10d6608 - Yoga: d56980c8914db0b51692f55533409e844b66133c - YogaKit: f782866e155069a2cca2517aafea43200b01fd5a - -PODFILE CHECKSUM: dd5c09cddf3cb19ccec399516256a7b048ea0785 - -COCOAPODS: 1.11.3 diff --git a/example/ios/RealmExample.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/example/ios/RealmExample.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100644 index 18d981003d..0000000000 --- a/example/ios/RealmExample.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - - diff --git a/example/metro.config.js b/example/metro.config.js deleted file mode 100644 index 28679c8a85..0000000000 --- a/example/metro.config.js +++ /dev/null @@ -1,6 +0,0 @@ -const config = require('@realm/metro-config')({projectRoot: __dirname}); - -// Prevent .js versions of files from being loaded in preference to TS -config.resolver.sourceExts = ['json', 'ts', 'tsx', 'js', 'jsx']; - -module.exports = config; diff --git a/example/sync.config.js b/example/sync.config.js deleted file mode 100644 index 2d6258edc8..0000000000 --- a/example/sync.config.js +++ /dev/null @@ -1,6 +0,0 @@ -export const SYNC_CONFIG = { - // Set `enabled` to `true` to enable sync. - enabled: false, - // Add your Realm App ID here if sync is enabled. - appId: '', -}; diff --git a/examples/rn-todo-list/README.md b/examples/rn-todo-list/README.md new file mode 100644 index 0000000000..d10d021f5d --- /dev/null +++ b/examples/rn-todo-list/README.md @@ -0,0 +1,218 @@ +# An Offline-First Todo List App Using Atlas Device SDK for React Native + +A todo list (task manager) app showcasing how to create, read, update, and delete data while offline using [MongoDB's Atlas Device SDK for React Native](https://www.mongodb.com/docs/realm/sdk/react-native/) (fka Realm). + +> **TIP:** This app can be run together with the corresponding [Electron example app](../electron-todo-list/) using the same [App Services App](./backend/). + +## Screenshots + +![Todo List Screenshot](./frontend/app/assets/screenshot-login-and-tasks.png) + +## Project Structure + +The following shows the project structure and the most relevant files. + +> To learn more about the backend file structure, see [App Configuration](https://www.mongodb.com/docs/atlas/app-services/reference/config/). + +``` +├── backend - App Services App +│ └── (see link above) +│ +├── frontend - React Native App +│ ├── app +│ │ ├── components +│ │ │ ├── AddTaskForm.tsx - Creates a task +│ │ │ ├── OfflineModeButton.tsx - Pauses/resumes the sync session +│ │ │ ├── TaskItem.tsx - Updates or deletes a task +│ │ │ └── TaskList.tsx - Displays all tasks +│ │ │ +│ │ ├── hooks +│ │ │ ├── useSyncConnection.ts - Functions for re/disconnecting +│ │ │ └── useTaskManager.ts - Functions for managing (CRUD) tasks +│ │ │ +│ │ ├── models +│ │ │ ├── index.ts - Exports all (1) models +│ │ │ └── Task.ts - Data model +│ │ │ +│ │ ├── screens +│ │ │ ├── LoginScreen.tsx - Login and registration +│ │ │ ├── TaskScreen.tsx - Display task components +│ │ │ └── TaskScreenSync.tsx - Task screen with sync-related ops +│ │ │ +│ │ ├── AppNonSync.tsx - Local-only app and opens Realm +│ │ └── AppSync.tsx - Sync-enabled app and opens Realm +│ │ +│ ├── index.js - Entry point +│ └── package.json - Dependencies +│ +├── README.md - Instructions and info +└── sync.config.js - Option to use Device Sync enabled app +``` + +## Use Cases + +This app focuses on showing how to work with data no matter the network connection. + +It specifically addresses the following points: + +* Registering and logging in to an App Services App using [Email/Password Authentication](https://www.mongodb.com/docs/atlas/app-services/authentication/email-password/). +* Accessing and updating data: + * Create + * Query/Read + * Sort and filter the query + * Update + * Delete +* Using offline/local-first reads and writes. + * Shows configuration for opening a synced Realm. + * Realms are opened immediately without waiting for downloads from the server. + * See [Offline Support](#note-offline-support) below. +* Allowing users to only read and write to their own tasks via [data access rules/permissions](https://www.mongodb.com/docs/atlas/app-services/rules/roles/#define-roles---permissions). + * See [Set Data Access Permissions](#set-data-access-permissions) further below. +* The app demonstrates both how to use *either*: + * A) A local-only app (see [AppNonSync.tsx](./frontend/app/AppNonSync.tsx)). + * B) A [Device Sync](https://www.mongodb.com/atlas/app-services/device-sync) enabled app (see [AppSync.tsx](./frontend/app/AppSync.tsx)). + * Choose which one to use via [sync.config.js](./frontend/sync.config.js). + +### Note: Offline Support + +Users who have logged in at least once will have their credentials cached on the client. Thus, a logged in user who restarts the app will remain logged in. [@realm/react's](https://www.npmjs.com/package/@realm/react) `UserProvider` automatically handles this for you by checking if the `app.currentUser` already exists. + +Data that was previously synced to the device will also exist locally in the Realm database. From this point on, users can be offline and still query and update data. Any changes made offline will be synced automatically to Atlas and any other devices once a network connection is established. If multiple users modify the same data either while online or offline, those conflicts are [automatically resolved](https://www.mongodb.com/docs/atlas/app-services/sync/details/conflict-resolution/) before being synced. + +#### Realm Configuration + +When opening a Realm, we can specify the behavior in the Realm configuration when opening it for the first time (via `newRealmFileBehavior`) and for subsequent ones (via `existingRealmFileBehavior`). We can either: +* `OpenRealmBehaviorType.OpenImmediately` + * Opens the Realm file immediately if it exists, otherwise it first creates a new empty Realm file then opens it. + * This lets users use the app with the existing data, while syncing any changes to the device in the background. +* `OpenRealmBehaviorType.DownloadBeforeOpen` + * If there is data to be downloaded, this waits for the data to be fully synced before opening the Realm. + +This app opens a Realm via `RealmProvider` (see [AppSync.tsx](./frontend/app/AppSync.tsx)) and passes the configuration as props. We use `OpenImmediately` for new and existing Realm files in order to use the app while offline. + +> See [OpenRealmBehaviorConfiguration](https://www.mongodb.com/docs/realm-sdks/js/latest/types/OpenRealmBehaviorConfiguration.html) for possible configurations of new and existing Realm file behaviors. + +## Getting Started + +### Prerequisites + +* [Node.js](https://nodejs.org/) +* [React Native development environment](https://reactnative.dev/docs/environment-setup?guide=native) + * Refer to the **"React Native CLI Quickstart"**. + +### Set up an Atlas Database + +Start by [deploying a free Atlas cluster](https://www.mongodb.com/docs/atlas/getting-started/#get-started-with-atlas) and create an Atlas database. + +### Set up an Atlas App Services App + +You can either choose to set up your App via a CLI (this has fewer steps and is much faster since all configurations are already provided in the [backend directory](./backend/)), or via the App Services UI (steps provided below). + +#### Via a CLI (recommended) + +To import and deploy changes from your local directory to App Services you can use the command line interface: + +1. [Set up Realm CLI](https://www.mongodb.com/docs/atlas/app-services/cli/). +2. In the provided [backend directory](./backend/) (the App Services App), update the following: + * Cluster Name + * Update the `"clusterName"` in [data_sources/mongodb-atlas/config.json](./backend/data_sources/mongodb-atlas/config.json) to the name of your cluster. + * (The default name is `Cluster0`.) + * App ID + * There is no `"app_id"` defined in [realm_config.json](./backend/realm_config.json) since we will create a brand new App. **If** you for some reason are updating an existing app, add an `"app_id"` field and its value. +3. [Push and deploy](https://www.mongodb.com/docs/atlas/app-services/cli/realm-cli-push/#std-label-realm-cli-push) the local directory to App Services: +```sh +realm-cli push --local +``` +4. Once pushed, verify that your App shows up in the App Services UI. +5. 🥳 You can now go ahead and [install dependencies and run the React Native app](#install-dependencies). + +#### Via the App Services UI + +To sync data used in this app you must first: + +1. [Create an App Services App](https://www.mongodb.com/docs/atlas/app-services/manage-apps/create/create-with-ui/). +2. [Enable Email/Password Authentication](https://www.mongodb.com/docs/atlas/app-services/authentication/email-password/). + * For this example app, we automatically confirm users' emails. +3. [Enable Flexible Sync](https://www.mongodb.com/docs/atlas/app-services/sync/configure/enable-sync/) with **Development Mode** enabled. + * When Development Mode is enabled, [queryable fields](https://www.mongodb.com/docs/atlas/app-services/sync/configure/sync-settings/#queryable-fields) will be added **automatically**, and schemas will be inferred based on the client Realm data models. + * For information, queryable fields used in this app include: + * Global (all collections): `_id` + * `Task` collection: `isComplete`, `userId` + * (Development Mode should be turned off in production.) +4. Don't forget to click `Review Draft and Deploy`. + +### Install Dependencies + +From the [frontend directory](./frontend/), run: + +```sh +npm install +``` + +If developing with iOS, also run: + +```sh +npx pod-install +``` + +### Run the App + +1. [Copy your Atlas App ID](https://www.mongodb.com/docs/atlas/app-services/reference/find-your-project-or-app-id/#std-label-find-your-app-id) from the App Services UI. +2. Set `SYNC_CONFIG.enabled` to `true` and paste the copied ID as the value of the existing variable `SYNC_CONFIG.appId` in [sync.config.js](./frontend/sync.config.js): +```js +export const SYNC_CONFIG = { + enabled: true, + appId: 'YOUR_APP_ID', +}; +``` +3. Start Metro (the JavaScript bundler) in its own terminal: +```sh +npm start +``` +4. In another terminal, start the app: +```sh +# Open the app on an iOS simulator. +npm run ios + +# Open the app on an Android emulator. +npm run android +``` + +> To run the app on an actual device, see React Native's [Running on Device](https://reactnative.dev/docs/running-on-device). + +### Set Data Access Permissions + +> If you set up your App Services App [via a CLI](#via-a-cli-recommended), you can **skip this step** as the permissions should already be defined for you. + +After running the client app for the first time, [modify the rules](https://www.mongodb.com/docs/atlas/app-services/rules/roles/#define-roles---permissions) for the collection in the App Services UI. + +* Collection: `Task` + * Permissions: `readOwnWriteOwn` (see [corresponding json](./backend/data_sources/mongodb-atlas/TodoList/Task/rules.json)) + * Explanation: + * A user should be able to read and write to their own document (i.e. when `Task.userId === `), but not anyone else's. + +> To learn more and see examples of permissions depending on a certain use case, see [Device Sync Permissions Guide](https://www.mongodb.com/docs/atlas/app-services/sync/app-builder/device-sync-permissions-guide/#std-label-flexible-sync-permissions-guide) and [Data Access Role Examples](https://www.mongodb.com/docs/atlas/app-services/rules/examples/). + +## Troubleshooting + +A great help when troubleshooting is to look at the [Application Logs](https://www.mongodb.com/docs/atlas/app-services/activity/view-logs/) in the App Services UI. + +### Permissions + +If permission is denied: + * Make sure your IP address is on the [IP Access List](https://www.mongodb.com/docs/atlas/app-services/security/network/#ip-access-list) for your App. + * Make sure you have the correct data access permissions for the collections. + * See [Set Data Access Permissions](#set-data-access-permissions) further above. + +### Removing the Local Realm Database + +Removing the local database can be useful for certain errors. + +On an iOS simulator: +1. Press and hold the app icon on the Home Screen. +2. Choose to remove the app and its data. + +On an Android emulator via Android Studio: +1. Quit the emulator if it is running. +2. Open `Device Manager`. +3. Select `Wipe Data` for the relevant emulator. diff --git a/examples/rn-todo-list/backend/README.md b/examples/rn-todo-list/backend/README.md new file mode 100644 index 0000000000..07508bebf5 --- /dev/null +++ b/examples/rn-todo-list/backend/README.md @@ -0,0 +1,7 @@ +# Backend + +This contains the Atlas App Services App and its configurations for the example app. + +Please see the [main README](../README.md) for all instructions. + +> To learn more about the backend file structure, see [App Configuration](https://www.mongodb.com/docs/atlas/app-services/reference/config/). diff --git a/examples/rn-todo-list/backend/auth/custom_user_data.json b/examples/rn-todo-list/backend/auth/custom_user_data.json new file mode 100644 index 0000000000..a82d0fb255 --- /dev/null +++ b/examples/rn-todo-list/backend/auth/custom_user_data.json @@ -0,0 +1,3 @@ +{ + "enabled": false +} diff --git a/examples/rn-todo-list/backend/auth/providers.json b/examples/rn-todo-list/backend/auth/providers.json new file mode 100644 index 0000000000..352f51d7d1 --- /dev/null +++ b/examples/rn-todo-list/backend/auth/providers.json @@ -0,0 +1,22 @@ +{ + "anon-user": { + "name": "anon-user", + "type": "anon-user", + "disabled": false + }, + "api-key": { + "name": "api-key", + "type": "api-key", + "disabled": true + }, + "local-userpass": { + "name": "local-userpass", + "type": "local-userpass", + "config": { + "autoConfirm": true, + "resetPasswordUrl": "https://", + "runConfirmationFunction": false + }, + "disabled": false + } +} diff --git a/examples/rn-todo-list/backend/data_sources/mongodb-atlas/TodoList/Task/relationships.json b/examples/rn-todo-list/backend/data_sources/mongodb-atlas/TodoList/Task/relationships.json new file mode 100644 index 0000000000..0967ef424b --- /dev/null +++ b/examples/rn-todo-list/backend/data_sources/mongodb-atlas/TodoList/Task/relationships.json @@ -0,0 +1 @@ +{} diff --git a/examples/rn-todo-list/backend/data_sources/mongodb-atlas/TodoList/Task/rules.json b/examples/rn-todo-list/backend/data_sources/mongodb-atlas/TodoList/Task/rules.json new file mode 100644 index 0000000000..6ca1b3345c --- /dev/null +++ b/examples/rn-todo-list/backend/data_sources/mongodb-atlas/TodoList/Task/rules.json @@ -0,0 +1,23 @@ +{ + "collection": "Task", + "database": "TodoList", + "roles": [ + { + "name": "readOwnWriteOwn", + "apply_when": {}, + "document_filters": { + "write": { + "userId": "%%user.id" + }, + "read": { + "userId": "%%user.id" + } + }, + "read": true, + "write": true, + "insert": true, + "delete": true, + "search": true + } + ] +} diff --git a/examples/rn-todo-list/backend/data_sources/mongodb-atlas/TodoList/Task/schema.json b/examples/rn-todo-list/backend/data_sources/mongodb-atlas/TodoList/Task/schema.json new file mode 100644 index 0000000000..08ef6db636 --- /dev/null +++ b/examples/rn-todo-list/backend/data_sources/mongodb-atlas/TodoList/Task/schema.json @@ -0,0 +1,28 @@ +{ + "properties": { + "_id": { + "bsonType": "objectId" + }, + "createdAt": { + "bsonType": "date" + }, + "description": { + "bsonType": "string" + }, + "isComplete": { + "bsonType": "bool" + }, + "userId": { + "bsonType": "string" + } + }, + "required": [ + "_id", + "createdAt", + "description", + "isComplete", + "userId" + ], + "title": "Task", + "type": "object" +} diff --git a/examples/rn-todo-list/backend/data_sources/mongodb-atlas/config.json b/examples/rn-todo-list/backend/data_sources/mongodb-atlas/config.json new file mode 100644 index 0000000000..9913676dd9 --- /dev/null +++ b/examples/rn-todo-list/backend/data_sources/mongodb-atlas/config.json @@ -0,0 +1,10 @@ +{ + "name": "mongodb-atlas", + "type": "mongodb-atlas", + "config": { + "clusterName": "Cluster0", + "readPreference": "primary", + "wireProtocolEnabled": false + }, + "version": 1 +} diff --git a/examples/rn-todo-list/backend/data_sources/mongodb-atlas/default_rule.json b/examples/rn-todo-list/backend/data_sources/mongodb-atlas/default_rule.json new file mode 100644 index 0000000000..86c55c8767 --- /dev/null +++ b/examples/rn-todo-list/backend/data_sources/mongodb-atlas/default_rule.json @@ -0,0 +1,17 @@ +{ + "roles": [ + { + "name": "readAndWriteAll", + "apply_when": {}, + "document_filters": { + "write": true, + "read": true + }, + "read": true, + "write": true, + "insert": true, + "delete": true, + "search": true + } + ] +} diff --git a/examples/rn-todo-list/backend/environments/development.json b/examples/rn-todo-list/backend/environments/development.json new file mode 100644 index 0000000000..ad7e98e68c --- /dev/null +++ b/examples/rn-todo-list/backend/environments/development.json @@ -0,0 +1,3 @@ +{ + "values": {} +} diff --git a/examples/rn-todo-list/backend/environments/no-environment.json b/examples/rn-todo-list/backend/environments/no-environment.json new file mode 100644 index 0000000000..ad7e98e68c --- /dev/null +++ b/examples/rn-todo-list/backend/environments/no-environment.json @@ -0,0 +1,3 @@ +{ + "values": {} +} diff --git a/examples/rn-todo-list/backend/environments/production.json b/examples/rn-todo-list/backend/environments/production.json new file mode 100644 index 0000000000..ad7e98e68c --- /dev/null +++ b/examples/rn-todo-list/backend/environments/production.json @@ -0,0 +1,3 @@ +{ + "values": {} +} diff --git a/examples/rn-todo-list/backend/environments/qa.json b/examples/rn-todo-list/backend/environments/qa.json new file mode 100644 index 0000000000..ad7e98e68c --- /dev/null +++ b/examples/rn-todo-list/backend/environments/qa.json @@ -0,0 +1,3 @@ +{ + "values": {} +} diff --git a/examples/rn-todo-list/backend/environments/testing.json b/examples/rn-todo-list/backend/environments/testing.json new file mode 100644 index 0000000000..ad7e98e68c --- /dev/null +++ b/examples/rn-todo-list/backend/environments/testing.json @@ -0,0 +1,3 @@ +{ + "values": {} +} diff --git a/examples/rn-todo-list/backend/functions/config.json b/examples/rn-todo-list/backend/functions/config.json new file mode 100644 index 0000000000..fe51488c70 --- /dev/null +++ b/examples/rn-todo-list/backend/functions/config.json @@ -0,0 +1 @@ +[] diff --git a/examples/rn-todo-list/backend/graphql/config.json b/examples/rn-todo-list/backend/graphql/config.json new file mode 100644 index 0000000000..406b1abcde --- /dev/null +++ b/examples/rn-todo-list/backend/graphql/config.json @@ -0,0 +1,4 @@ +{ + "use_natural_pluralization": true, + "disable_schema_introspection": false +} diff --git a/examples/rn-todo-list/backend/http_endpoints/config.json b/examples/rn-todo-list/backend/http_endpoints/config.json new file mode 100644 index 0000000000..fe51488c70 --- /dev/null +++ b/examples/rn-todo-list/backend/http_endpoints/config.json @@ -0,0 +1 @@ +[] diff --git a/examples/rn-todo-list/backend/realm_config.json b/examples/rn-todo-list/backend/realm_config.json new file mode 100644 index 0000000000..aff50a7db3 --- /dev/null +++ b/examples/rn-todo-list/backend/realm_config.json @@ -0,0 +1,7 @@ +{ + "config_version": 20210101, + "name": "Todo-List", + "location": "IE", + "provider_region": "aws-eu-west-1", + "deployment_model": "GLOBAL" +} diff --git a/examples/rn-todo-list/backend/sync/config.json b/examples/rn-todo-list/backend/sync/config.json new file mode 100644 index 0000000000..78f4a71c74 --- /dev/null +++ b/examples/rn-todo-list/backend/sync/config.json @@ -0,0 +1,19 @@ +{ + "type": "flexible", + "state": "enabled", + "development_mode_enabled": true, + "service_name": "mongodb-atlas", + "database_name": "TodoList", + "client_max_offline_days": 30, + "is_recovery_mode_disabled": false, + "permissions": { + "rules": {}, + "defaultRoles": [] + }, + "collection_queryable_fields_names": { + "Task": [ + "isComplete", + "userId" + ] + } +} diff --git a/example/.bundle/config b/examples/rn-todo-list/frontend/.bundle/config similarity index 100% rename from example/.bundle/config rename to examples/rn-todo-list/frontend/.bundle/config diff --git a/examples/rn-todo-list/frontend/.eslintrc.js b/examples/rn-todo-list/frontend/.eslintrc.js new file mode 100644 index 0000000000..308f4ed596 --- /dev/null +++ b/examples/rn-todo-list/frontend/.eslintrc.js @@ -0,0 +1,22 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2023 Realm Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////// + +module.exports = { + root: true, + extends: '@react-native', +}; diff --git a/example/.gitignore b/examples/rn-todo-list/frontend/.gitignore similarity index 97% rename from example/.gitignore rename to examples/rn-todo-list/frontend/.gitignore index 16f8c30773..0cab2ac6fc 100644 --- a/example/.gitignore +++ b/examples/rn-todo-list/frontend/.gitignore @@ -61,3 +61,6 @@ yarn-error.log # Temporary files created by Metro to check the health of the file watcher .metro-health-check* + +# testing +/coverage diff --git a/examples/rn-todo-list/frontend/.prettierrc.js b/examples/rn-todo-list/frontend/.prettierrc.js new file mode 100644 index 0000000000..6857cd6f1e --- /dev/null +++ b/examples/rn-todo-list/frontend/.prettierrc.js @@ -0,0 +1,25 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2023 Realm Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////// + +module.exports = { + arrowParens: 'avoid', + bracketSameLine: true, + bracketSpacing: false, + singleQuote: true, + trailingComma: 'all', +}; diff --git a/example/.ruby-version b/examples/rn-todo-list/frontend/.ruby-version similarity index 100% rename from example/.ruby-version rename to examples/rn-todo-list/frontend/.ruby-version diff --git a/examples/rn-todo-list/frontend/.watchmanconfig b/examples/rn-todo-list/frontend/.watchmanconfig new file mode 100644 index 0000000000..0967ef424b --- /dev/null +++ b/examples/rn-todo-list/frontend/.watchmanconfig @@ -0,0 +1 @@ +{} diff --git a/example/Gemfile b/examples/rn-todo-list/frontend/Gemfile similarity index 53% rename from example/Gemfile rename to examples/rn-todo-list/frontend/Gemfile index 567e59805c..1fa2c2e1ab 100644 --- a/example/Gemfile +++ b/examples/rn-todo-list/frontend/Gemfile @@ -1,6 +1,6 @@ source 'https://rubygems.org' # You may use http://rbenv.org/ or https://rvm.io/ to install and use this version -ruby File.read(File.join(__dir__, '.ruby-version')).strip +ruby ">= 2.6.10" -gem 'cocoapods', '~> 1.11', '>= 1.11.3' +gem 'cocoapods', '~> 1.12' diff --git a/examples/rn-todo-list/frontend/README.md b/examples/rn-todo-list/frontend/README.md new file mode 100644 index 0000000000..97c45eac17 --- /dev/null +++ b/examples/rn-todo-list/frontend/README.md @@ -0,0 +1,5 @@ +# Frontend + +This contains the React Native code base for the example app. + +Please see the [main README](../README.md) for all instructions. diff --git a/example/__tests__/App-test.tsx b/examples/rn-todo-list/frontend/__tests__/App.test.tsx similarity index 65% rename from example/__tests__/App-test.tsx rename to examples/rn-todo-list/frontend/__tests__/App.test.tsx index 178476699b..b2ef268594 100644 --- a/example/__tests__/App-test.tsx +++ b/examples/rn-todo-list/frontend/__tests__/App.test.tsx @@ -4,7 +4,10 @@ import 'react-native'; import React from 'react'; -import App from '../App'; +import {App} from '../index'; + +// Note: import explicitly to use the types shipped with jest. +import {it} from '@jest/globals'; // Note: test renderer must be required after react-native. import renderer from 'react-test-renderer'; diff --git a/example/android/app/build.gradle b/examples/rn-todo-list/frontend/android/app/build.gradle similarity index 64% rename from example/android/app/build.gradle rename to examples/rn-todo-list/frontend/android/app/build.gradle index bceecd7e44..28d21fa625 100644 --- a/example/android/app/build.gradle +++ b/examples/rn-todo-list/frontend/android/app/build.gradle @@ -1,8 +1,6 @@ apply plugin: "com.android.application" apply plugin: "com.facebook.react" -import com.android.build.OutputFile - /** * This is the configuration block to customize your React Native Android app. * By default you don't need to apply any configuration, just uncomment the lines you need. @@ -12,11 +10,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") - // The folder where the react-native Codegen package is. Default is ../node_modules/react-native-codegen - codegenDir = file("../../../node_modules/react-native-codegen") + // 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") // 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 @@ -52,14 +50,6 @@ react { // hermesFlags = ["-O", "-output-source-map"] } -/** - * Set this to true to create four separate APKs instead of one, - * one for each native architecture. This is useful if you don't - * use App Bundles (https://developer.android.com/guide/app-bundle/) - * and want to have separate APKs to upload to the Play Store. - */ -def enableSeparateBuildPerCPUArchitecture = false - /** * Set this to true to Run Proguard on Release builds to minify the Java bytecode. */ @@ -78,38 +68,19 @@ def enableProguardInReleaseBuilds = false */ def jscFlavor = 'org.webkit:android-jsc:+' -/** - * Private function to get the list of Native Architectures you want to build. - * This reads the value from reactNativeArchitectures in your gradle.properties - * file and works together with the --active-arch-only flag of react-native run-android. - */ -def reactNativeArchitectures() { - def value = project.getProperties().get("reactNativeArchitectures") - return value ? value.split(",") : ["armeabi-v7a", "x86", "x86_64", "arm64-v8a"] -} - android { ndkVersion rootProject.ext.ndkVersion compileSdkVersion rootProject.ext.compileSdkVersion - namespace "com.realmexample" + namespace "com.examplerntodolist" defaultConfig { - applicationId "com.realmexample" + applicationId "com.examplerntodolist" minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion versionCode 1 versionName "1.0" } - - splits { - abi { - reset() - enable enableSeparateBuildPerCPUArchitecture - universalApk false // If true, also generate a universal APK - include (*reactNativeArchitectures()) - } - } signingConfigs { debug { storeFile file('debug.keystore') @@ -130,30 +101,12 @@ android { proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro" } } - - // applicationVariants are e.g. debug, release - applicationVariants.all { variant -> - variant.outputs.each { output -> - // For each separate APK per architecture, set a unique version code as described here: - // https://developer.android.com/studio/build/configure-apk-splits.html - // Example: versionCode 1 will generate 1001 for armeabi-v7a, 1002 for x86, etc. - def versionCodes = ["armeabi-v7a": 1, "x86": 2, "arm64-v8a": 3, "x86_64": 4] - def abi = output.getFilter(OutputFile.ABI) - if (abi != null) { // null for the universal-debug, universal-release variants - output.versionCodeOverride = - defaultConfig.versionCode * 1000 + versionCodes.get(abi) - } - - } - } } dependencies { // The version of react-native is set by the React Native Gradle Plugin implementation("com.facebook.react:react-android") - implementation("androidx.swiperefreshlayout:swiperefreshlayout:1.0.0") - debugImplementation("com.facebook.flipper:flipper:${FLIPPER_VERSION}") debugImplementation("com.facebook.flipper:flipper-network-plugin:${FLIPPER_VERSION}") { exclude group:'com.squareup.okhttp3', module:'okhttp' @@ -167,4 +120,4 @@ dependencies { } } -apply from: file("../../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesAppBuildGradle(project) +apply from: file("../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesAppBuildGradle(project) diff --git a/example/android/app/debug.keystore b/examples/rn-todo-list/frontend/android/app/debug.keystore similarity index 100% rename from example/android/app/debug.keystore rename to examples/rn-todo-list/frontend/android/app/debug.keystore diff --git a/example/android/app/proguard-rules.pro b/examples/rn-todo-list/frontend/android/app/proguard-rules.pro similarity index 100% rename from example/android/app/proguard-rules.pro rename to examples/rn-todo-list/frontend/android/app/proguard-rules.pro diff --git a/example/android/app/src/debug/AndroidManifest.xml b/examples/rn-todo-list/frontend/android/app/src/debug/AndroidManifest.xml similarity index 100% rename from example/android/app/src/debug/AndroidManifest.xml rename to examples/rn-todo-list/frontend/android/app/src/debug/AndroidManifest.xml diff --git a/example/android/app/src/debug/java/com/realmexample/ReactNativeFlipper.java b/examples/rn-todo-list/frontend/android/app/src/debug/java/com/examplerntodolist/ReactNativeFlipper.java similarity index 99% rename from example/android/app/src/debug/java/com/realmexample/ReactNativeFlipper.java rename to examples/rn-todo-list/frontend/android/app/src/debug/java/com/examplerntodolist/ReactNativeFlipper.java index 3b5df21548..9ea2348a5b 100644 --- a/example/android/app/src/debug/java/com/realmexample/ReactNativeFlipper.java +++ b/examples/rn-todo-list/frontend/android/app/src/debug/java/com/examplerntodolist/ReactNativeFlipper.java @@ -4,7 +4,7 @@ *

This source code is licensed under the MIT license found in the LICENSE file in the root * directory of this source tree. */ -package com.realmexample; +package com.examplerntodolist; import android.content.Context; import com.facebook.flipper.android.AndroidFlipperClient; diff --git a/example/android/app/src/main/AndroidManifest.xml b/examples/rn-todo-list/frontend/android/app/src/main/AndroidManifest.xml similarity index 100% rename from example/android/app/src/main/AndroidManifest.xml rename to examples/rn-todo-list/frontend/android/app/src/main/AndroidManifest.xml diff --git a/example/android/app/src/main/java/com/realmexample/MainActivity.java b/examples/rn-todo-list/frontend/android/app/src/main/java/com/examplerntodolist/MainActivity.java similarity index 74% rename from example/android/app/src/main/java/com/realmexample/MainActivity.java rename to examples/rn-todo-list/frontend/android/app/src/main/java/com/examplerntodolist/MainActivity.java index d7550543a1..e4a8493c92 100644 --- a/example/android/app/src/main/java/com/realmexample/MainActivity.java +++ b/examples/rn-todo-list/frontend/android/app/src/main/java/com/examplerntodolist/MainActivity.java @@ -1,4 +1,4 @@ -package com.realmexample; +package com.examplerntodolist; import com.facebook.react.ReactActivity; import com.facebook.react.ReactActivityDelegate; @@ -13,7 +13,7 @@ public class MainActivity extends ReactActivity { */ @Override protected String getMainComponentName() { - return "RealmExample"; + return "ExampleRnTodoList"; } /** @@ -27,9 +27,6 @@ protected ReactActivityDelegate createReactActivityDelegate() { this, getMainComponentName(), // If you opted-in for the New Architecture, we enable the Fabric Renderer. - DefaultNewArchitectureEntryPoint.getFabricEnabled(), // fabricEnabled - // If you opted-in for the New Architecture, we enable Concurrent React (i.e. React 18). - DefaultNewArchitectureEntryPoint.getConcurrentReactEnabled() // concurrentRootEnabled - ); + DefaultNewArchitectureEntryPoint.getFabricEnabled()); } } diff --git a/example/android/app/src/main/java/com/realmexample/MainApplication.java b/examples/rn-todo-list/frontend/android/app/src/main/java/com/examplerntodolist/MainApplication.java similarity index 98% rename from example/android/app/src/main/java/com/realmexample/MainApplication.java rename to examples/rn-todo-list/frontend/android/app/src/main/java/com/examplerntodolist/MainApplication.java index d438b8e4a2..34eb221c40 100644 --- a/example/android/app/src/main/java/com/realmexample/MainApplication.java +++ b/examples/rn-todo-list/frontend/android/app/src/main/java/com/examplerntodolist/MainApplication.java @@ -1,4 +1,4 @@ -package com.realmexample; +package com.examplerntodolist; import android.app.Application; import com.facebook.react.PackageList; diff --git a/example/android/app/src/main/res/drawable/rn_edit_text_material.xml b/examples/rn-todo-list/frontend/android/app/src/main/res/drawable/rn_edit_text_material.xml similarity index 99% rename from example/android/app/src/main/res/drawable/rn_edit_text_material.xml rename to examples/rn-todo-list/frontend/android/app/src/main/res/drawable/rn_edit_text_material.xml index f35d996202..73b37e4d99 100644 --- a/example/android/app/src/main/res/drawable/rn_edit_text_material.xml +++ b/examples/rn-todo-list/frontend/android/app/src/main/res/drawable/rn_edit_text_material.xml @@ -20,7 +20,7 @@ android:insetBottom="@dimen/abc_edit_text_inset_bottom_material"> -