├── .buckconfig
├── .eslintrc.js
├── .gitattributes
├── .gitignore
├── .node-version
├── .prettierrc.js
├── .ruby-version
├── .watchmanconfig
├── App.tsx
├── Gemfile
├── README.md
├── __tests__
└── App-test.tsx
├── android
├── app
│ ├── _BUCK
│ ├── build.gradle
│ ├── build_defs.bzl
│ ├── debug.keystore
│ ├── proguard-rules.pro
│ └── src
│ │ ├── debug
│ │ ├── AndroidManifest.xml
│ │ └── java
│ │ │ └── com
│ │ │ └── reactnativetypescriptexamples
│ │ │ └── ReactNativeFlipper.java
│ │ └── main
│ │ ├── AndroidManifest.xml
│ │ ├── java
│ │ └── com
│ │ │ └── reactnativetypescriptexamples
│ │ │ ├── MainActivity.java
│ │ │ ├── MainApplication.java
│ │ │ └── newarchitecture
│ │ │ ├── MainApplicationReactNativeHost.java
│ │ │ ├── components
│ │ │ └── MainComponentsRegistry.java
│ │ │ └── modules
│ │ │ └── MainApplicationTurboModuleManagerDelegate.java
│ │ ├── jni
│ │ ├── CMakeLists.txt
│ │ ├── MainApplicationModuleProvider.cpp
│ │ ├── MainApplicationModuleProvider.h
│ │ ├── MainApplicationTurboModuleManagerDelegate.cpp
│ │ ├── MainApplicationTurboModuleManagerDelegate.h
│ │ ├── MainComponentsRegistry.cpp
│ │ ├── MainComponentsRegistry.h
│ │ └── OnLoad.cpp
│ │ └── res
│ │ ├── drawable
│ │ └── rn_edit_text_material.xml
│ │ ├── mipmap-hdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-mdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xhdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xxhdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xxxhdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ └── values
│ │ ├── strings.xml
│ │ └── styles.xml
├── build.gradle
├── gradle.properties
├── gradle
│ └── wrapper
│ │ ├── gradle-wrapper.jar
│ │ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
└── settings.gradle
├── app.json
├── babel.config.js
├── examples
├── 1-quiz-game
│ ├── App.tsx
│ ├── mockdata.json
│ └── screens
│ │ ├── GameScreen.tsx
│ │ ├── StartScreen.tsx
│ │ └── game-screen-components
│ │ ├── AnswerBox.tsx
│ │ ├── Header.tsx
│ │ ├── ProgressBar.tsx
│ │ ├── QuestionBox.tsx
│ │ └── ResultModal.tsx
├── 2-booking-car
│ ├── App.tsx
│ ├── ChooseLocation.tsx
│ ├── Main.tsx
│ ├── const.ts
│ └── googleAPI.ts
└── 3-gmail-clone
│ ├── app
│ ├── App.tsx
│ ├── Navigation.tsx
│ ├── components
│ │ ├── EmailList.tsx
│ │ ├── EmailListItem.tsx
│ │ ├── ScreenHeader.tsx
│ │ └── Toolbar.tsx
│ ├── models
│ │ ├── Store.ts
│ │ └── models.ts
│ └── screens
│ │ ├── DetailScreen.tsx
│ │ ├── InboxScreen.tsx
│ │ ├── LoginScreen.tsx
│ │ ├── SplashScreen.tsx
│ │ ├── TrashScreen.tsx
│ │ └── login
│ │ ├── LoginForm.tsx
│ │ └── google-logo.png
│ └── server
│ ├── README.md
│ ├── additional_routes.js
│ ├── config.json
│ ├── database.json
│ ├── jwt-authenticate.js
│ ├── package.json
│ ├── server.js
│ └── yarn.lock
├── index.js
├── ios
├── .xcode.env
├── Podfile
├── ReactNativeTypescriptExamples.xcodeproj
│ ├── project.pbxproj
│ └── xcshareddata
│ │ └── xcschemes
│ │ └── ReactNativeTypescriptExamples.xcscheme
├── ReactNativeTypescriptExamples
│ ├── AppDelegate.h
│ ├── AppDelegate.mm
│ ├── Images.xcassets
│ │ ├── AppIcon.appiconset
│ │ │ └── Contents.json
│ │ └── Contents.json
│ ├── Info.plist
│ ├── LaunchScreen.storyboard
│ └── main.m
└── ReactNativeTypescriptExamplesTests
│ ├── Info.plist
│ └── ReactNativeTypescriptExamplesTests.m
├── metro.config.js
├── package.json
├── tsconfig.json
└── yarn.lock
/.buckconfig:
--------------------------------------------------------------------------------
1 |
2 | [android]
3 | target = Google Inc.:Google APIs:23
4 |
5 | [maven_repositories]
6 | central = https://repo1.maven.org/maven2
7 |
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | extends: '@react-native-community',
4 | parser: '@typescript-eslint/parser',
5 | plugins: ['@typescript-eslint'],
6 | overrides: [
7 | {
8 | files: ['*.ts', '*.tsx'],
9 | rules: {
10 | '@typescript-eslint/no-shadow': ['error'],
11 | 'no-shadow': 'off',
12 | 'no-undef': 'off',
13 | },
14 | },
15 | ],
16 | };
17 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | *.pbxproj -text
2 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # OSX
2 | #
3 | .DS_Store
4 |
5 | # Xcode
6 | #
7 | build/
8 | *.pbxuser
9 | !default.pbxuser
10 | *.mode1v3
11 | !default.mode1v3
12 | *.mode2v3
13 | !default.mode2v3
14 | *.perspectivev3
15 | !default.perspectivev3
16 | xcuserdata
17 | *.xccheckout
18 | *.moved-aside
19 | DerivedData
20 | *.hmap
21 | *.ipa
22 | *.xcuserstate
23 | ios/.xcode.env.local
24 |
25 | # Android/IntelliJ
26 | #
27 | build/
28 | .idea
29 | .gradle
30 | local.properties
31 | *.iml
32 | *.hprof
33 | .cxx/
34 |
35 | # node.js
36 | #
37 | node_modules/
38 | npm-debug.log
39 | yarn-error.log
40 |
41 | # BUCK
42 | buck-out/
43 | \.buckd/
44 | *.keystore
45 | !debug.keystore
46 |
47 | # fastlane
48 | #
49 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
50 | # screenshots whenever they are needed.
51 | # For more information about the recommended setup visit:
52 | # https://docs.fastlane.tools/best-practices/source-control/
53 |
54 | **/fastlane/report.xml
55 | **/fastlane/Preview.html
56 | **/fastlane/screenshots
57 | **/fastlane/test_output
58 |
59 | # Bundle artifact
60 | *.jsbundle
61 |
62 | # Ruby / CocoaPods
63 | /ios/Pods/
64 | /vendor/bundle/
65 |
--------------------------------------------------------------------------------
/.node-version:
--------------------------------------------------------------------------------
1 | 16
2 |
--------------------------------------------------------------------------------
/.prettierrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | arrowParens: 'avoid',
3 | bracketSameLine: true,
4 | bracketSpacing: false,
5 | printWidth: 100,
6 | singleQuote: true,
7 | trailingComma: 'all',
8 | };
9 |
--------------------------------------------------------------------------------
/.ruby-version:
--------------------------------------------------------------------------------
1 | 2.7.5
2 |
--------------------------------------------------------------------------------
/.watchmanconfig:
--------------------------------------------------------------------------------
1 | {}
--------------------------------------------------------------------------------
/App.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Quiz from './examples/1-quiz-game/App';
3 | import BookingCar from './examples/2-booking-car/App';
4 | import GmailClone from './examples/3-gmail-clone/app/App';
5 |
6 | const App: React.FunctionComponent = () => {
7 | // Comment unwanted examples, return the example you want to display
8 | return ;
9 | return ;
10 | return ;
11 | };
12 |
13 | export default App;
14 |
--------------------------------------------------------------------------------
/Gemfile:
--------------------------------------------------------------------------------
1 | source 'https://rubygems.org'
2 |
3 | # You may use http://rbenv.org/ or https://rvm.io/ to install and use this version
4 | ruby '2.7.5'
5 |
6 | gem 'cocoapods', '~> 1.11', '>= 1.11.2'
7 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # React Native Typescript examples
2 |
3 | Learn React Native (version 0.70 with Typescript) by easy-to-difficult examples.
4 |
5 | _For more basic examples, see [React Native Expo examples](https://github.com/robinhuy/react-native-expo-examples)_
6 |
7 | ## Run project in development
8 |
9 | - Setting up the development environment: https://reactnative.dev/docs/environment-setup.
10 |
11 | - Install dependencies: `yarn` (or `npm install`). On iOS run: `npx pod-install`.
12 |
13 | - Run on Android: `yarn android` (or `npm run android`).
14 |
15 | - Run on iOS: `yarn ios` (or `npm run ios`).
16 |
17 | ## Change example
18 |
19 | Modify code in `App.tsx`, each example is an application.
20 |
21 | ## Preview
22 |
23 | ### 1. Quiz Game
24 |
25 | Learn how to use: **Type Script static type checking**, **React Hook useEffect + Timer**
26 |
27 |
28 |
29 | ### 2. Booking Car
30 |
31 | Learn how to use: **Native Base + React Native Vector Icons**, **React Native Maps + React Native Maps Directions**, **Google Map API**, **Keyboard + Keyboard Event**
32 |
33 |
34 |
35 | Note: To run this example, you must get & config Google Map API KEY for [Android](https://developers.google.com/maps/documentation/android-sdk/get-api-key) or [iOS](https://developers.google.com/maps/documentation/ios-sdk/get-api-key)
36 |
37 | ### 3. Gmail clone
38 |
39 | Learn how to use: **API Sauce**, **MobX + MobX React Lite**, **React Context**, **React Navigation Authentication flows + useFocusEffect**, **React Native Web View**
40 |
41 |
42 |
43 | Note: To run this example, you must start the server ([https://github.com/robinhuy/fake-api-nodejs](https://github.com/robinhuy/fake-api-nodejs)) in folder `server`:
44 |
45 | ```
46 | cd server
47 | yarn
48 | yarn start
49 | ```
50 |
--------------------------------------------------------------------------------
/__tests__/App-test.tsx:
--------------------------------------------------------------------------------
1 | /**
2 | * @format
3 | */
4 |
5 | import 'react-native';
6 | import React from 'react';
7 | import App from '../App';
8 |
9 | // Note: test renderer must be required after react-native.
10 | import renderer from 'react-test-renderer';
11 |
12 | it('renders correctly', () => {
13 | renderer.create( );
14 | });
15 |
--------------------------------------------------------------------------------
/android/app/_BUCK:
--------------------------------------------------------------------------------
1 | # To learn about Buck see [Docs](https://buckbuild.com/).
2 | # To run your application with Buck:
3 | # - install Buck
4 | # - `npm start` - to start the packager
5 | # - `cd android`
6 | # - `keytool -genkey -v -keystore keystores/debug.keystore -storepass android -alias androiddebugkey -keypass android -dname "CN=Android Debug,O=Android,C=US"`
7 | # - `./gradlew :app:copyDownloadableDepsToLibs` - make all Gradle compile dependencies available to Buck
8 | # - `buck install -r android/app` - compile, install and run application
9 | #
10 |
11 | load(":build_defs.bzl", "create_aar_targets", "create_jar_targets")
12 |
13 | lib_deps = []
14 |
15 | create_aar_targets(glob(["libs/*.aar"]))
16 |
17 | create_jar_targets(glob(["libs/*.jar"]))
18 |
19 | android_library(
20 | name = "all-libs",
21 | exported_deps = lib_deps,
22 | )
23 |
24 | android_library(
25 | name = "app-code",
26 | srcs = glob([
27 | "src/main/java/**/*.java",
28 | ]),
29 | deps = [
30 | ":all-libs",
31 | ":build_config",
32 | ":res",
33 | ],
34 | )
35 |
36 | android_build_config(
37 | name = "build_config",
38 | package = "com.reactnativetypescriptexamples",
39 | )
40 |
41 | android_resource(
42 | name = "res",
43 | package = "com.reactnativetypescriptexamples",
44 | res = "src/main/res",
45 | )
46 |
47 | android_binary(
48 | name = "app",
49 | keystore = "//android/keystores:debug",
50 | manifest = "src/main/AndroidManifest.xml",
51 | package_type = "debug",
52 | deps = [
53 | ":app-code",
54 | ],
55 | )
56 |
--------------------------------------------------------------------------------
/android/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: "com.android.application"
2 |
3 | import com.android.build.OutputFile
4 | import org.apache.tools.ant.taskdefs.condition.Os
5 |
6 | /**
7 | * The react.gradle file registers a task for each build variant (e.g. bundleDebugJsAndAssets
8 | * and bundleReleaseJsAndAssets).
9 | * These basically call `react-native bundle` with the correct arguments during the Android build
10 | * cycle. By default, bundleDebugJsAndAssets is skipped, as in debug/dev mode we prefer to load the
11 | * bundle directly from the development server. Below you can see all the possible configurations
12 | * and their defaults. If you decide to add a configuration block, make sure to add it before the
13 | * `apply from: "../../node_modules/react-native/react.gradle"` line.
14 | *
15 | * project.ext.react = [
16 | * // the name of the generated asset file containing your JS bundle
17 | * bundleAssetName: "index.android.bundle",
18 | *
19 | * // the entry file for bundle generation. If none specified and
20 | * // "index.android.js" exists, it will be used. Otherwise "index.js" is
21 | * // default. Can be overridden with ENTRY_FILE environment variable.
22 | * entryFile: "index.android.js",
23 | *
24 | * // https://reactnative.dev/docs/performance#enable-the-ram-format
25 | * bundleCommand: "ram-bundle",
26 | *
27 | * // whether to bundle JS and assets in debug mode
28 | * bundleInDebug: false,
29 | *
30 | * // whether to bundle JS and assets in release mode
31 | * bundleInRelease: true,
32 | *
33 | * // whether to bundle JS and assets in another build variant (if configured).
34 | * // See http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Build-Variants
35 | * // The configuration property can be in the following formats
36 | * // 'bundleIn${productFlavor}${buildType}'
37 | * // 'bundleIn${buildType}'
38 | * // bundleInFreeDebug: true,
39 | * // bundleInPaidRelease: true,
40 | * // bundleInBeta: true,
41 | *
42 | * // whether to disable dev mode in custom build variants (by default only disabled in release)
43 | * // for example: to disable dev mode in the staging build type (if configured)
44 | * devDisabledInStaging: true,
45 | * // The configuration property can be in the following formats
46 | * // 'devDisabledIn${productFlavor}${buildType}'
47 | * // 'devDisabledIn${buildType}'
48 | *
49 | * // the root of your project, i.e. where "package.json" lives
50 | * root: "../../",
51 | *
52 | * // where to put the JS bundle asset in debug mode
53 | * jsBundleDirDebug: "$buildDir/intermediates/assets/debug",
54 | *
55 | * // where to put the JS bundle asset in release mode
56 | * jsBundleDirRelease: "$buildDir/intermediates/assets/release",
57 | *
58 | * // where to put drawable resources / React Native assets, e.g. the ones you use via
59 | * // require('./image.png')), in debug mode
60 | * resourcesDirDebug: "$buildDir/intermediates/res/merged/debug",
61 | *
62 | * // where to put drawable resources / React Native assets, e.g. the ones you use via
63 | * // require('./image.png')), in release mode
64 | * resourcesDirRelease: "$buildDir/intermediates/res/merged/release",
65 | *
66 | * // by default the gradle tasks are skipped if none of the JS files or assets change; this means
67 | * // that we don't look at files in android/ or ios/ to determine whether the tasks are up to
68 | * // date; if you have any other folders that you want to ignore for performance reasons (gradle
69 | * // indexes the entire tree), add them here. Alternatively, if you have JS files in android/
70 | * // for example, you might want to remove it from here.
71 | * inputExcludes: ["android/**", "ios/**"],
72 | *
73 | * // override which node gets called and with what additional arguments
74 | * nodeExecutableAndArgs: ["node"],
75 | *
76 | * // supply additional arguments to the packager
77 | * extraPackagerArgs: []
78 | * ]
79 | */
80 |
81 | project.ext.react = [
82 | enableHermes: true, // clean and rebuild if changing
83 | ]
84 |
85 | apply from: "../../node_modules/react-native/react.gradle"
86 |
87 | /**
88 | * Set this to true to create two separate APKs instead of one:
89 | * - An APK that only works on ARM devices
90 | * - An APK that only works on x86 devices
91 | * The advantage is the size of the APK is reduced by about 4MB.
92 | * Upload all the APKs to the Play Store and people will download
93 | * the correct one based on the CPU architecture of their device.
94 | */
95 | def enableSeparateBuildPerCPUArchitecture = false
96 |
97 | /**
98 | * Run Proguard to shrink the Java bytecode in release builds.
99 | */
100 | def enableProguardInReleaseBuilds = false
101 |
102 | /**
103 | * The preferred build flavor of JavaScriptCore.
104 | *
105 | * For example, to use the international variant, you can use:
106 | * `def jscFlavor = 'org.webkit:android-jsc-intl:+'`
107 | *
108 | * The international variant includes ICU i18n library and necessary data
109 | * allowing to use e.g. `Date.toLocaleString` and `String.localeCompare` that
110 | * give correct results when using with locales other than en-US. Note that
111 | * this variant is about 6MiB larger per architecture than default.
112 | */
113 | def jscFlavor = 'org.webkit:android-jsc:+'
114 |
115 | /**
116 | * Whether to enable the Hermes VM.
117 | *
118 | * This should be set on project.ext.react and that value will be read here. If it is not set
119 | * on project.ext.react, JavaScript will not be compiled to Hermes Bytecode
120 | * and the benefits of using Hermes will therefore be sharply reduced.
121 | */
122 | def enableHermes = project.ext.react.get("enableHermes", false);
123 |
124 | /**
125 | * Architectures to build native code for.
126 | */
127 | def reactNativeArchitectures() {
128 | def value = project.getProperties().get("reactNativeArchitectures")
129 | return value ? value.split(",") : ["armeabi-v7a", "x86", "x86_64", "arm64-v8a"]
130 | }
131 |
132 | android {
133 | ndkVersion rootProject.ext.ndkVersion
134 |
135 | compileSdkVersion rootProject.ext.compileSdkVersion
136 |
137 | defaultConfig {
138 | applicationId "com.reactnativetypescriptexamples"
139 | minSdkVersion rootProject.ext.minSdkVersion
140 | targetSdkVersion rootProject.ext.targetSdkVersion
141 | versionCode 1
142 | versionName "1.0"
143 | buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString()
144 |
145 | if (isNewArchitectureEnabled()) {
146 | // We configure the CMake build only if you decide to opt-in for the New Architecture.
147 | externalNativeBuild {
148 | cmake {
149 | arguments "-DPROJECT_BUILD_DIR=$buildDir",
150 | "-DREACT_ANDROID_DIR=$rootDir/../node_modules/react-native/ReactAndroid",
151 | "-DREACT_ANDROID_BUILD_DIR=$rootDir/../node_modules/react-native/ReactAndroid/build",
152 | "-DNODE_MODULES_DIR=$rootDir/../node_modules",
153 | "-DANDROID_STL=c++_shared"
154 | }
155 | }
156 | if (!enableSeparateBuildPerCPUArchitecture) {
157 | ndk {
158 | abiFilters (*reactNativeArchitectures())
159 | }
160 | }
161 | }
162 | }
163 |
164 | if (isNewArchitectureEnabled()) {
165 | // We configure the NDK build only if you decide to opt-in for the New Architecture.
166 | externalNativeBuild {
167 | cmake {
168 | path "$projectDir/src/main/jni/CMakeLists.txt"
169 | }
170 | }
171 | def reactAndroidProjectDir = project(':ReactAndroid').projectDir
172 | def packageReactNdkDebugLibs = tasks.register("packageReactNdkDebugLibs", Copy) {
173 | dependsOn(":ReactAndroid:packageReactNdkDebugLibsForBuck")
174 | from("$reactAndroidProjectDir/src/main/jni/prebuilt/lib")
175 | into("$buildDir/react-ndk/exported")
176 | }
177 | def packageReactNdkReleaseLibs = tasks.register("packageReactNdkReleaseLibs", Copy) {
178 | dependsOn(":ReactAndroid:packageReactNdkReleaseLibsForBuck")
179 | from("$reactAndroidProjectDir/src/main/jni/prebuilt/lib")
180 | into("$buildDir/react-ndk/exported")
181 | }
182 | afterEvaluate {
183 | // If you wish to add a custom TurboModule or component locally,
184 | // you should uncomment this line.
185 | // preBuild.dependsOn("generateCodegenArtifactsFromSchema")
186 | preDebugBuild.dependsOn(packageReactNdkDebugLibs)
187 | preReleaseBuild.dependsOn(packageReactNdkReleaseLibs)
188 |
189 | // Due to a bug inside AGP, we have to explicitly set a dependency
190 | // between configureCMakeDebug* tasks and the preBuild tasks.
191 | // This can be removed once this is solved: https://issuetracker.google.com/issues/207403732
192 | configureCMakeRelWithDebInfo.dependsOn(preReleaseBuild)
193 | configureCMakeDebug.dependsOn(preDebugBuild)
194 | reactNativeArchitectures().each { architecture ->
195 | tasks.findByName("configureCMakeDebug[${architecture}]")?.configure {
196 | dependsOn("preDebugBuild")
197 | }
198 | tasks.findByName("configureCMakeRelWithDebInfo[${architecture}]")?.configure {
199 | dependsOn("preReleaseBuild")
200 | }
201 | }
202 | }
203 | }
204 |
205 | splits {
206 | abi {
207 | reset()
208 | enable enableSeparateBuildPerCPUArchitecture
209 | universalApk false // If true, also generate a universal APK
210 | include (*reactNativeArchitectures())
211 | }
212 | }
213 | signingConfigs {
214 | debug {
215 | storeFile file('debug.keystore')
216 | storePassword 'android'
217 | keyAlias 'androiddebugkey'
218 | keyPassword 'android'
219 | }
220 | }
221 | buildTypes {
222 | debug {
223 | signingConfig signingConfigs.debug
224 | }
225 | release {
226 | // Caution! In production, you need to generate your own keystore file.
227 | // see https://reactnative.dev/docs/signed-apk-android.
228 | signingConfig signingConfigs.debug
229 | minifyEnabled enableProguardInReleaseBuilds
230 | proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
231 | }
232 | }
233 |
234 | // applicationVariants are e.g. debug, release
235 | applicationVariants.all { variant ->
236 | variant.outputs.each { output ->
237 | // For each separate APK per architecture, set a unique version code as described here:
238 | // https://developer.android.com/studio/build/configure-apk-splits.html
239 | // Example: versionCode 1 will generate 1001 for armeabi-v7a, 1002 for x86, etc.
240 | def versionCodes = ["armeabi-v7a": 1, "x86": 2, "arm64-v8a": 3, "x86_64": 4]
241 | def abi = output.getFilter(OutputFile.ABI)
242 | if (abi != null) { // null for the universal-debug, universal-release variants
243 | output.versionCodeOverride =
244 | defaultConfig.versionCode * 1000 + versionCodes.get(abi)
245 | }
246 |
247 | }
248 | }
249 | }
250 |
251 | dependencies {
252 | implementation fileTree(dir: "libs", include: ["*.jar"])
253 |
254 | //noinspection GradleDynamicVersion
255 | implementation "com.facebook.react:react-native:+" // From node_modules
256 |
257 | implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.0.0"
258 |
259 | debugImplementation("com.facebook.flipper:flipper:${FLIPPER_VERSION}") {
260 | exclude group:'com.facebook.fbjni'
261 | }
262 |
263 | debugImplementation("com.facebook.flipper:flipper-network-plugin:${FLIPPER_VERSION}") {
264 | exclude group:'com.facebook.flipper'
265 | exclude group:'com.squareup.okhttp3', module:'okhttp'
266 | }
267 |
268 | debugImplementation("com.facebook.flipper:flipper-fresco-plugin:${FLIPPER_VERSION}") {
269 | exclude group:'com.facebook.flipper'
270 | }
271 |
272 | if (enableHermes) {
273 | //noinspection GradleDynamicVersion
274 | implementation("com.facebook.react:hermes-engine:+") { // From node_modules
275 | exclude group:'com.facebook.fbjni'
276 | }
277 | } else {
278 | implementation jscFlavor
279 | }
280 | }
281 |
282 | if (isNewArchitectureEnabled()) {
283 | // If new architecture is enabled, we let you build RN from source
284 | // Otherwise we fallback to a prebuilt .aar bundled in the NPM package.
285 | // This will be applied to all the imported transtitive dependency.
286 | configurations.all {
287 | resolutionStrategy.dependencySubstitution {
288 | substitute(module("com.facebook.react:react-native"))
289 | .using(project(":ReactAndroid"))
290 | .because("On New Architecture we're building React Native from source")
291 | substitute(module("com.facebook.react:hermes-engine"))
292 | .using(project(":ReactAndroid:hermes-engine"))
293 | .because("On New Architecture we're building Hermes from source")
294 | }
295 | }
296 | }
297 |
298 | // Run this once to be able to run the application with BUCK
299 | // puts all compile dependencies into folder libs for BUCK to use
300 | task copyDownloadableDepsToLibs(type: Copy) {
301 | from configurations.implementation
302 | into 'libs'
303 | }
304 |
305 | apply from: file("../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesAppBuildGradle(project)
306 |
307 | // https://github.com/oblador/react-native-vector-icons#android
308 | apply from: "../../node_modules/react-native-vector-icons/fonts.gradle"
309 |
310 | def isNewArchitectureEnabled() {
311 | // To opt-in for the New Architecture, you can either:
312 | // - Set `newArchEnabled` to true inside the `gradle.properties` file
313 | // - Invoke gradle with `-newArchEnabled=true`
314 | // - Set an environment variable `ORG_GRADLE_PROJECT_newArchEnabled=true`
315 | return project.hasProperty("newArchEnabled") && project.newArchEnabled == "true"
316 | }
317 |
--------------------------------------------------------------------------------
/android/app/build_defs.bzl:
--------------------------------------------------------------------------------
1 | """Helper definitions to glob .aar and .jar targets"""
2 |
3 | def create_aar_targets(aarfiles):
4 | for aarfile in aarfiles:
5 | name = "aars__" + aarfile[aarfile.rindex("/") + 1:aarfile.rindex(".aar")]
6 | lib_deps.append(":" + name)
7 | android_prebuilt_aar(
8 | name = name,
9 | aar = aarfile,
10 | )
11 |
12 | def create_jar_targets(jarfiles):
13 | for jarfile in jarfiles:
14 | name = "jars__" + jarfile[jarfile.rindex("/") + 1:jarfile.rindex(".jar")]
15 | lib_deps.append(":" + name)
16 | prebuilt_jar(
17 | name = name,
18 | binary_jar = jarfile,
19 | )
20 |
--------------------------------------------------------------------------------
/android/app/debug.keystore:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/robinhuy/react-native-typescript-examples/3a088e6b7407fde40b8161c38872fc482b5f8118/android/app/debug.keystore
--------------------------------------------------------------------------------
/android/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /usr/local/Cellar/android-sdk/24.3.3/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # https://docs.swmansion.com/react-native-reanimated/docs/fundamentals/installation/
13 | -keep class com.swmansion.reanimated.** { *; }
14 | -keep class com.facebook.react.turbomodule.** { *; }
15 |
--------------------------------------------------------------------------------
/android/app/src/debug/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/android/app/src/debug/java/com/reactnativetypescriptexamples/ReactNativeFlipper.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) Meta Platforms, Inc. and affiliates.
3 | *
4 | *
This source code is licensed under the MIT license found in the LICENSE file in the root
5 | * directory of this source tree.
6 | */
7 | package com.reactnativetypescriptexamples;
8 |
9 | import android.content.Context;
10 | import com.facebook.flipper.android.AndroidFlipperClient;
11 | import com.facebook.flipper.android.utils.FlipperUtils;
12 | import com.facebook.flipper.core.FlipperClient;
13 | import com.facebook.flipper.plugins.crashreporter.CrashReporterPlugin;
14 | import com.facebook.flipper.plugins.databases.DatabasesFlipperPlugin;
15 | import com.facebook.flipper.plugins.fresco.FrescoFlipperPlugin;
16 | import com.facebook.flipper.plugins.inspector.DescriptorMapping;
17 | import com.facebook.flipper.plugins.inspector.InspectorFlipperPlugin;
18 | import com.facebook.flipper.plugins.network.FlipperOkhttpInterceptor;
19 | import com.facebook.flipper.plugins.network.NetworkFlipperPlugin;
20 | import com.facebook.flipper.plugins.react.ReactFlipperPlugin;
21 | import com.facebook.flipper.plugins.sharedpreferences.SharedPreferencesFlipperPlugin;
22 | import com.facebook.react.ReactInstanceEventListener;
23 | import com.facebook.react.ReactInstanceManager;
24 | import com.facebook.react.bridge.ReactContext;
25 | import com.facebook.react.modules.network.NetworkingModule;
26 | import okhttp3.OkHttpClient;
27 |
28 | public class ReactNativeFlipper {
29 | public static void initializeFlipper(Context context, ReactInstanceManager reactInstanceManager) {
30 | if (FlipperUtils.shouldEnableFlipper(context)) {
31 | final FlipperClient client = AndroidFlipperClient.getInstance(context);
32 |
33 | client.addPlugin(new InspectorFlipperPlugin(context, DescriptorMapping.withDefaults()));
34 | client.addPlugin(new ReactFlipperPlugin());
35 | client.addPlugin(new DatabasesFlipperPlugin(context));
36 | client.addPlugin(new SharedPreferencesFlipperPlugin(context));
37 | client.addPlugin(CrashReporterPlugin.getInstance());
38 |
39 | NetworkFlipperPlugin networkFlipperPlugin = new NetworkFlipperPlugin();
40 | NetworkingModule.setCustomClientBuilder(
41 | new NetworkingModule.CustomClientBuilder() {
42 | @Override
43 | public void apply(OkHttpClient.Builder builder) {
44 | builder.addNetworkInterceptor(new FlipperOkhttpInterceptor(networkFlipperPlugin));
45 | }
46 | });
47 | client.addPlugin(networkFlipperPlugin);
48 | client.start();
49 |
50 | // Fresco Plugin needs to ensure that ImagePipelineFactory is initialized
51 | // Hence we run if after all native modules have been initialized
52 | ReactContext reactContext = reactInstanceManager.getCurrentReactContext();
53 | if (reactContext == null) {
54 | reactInstanceManager.addReactInstanceEventListener(
55 | new ReactInstanceEventListener() {
56 | @Override
57 | public void onReactContextInitialized(ReactContext reactContext) {
58 | reactInstanceManager.removeReactInstanceEventListener(this);
59 | reactContext.runOnNativeModulesQueueThread(
60 | new Runnable() {
61 | @Override
62 | public void run() {
63 | client.addPlugin(new FrescoFlipperPlugin());
64 | }
65 | });
66 | }
67 | });
68 | } else {
69 | client.addPlugin(new FrescoFlipperPlugin());
70 | }
71 | }
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/android/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
13 |
16 |
17 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/android/app/src/main/java/com/reactnativetypescriptexamples/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.reactnativetypescriptexamples;
2 |
3 | import com.facebook.react.ReactActivity;
4 | import com.facebook.react.ReactActivityDelegate;
5 | import com.facebook.react.ReactRootView;
6 |
7 | public class MainActivity extends ReactActivity {
8 |
9 | /**
10 | * Returns the name of the main component registered from JavaScript. This is used to schedule
11 | * rendering of the component.
12 | */
13 | @Override
14 | protected String getMainComponentName() {
15 | return "ReactNativeTypeScriptExamples";
16 | }
17 |
18 | /**
19 | * Returns the instance of the {@link ReactActivityDelegate}. There the RootView is created and
20 | * you can specify the renderer you wish to use - the new renderer (Fabric) or the old renderer
21 | * (Paper).
22 | */
23 | @Override
24 | protected ReactActivityDelegate createReactActivityDelegate() {
25 | return new MainActivityDelegate(this, getMainComponentName());
26 | }
27 |
28 | public static class MainActivityDelegate extends ReactActivityDelegate {
29 | public MainActivityDelegate(ReactActivity activity, String mainComponentName) {
30 | super(activity, mainComponentName);
31 | }
32 |
33 | @Override
34 | protected ReactRootView createRootView() {
35 | ReactRootView reactRootView = new ReactRootView(getContext());
36 | // If you opted-in for the New Architecture, we enable the Fabric Renderer.
37 | reactRootView.setIsFabric(BuildConfig.IS_NEW_ARCHITECTURE_ENABLED);
38 | return reactRootView;
39 | }
40 |
41 | @Override
42 | protected boolean isConcurrentRootEnabled() {
43 | // If you opted-in for the New Architecture, we enable Concurrent Root (i.e. React 18).
44 | // More on this on https://reactjs.org/blog/2022/03/29/react-v18.html
45 | return BuildConfig.IS_NEW_ARCHITECTURE_ENABLED;
46 | }
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/android/app/src/main/java/com/reactnativetypescriptexamples/MainApplication.java:
--------------------------------------------------------------------------------
1 | package com.reactnativetypescriptexamples;
2 |
3 | import android.app.Application;
4 | import android.content.Context;
5 | import com.facebook.react.PackageList;
6 | import com.facebook.react.ReactApplication;
7 | import com.facebook.react.ReactInstanceManager;
8 | import com.facebook.react.ReactNativeHost;
9 | import com.facebook.react.ReactPackage;
10 | import com.facebook.react.config.ReactFeatureFlags;
11 | import com.facebook.soloader.SoLoader;
12 | import com.reactnativetypescriptexamples.newarchitecture.MainApplicationReactNativeHost;
13 | import java.lang.reflect.InvocationTargetException;
14 | import java.util.List;
15 |
16 | public class MainApplication extends Application implements ReactApplication {
17 |
18 | private final ReactNativeHost mReactNativeHost =
19 | new ReactNativeHost(this) {
20 | @Override
21 | public boolean getUseDeveloperSupport() {
22 | return BuildConfig.DEBUG;
23 | }
24 |
25 | @Override
26 | protected List getPackages() {
27 | @SuppressWarnings("UnnecessaryLocalVariable")
28 | List packages = new PackageList(this).getPackages();
29 | // Packages that cannot be autolinked yet can be added manually here, for example:
30 | // packages.add(new MyReactNativePackage());
31 | return packages;
32 | }
33 |
34 | @Override
35 | protected String getJSMainModuleName() {
36 | return "index";
37 | }
38 | };
39 |
40 | private final ReactNativeHost mNewArchitectureNativeHost =
41 | new MainApplicationReactNativeHost(this);
42 |
43 | @Override
44 | public ReactNativeHost getReactNativeHost() {
45 | if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {
46 | return mNewArchitectureNativeHost;
47 | } else {
48 | return mReactNativeHost;
49 | }
50 | }
51 |
52 | @Override
53 | public void onCreate() {
54 | super.onCreate();
55 | // If you opted-in for the New Architecture, we enable the TurboModule system
56 | ReactFeatureFlags.useTurboModules = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED;
57 | SoLoader.init(this, /* native exopackage */ false);
58 | initializeFlipper(this, getReactNativeHost().getReactInstanceManager());
59 | }
60 |
61 | /**
62 | * Loads Flipper in React Native templates. Call this in the onCreate method with something like
63 | * initializeFlipper(this, getReactNativeHost().getReactInstanceManager());
64 | *
65 | * @param context
66 | * @param reactInstanceManager
67 | */
68 | private static void initializeFlipper(
69 | Context context, ReactInstanceManager reactInstanceManager) {
70 | if (BuildConfig.DEBUG) {
71 | try {
72 | /*
73 | We use reflection here to pick up the class that initializes Flipper,
74 | since Flipper library is not available in release mode
75 | */
76 | Class> aClass = Class.forName("com.reactnativetypescriptexamples.ReactNativeFlipper");
77 | aClass
78 | .getMethod("initializeFlipper", Context.class, ReactInstanceManager.class)
79 | .invoke(null, context, reactInstanceManager);
80 | } catch (ClassNotFoundException e) {
81 | e.printStackTrace();
82 | } catch (NoSuchMethodException e) {
83 | e.printStackTrace();
84 | } catch (IllegalAccessException e) {
85 | e.printStackTrace();
86 | } catch (InvocationTargetException e) {
87 | e.printStackTrace();
88 | }
89 | }
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/android/app/src/main/java/com/reactnativetypescriptexamples/newarchitecture/MainApplicationReactNativeHost.java:
--------------------------------------------------------------------------------
1 | package com.reactnativetypescriptexamples.newarchitecture;
2 |
3 | import android.app.Application;
4 | import androidx.annotation.NonNull;
5 | import com.facebook.react.PackageList;
6 | import com.facebook.react.ReactInstanceManager;
7 | import com.facebook.react.ReactNativeHost;
8 | import com.facebook.react.ReactPackage;
9 | import com.facebook.react.ReactPackageTurboModuleManagerDelegate;
10 | import com.facebook.react.bridge.JSIModulePackage;
11 | import com.facebook.react.bridge.JSIModuleProvider;
12 | import com.facebook.react.bridge.JSIModuleSpec;
13 | import com.facebook.react.bridge.JSIModuleType;
14 | import com.facebook.react.bridge.JavaScriptContextHolder;
15 | import com.facebook.react.bridge.ReactApplicationContext;
16 | import com.facebook.react.bridge.UIManager;
17 | import com.facebook.react.fabric.ComponentFactory;
18 | import com.facebook.react.fabric.CoreComponentsRegistry;
19 | import com.facebook.react.fabric.FabricJSIModuleProvider;
20 | import com.facebook.react.fabric.ReactNativeConfig;
21 | import com.facebook.react.uimanager.ViewManagerRegistry;
22 | import com.reactnativetypescriptexamples.BuildConfig;
23 | import com.reactnativetypescriptexamples.newarchitecture.components.MainComponentsRegistry;
24 | import com.reactnativetypescriptexamples.newarchitecture.modules.MainApplicationTurboModuleManagerDelegate;
25 | import java.util.ArrayList;
26 | import java.util.List;
27 |
28 | /**
29 | * A {@link ReactNativeHost} that helps you load everything needed for the New Architecture, both
30 | * TurboModule delegates and the Fabric Renderer.
31 | *
32 | * Please note that this class is used ONLY if you opt-in for the New Architecture (see the
33 | * `newArchEnabled` property). Is ignored otherwise.
34 | */
35 | public class MainApplicationReactNativeHost extends ReactNativeHost {
36 | public MainApplicationReactNativeHost(Application application) {
37 | super(application);
38 | }
39 |
40 | @Override
41 | public boolean getUseDeveloperSupport() {
42 | return BuildConfig.DEBUG;
43 | }
44 |
45 | @Override
46 | protected List getPackages() {
47 | List packages = new PackageList(this).getPackages();
48 | // Packages that cannot be autolinked yet can be added manually here, for example:
49 | // packages.add(new MyReactNativePackage());
50 | // TurboModules must also be loaded here providing a valid TurboReactPackage implementation:
51 | // packages.add(new TurboReactPackage() { ... });
52 | // If you have custom Fabric Components, their ViewManagers should also be loaded here
53 | // inside a ReactPackage.
54 | return packages;
55 | }
56 |
57 | @Override
58 | protected String getJSMainModuleName() {
59 | return "index";
60 | }
61 |
62 | @NonNull
63 | @Override
64 | protected ReactPackageTurboModuleManagerDelegate.Builder
65 | getReactPackageTurboModuleManagerDelegateBuilder() {
66 | // Here we provide the ReactPackageTurboModuleManagerDelegate Builder. This is necessary
67 | // for the new architecture and to use TurboModules correctly.
68 | return new MainApplicationTurboModuleManagerDelegate.Builder();
69 | }
70 |
71 | @Override
72 | protected JSIModulePackage getJSIModulePackage() {
73 | return new JSIModulePackage() {
74 | @Override
75 | public List getJSIModules(
76 | final ReactApplicationContext reactApplicationContext,
77 | final JavaScriptContextHolder jsContext) {
78 | final List specs = new ArrayList<>();
79 |
80 | // Here we provide a new JSIModuleSpec that will be responsible of providing the
81 | // custom Fabric Components.
82 | specs.add(
83 | new JSIModuleSpec() {
84 | @Override
85 | public JSIModuleType getJSIModuleType() {
86 | return JSIModuleType.UIManager;
87 | }
88 |
89 | @Override
90 | public JSIModuleProvider getJSIModuleProvider() {
91 | final ComponentFactory componentFactory = new ComponentFactory();
92 | CoreComponentsRegistry.register(componentFactory);
93 |
94 | // Here we register a Components Registry.
95 | // The one that is generated with the template contains no components
96 | // and just provides you the one from React Native core.
97 | MainComponentsRegistry.register(componentFactory);
98 |
99 | final ReactInstanceManager reactInstanceManager = getReactInstanceManager();
100 |
101 | ViewManagerRegistry viewManagerRegistry =
102 | new ViewManagerRegistry(
103 | reactInstanceManager.getOrCreateViewManagers(reactApplicationContext));
104 |
105 | return new FabricJSIModuleProvider(
106 | reactApplicationContext,
107 | componentFactory,
108 | ReactNativeConfig.DEFAULT_CONFIG,
109 | viewManagerRegistry);
110 | }
111 | });
112 | return specs;
113 | }
114 | };
115 | }
116 | }
117 |
--------------------------------------------------------------------------------
/android/app/src/main/java/com/reactnativetypescriptexamples/newarchitecture/components/MainComponentsRegistry.java:
--------------------------------------------------------------------------------
1 | package com.reactnativetypescriptexamples.newarchitecture.components;
2 |
3 | import com.facebook.jni.HybridData;
4 | import com.facebook.proguard.annotations.DoNotStrip;
5 | import com.facebook.react.fabric.ComponentFactory;
6 | import com.facebook.soloader.SoLoader;
7 |
8 | /**
9 | * Class responsible to load the custom Fabric Components. This class has native methods and needs a
10 | * corresponding C++ implementation/header file to work correctly (already placed inside the jni/
11 | * folder for you).
12 | *
13 | * Please note that this class is used ONLY if you opt-in for the New Architecture (see the
14 | * `newArchEnabled` property). Is ignored otherwise.
15 | */
16 | @DoNotStrip
17 | public class MainComponentsRegistry {
18 | static {
19 | SoLoader.loadLibrary("fabricjni");
20 | }
21 |
22 | @DoNotStrip private final HybridData mHybridData;
23 |
24 | @DoNotStrip
25 | private native HybridData initHybrid(ComponentFactory componentFactory);
26 |
27 | @DoNotStrip
28 | private MainComponentsRegistry(ComponentFactory componentFactory) {
29 | mHybridData = initHybrid(componentFactory);
30 | }
31 |
32 | @DoNotStrip
33 | public static MainComponentsRegistry register(ComponentFactory componentFactory) {
34 | return new MainComponentsRegistry(componentFactory);
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/android/app/src/main/java/com/reactnativetypescriptexamples/newarchitecture/modules/MainApplicationTurboModuleManagerDelegate.java:
--------------------------------------------------------------------------------
1 | package com.reactnativetypescriptexamples.newarchitecture.modules;
2 |
3 | import com.facebook.jni.HybridData;
4 | import com.facebook.react.ReactPackage;
5 | import com.facebook.react.ReactPackageTurboModuleManagerDelegate;
6 | import com.facebook.react.bridge.ReactApplicationContext;
7 | import com.facebook.soloader.SoLoader;
8 | import java.util.List;
9 |
10 | /**
11 | * Class responsible to load the TurboModules. This class has native methods and needs a
12 | * corresponding C++ implementation/header file to work correctly (already placed inside the jni/
13 | * folder for you).
14 | *
15 | *
Please note that this class is used ONLY if you opt-in for the New Architecture (see the
16 | * `newArchEnabled` property). Is ignored otherwise.
17 | */
18 | public class MainApplicationTurboModuleManagerDelegate
19 | extends ReactPackageTurboModuleManagerDelegate {
20 |
21 | private static volatile boolean sIsSoLibraryLoaded;
22 |
23 | protected MainApplicationTurboModuleManagerDelegate(
24 | ReactApplicationContext reactApplicationContext, List packages) {
25 | super(reactApplicationContext, packages);
26 | }
27 |
28 | protected native HybridData initHybrid();
29 |
30 | native boolean canCreateTurboModule(String moduleName);
31 |
32 | public static class Builder extends ReactPackageTurboModuleManagerDelegate.Builder {
33 | protected MainApplicationTurboModuleManagerDelegate build(
34 | ReactApplicationContext context, List packages) {
35 | return new MainApplicationTurboModuleManagerDelegate(context, packages);
36 | }
37 | }
38 |
39 | @Override
40 | protected synchronized void maybeLoadOtherSoLibraries() {
41 | if (!sIsSoLibraryLoaded) {
42 | // If you change the name of your application .so file in the Android.mk file,
43 | // make sure you update the name here as well.
44 | SoLoader.loadLibrary("reactnativetypescriptexamples_appmodules");
45 | sIsSoLibraryLoaded = true;
46 | }
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/android/app/src/main/jni/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.13)
2 |
3 | # Define the library name here.
4 | project(reactnativetypescriptexamples_appmodules)
5 |
6 | # This file includes all the necessary to let you build your application with the New Architecture.
7 | include(${REACT_ANDROID_DIR}/cmake-utils/ReactNative-application.cmake)
8 |
--------------------------------------------------------------------------------
/android/app/src/main/jni/MainApplicationModuleProvider.cpp:
--------------------------------------------------------------------------------
1 | #include "MainApplicationModuleProvider.h"
2 |
3 | #include
4 | #include
5 |
6 | namespace facebook {
7 | namespace react {
8 |
9 | std::shared_ptr MainApplicationModuleProvider(
10 | const std::string &moduleName,
11 | const JavaTurboModule::InitParams ¶ms) {
12 | // Here you can provide your own module provider for TurboModules coming from
13 | // either your application or from external libraries. The approach to follow
14 | // is similar to the following (for a library called `samplelibrary`:
15 | //
16 | // auto module = samplelibrary_ModuleProvider(moduleName, params);
17 | // if (module != nullptr) {
18 | // return module;
19 | // }
20 | // return rncore_ModuleProvider(moduleName, params);
21 |
22 | // Module providers autolinked by RN CLI
23 | auto rncli_module = rncli_ModuleProvider(moduleName, params);
24 | if (rncli_module != nullptr) {
25 | return rncli_module;
26 | }
27 |
28 | return rncore_ModuleProvider(moduleName, params);
29 | }
30 |
31 | } // namespace react
32 | } // namespace facebook
33 |
--------------------------------------------------------------------------------
/android/app/src/main/jni/MainApplicationModuleProvider.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 | #include
5 |
6 | #include
7 |
8 | namespace facebook {
9 | namespace react {
10 |
11 | std::shared_ptr MainApplicationModuleProvider(
12 | const std::string &moduleName,
13 | const JavaTurboModule::InitParams ¶ms);
14 |
15 | } // namespace react
16 | } // namespace facebook
17 |
--------------------------------------------------------------------------------
/android/app/src/main/jni/MainApplicationTurboModuleManagerDelegate.cpp:
--------------------------------------------------------------------------------
1 | #include "MainApplicationTurboModuleManagerDelegate.h"
2 | #include "MainApplicationModuleProvider.h"
3 |
4 | namespace facebook {
5 | namespace react {
6 |
7 | jni::local_ref
8 | MainApplicationTurboModuleManagerDelegate::initHybrid(
9 | jni::alias_ref) {
10 | return makeCxxInstance();
11 | }
12 |
13 | void MainApplicationTurboModuleManagerDelegate::registerNatives() {
14 | registerHybrid({
15 | makeNativeMethod(
16 | "initHybrid", MainApplicationTurboModuleManagerDelegate::initHybrid),
17 | makeNativeMethod(
18 | "canCreateTurboModule",
19 | MainApplicationTurboModuleManagerDelegate::canCreateTurboModule),
20 | });
21 | }
22 |
23 | std::shared_ptr
24 | MainApplicationTurboModuleManagerDelegate::getTurboModule(
25 | const std::string &name,
26 | const std::shared_ptr &jsInvoker) {
27 | // Not implemented yet: provide pure-C++ NativeModules here.
28 | return nullptr;
29 | }
30 |
31 | std::shared_ptr
32 | MainApplicationTurboModuleManagerDelegate::getTurboModule(
33 | const std::string &name,
34 | const JavaTurboModule::InitParams ¶ms) {
35 | return MainApplicationModuleProvider(name, params);
36 | }
37 |
38 | bool MainApplicationTurboModuleManagerDelegate::canCreateTurboModule(
39 | const std::string &name) {
40 | return getTurboModule(name, nullptr) != nullptr ||
41 | getTurboModule(name, {.moduleName = name}) != nullptr;
42 | }
43 |
44 | } // namespace react
45 | } // namespace facebook
46 |
--------------------------------------------------------------------------------
/android/app/src/main/jni/MainApplicationTurboModuleManagerDelegate.h:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 |
4 | #include
5 | #include
6 |
7 | namespace facebook {
8 | namespace react {
9 |
10 | class MainApplicationTurboModuleManagerDelegate
11 | : public jni::HybridClass<
12 | MainApplicationTurboModuleManagerDelegate,
13 | TurboModuleManagerDelegate> {
14 | public:
15 | // Adapt it to the package you used for your Java class.
16 | static constexpr auto kJavaDescriptor =
17 | "Lcom/reactnativetypescriptexamples/newarchitecture/modules/MainApplicationTurboModuleManagerDelegate;";
18 |
19 | static jni::local_ref initHybrid(jni::alias_ref);
20 |
21 | static void registerNatives();
22 |
23 | std::shared_ptr getTurboModule(
24 | const std::string &name,
25 | const std::shared_ptr &jsInvoker) override;
26 | std::shared_ptr getTurboModule(
27 | const std::string &name,
28 | const JavaTurboModule::InitParams ¶ms) override;
29 |
30 | /**
31 | * Test-only method. Allows user to verify whether a TurboModule can be
32 | * created by instances of this class.
33 | */
34 | bool canCreateTurboModule(const std::string &name);
35 | };
36 |
37 | } // namespace react
38 | } // namespace facebook
39 |
--------------------------------------------------------------------------------
/android/app/src/main/jni/MainComponentsRegistry.cpp:
--------------------------------------------------------------------------------
1 | #include "MainComponentsRegistry.h"
2 |
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 |
9 | namespace facebook {
10 | namespace react {
11 |
12 | MainComponentsRegistry::MainComponentsRegistry(ComponentFactory *delegate) {}
13 |
14 | std::shared_ptr
15 | MainComponentsRegistry::sharedProviderRegistry() {
16 | auto providerRegistry = CoreComponentsRegistry::sharedProviderRegistry();
17 |
18 | // Autolinked providers registered by RN CLI
19 | rncli_registerProviders(providerRegistry);
20 |
21 | // Custom Fabric Components go here. You can register custom
22 | // components coming from your App or from 3rd party libraries here.
23 | //
24 | // providerRegistry->add(concreteComponentDescriptorProvider<
25 | // AocViewerComponentDescriptor>());
26 | return providerRegistry;
27 | }
28 |
29 | jni::local_ref
30 | MainComponentsRegistry::initHybrid(
31 | jni::alias_ref,
32 | ComponentFactory *delegate) {
33 | auto instance = makeCxxInstance(delegate);
34 |
35 | auto buildRegistryFunction =
36 | [](EventDispatcher::Weak const &eventDispatcher,
37 | ContextContainer::Shared const &contextContainer)
38 | -> ComponentDescriptorRegistry::Shared {
39 | auto registry = MainComponentsRegistry::sharedProviderRegistry()
40 | ->createComponentDescriptorRegistry(
41 | {eventDispatcher, contextContainer});
42 |
43 | auto mutableRegistry =
44 | std::const_pointer_cast(registry);
45 |
46 | mutableRegistry->setFallbackComponentDescriptor(
47 | std::make_shared(
48 | ComponentDescriptorParameters{
49 | eventDispatcher, contextContainer, nullptr}));
50 |
51 | return registry;
52 | };
53 |
54 | delegate->buildRegistryFunction = buildRegistryFunction;
55 | return instance;
56 | }
57 |
58 | void MainComponentsRegistry::registerNatives() {
59 | registerHybrid({
60 | makeNativeMethod("initHybrid", MainComponentsRegistry::initHybrid),
61 | });
62 | }
63 |
64 | } // namespace react
65 | } // namespace facebook
66 |
--------------------------------------------------------------------------------
/android/app/src/main/jni/MainComponentsRegistry.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 | #include
5 | #include
6 | #include
7 |
8 | namespace facebook {
9 | namespace react {
10 |
11 | class MainComponentsRegistry
12 | : public facebook::jni::HybridClass {
13 | public:
14 | // Adapt it to the package you used for your Java class.
15 | constexpr static auto kJavaDescriptor =
16 | "Lcom/reactnativetypescriptexamples/newarchitecture/components/MainComponentsRegistry;";
17 |
18 | static void registerNatives();
19 |
20 | MainComponentsRegistry(ComponentFactory *delegate);
21 |
22 | private:
23 | static std::shared_ptr
24 | sharedProviderRegistry();
25 |
26 | static jni::local_ref initHybrid(
27 | jni::alias_ref,
28 | ComponentFactory *delegate);
29 | };
30 |
31 | } // namespace react
32 | } // namespace facebook
33 |
--------------------------------------------------------------------------------
/android/app/src/main/jni/OnLoad.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include "MainApplicationTurboModuleManagerDelegate.h"
3 | #include "MainComponentsRegistry.h"
4 |
5 | JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *) {
6 | return facebook::jni::initialize(vm, [] {
7 | facebook::react::MainApplicationTurboModuleManagerDelegate::
8 | registerNatives();
9 | facebook::react::MainComponentsRegistry::registerNatives();
10 | });
11 | }
12 |
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable/rn_edit_text_material.xml:
--------------------------------------------------------------------------------
1 |
2 |
16 |
21 |
22 |
23 |
32 |
33 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/robinhuy/react-native-typescript-examples/3a088e6b7407fde40b8161c38872fc482b5f8118/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/robinhuy/react-native-typescript-examples/3a088e6b7407fde40b8161c38872fc482b5f8118/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/robinhuy/react-native-typescript-examples/3a088e6b7407fde40b8161c38872fc482b5f8118/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/robinhuy/react-native-typescript-examples/3a088e6b7407fde40b8161c38872fc482b5f8118/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/robinhuy/react-native-typescript-examples/3a088e6b7407fde40b8161c38872fc482b5f8118/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/robinhuy/react-native-typescript-examples/3a088e6b7407fde40b8161c38872fc482b5f8118/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/robinhuy/react-native-typescript-examples/3a088e6b7407fde40b8161c38872fc482b5f8118/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/robinhuy/react-native-typescript-examples/3a088e6b7407fde40b8161c38872fc482b5f8118/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/robinhuy/react-native-typescript-examples/3a088e6b7407fde40b8161c38872fc482b5f8118/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/robinhuy/react-native-typescript-examples/3a088e6b7407fde40b8161c38872fc482b5f8118/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/android/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | ReactNativeTypeScriptExamples
3 |
4 |
--------------------------------------------------------------------------------
/android/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/android/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | ext {
5 | buildToolsVersion = "31.0.0"
6 | minSdkVersion = 21
7 | compileSdkVersion = 31
8 | targetSdkVersion = 31
9 |
10 | if (System.properties['os.arch'] == "aarch64") {
11 | // For M1 Users we need to use the NDK 24 which added support for aarch64
12 | ndkVersion = "24.0.8215888"
13 | } else {
14 | // Otherwise we default to the side-by-side NDK version from AGP.
15 | ndkVersion = "21.4.7075529"
16 | }
17 | }
18 | repositories {
19 | google()
20 | mavenCentral()
21 | }
22 | dependencies {
23 | classpath("com.android.tools.build:gradle:7.2.1")
24 | classpath("com.facebook.react:react-native-gradle-plugin")
25 | classpath("de.undercouch:gradle-download-task:5.0.1")
26 | // NOTE: Do not place your application dependencies here; they belong
27 | // in the individual module build.gradle files
28 | }
29 | }
30 |
31 | allprojects {
32 | repositories {
33 | maven {
34 | // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
35 | url("$rootDir/../node_modules/react-native/android")
36 | }
37 | maven {
38 | // Android JSC is installed from npm
39 | url("$rootDir/../node_modules/jsc-android/dist")
40 | }
41 | mavenCentral {
42 | // We don't want to fetch react-native from Maven Central as there are
43 | // older versions over there.
44 | content {
45 | excludeGroup "com.facebook.react"
46 | }
47 | }
48 | google()
49 | maven { url 'https://www.jitpack.io' }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/android/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | # Default value: -Xmx512m -XX:MaxMetaspaceSize=256m
13 | org.gradle.jvmargs=-Xmx2048m -XX:MaxMetaspaceSize=512m
14 |
15 | # When configured, Gradle will run in incubating parallel mode.
16 | # This option should only be used with decoupled projects. More details, visit
17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
18 | # org.gradle.parallel=true
19 |
20 | # AndroidX package structure to make it clearer which packages are bundled with the
21 | # Android operating system, and which are packaged with your app's APK
22 | # https://developer.android.com/topic/libraries/support-library/androidx-rn
23 | android.useAndroidX=true
24 | # Automatically convert third-party libraries to use AndroidX
25 | android.enableJetifier=true
26 |
27 | # Version of flipper SDK to use with React Native
28 | FLIPPER_VERSION=0.125.0
29 |
30 | # Use this property to specify which architecture you want to build.
31 | # You can also override it from the CLI using
32 | # ./gradlew -PreactNativeArchitectures=x86_64
33 | reactNativeArchitectures=armeabi-v7a,arm64-v8a,x86,x86_64
34 |
35 | # Use this property to enable support to the new architecture.
36 | # This will allow you to use TurboModules and the Fabric render in
37 | # your application. You should enable this flag either if you want
38 | # to write custom TurboModules/Fabric components OR use libraries that
39 | # are providing them.
40 | newArchEnabled=false
41 |
--------------------------------------------------------------------------------
/android/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/robinhuy/react-native-typescript-examples/3a088e6b7407fde40b8161c38872fc482b5f8118/android/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/android/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-all.zip
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 |
--------------------------------------------------------------------------------
/android/gradlew:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | #
4 | # Copyright © 2015-2021 the original authors.
5 | #
6 | # Licensed under the Apache License, Version 2.0 (the "License");
7 | # you may not use this file except in compliance with the License.
8 | # You may obtain a copy of the License at
9 | #
10 | # https://www.apache.org/licenses/LICENSE-2.0
11 | #
12 | # Unless required by applicable law or agreed to in writing, software
13 | # distributed under the License is distributed on an "AS IS" BASIS,
14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | # See the License for the specific language governing permissions and
16 | # limitations under the License.
17 | #
18 |
19 | ##############################################################################
20 | #
21 | # Gradle start up script for POSIX generated by Gradle.
22 | #
23 | # Important for running:
24 | #
25 | # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
26 | # noncompliant, but you have some other compliant shell such as ksh or
27 | # bash, then to run this script, type that shell name before the whole
28 | # command line, like:
29 | #
30 | # ksh Gradle
31 | #
32 | # Busybox and similar reduced shells will NOT work, because this script
33 | # requires all of these POSIX shell features:
34 | # * functions;
35 | # * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
36 | # «${var#prefix}», «${var%suffix}», and «$( cmd )»;
37 | # * compound commands having a testable exit status, especially «case»;
38 | # * various built-in commands including «command», «set», and «ulimit».
39 | #
40 | # Important for patching:
41 | #
42 | # (2) This script targets any POSIX shell, so it avoids extensions provided
43 | # by Bash, Ksh, etc; in particular arrays are avoided.
44 | #
45 | # The "traditional" practice of packing multiple parameters into a
46 | # space-separated string is a well documented source of bugs and security
47 | # problems, so this is (mostly) avoided, by progressively accumulating
48 | # options in "$@", and eventually passing that to Java.
49 | #
50 | # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
51 | # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
52 | # see the in-line comments for details.
53 | #
54 | # There are tweaks for specific operating systems such as AIX, CygWin,
55 | # Darwin, MinGW, and NonStop.
56 | #
57 | # (3) This script is generated from the Groovy template
58 | # https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
59 | # within the Gradle project.
60 | #
61 | # You can find Gradle at https://github.com/gradle/gradle/.
62 | #
63 | ##############################################################################
64 |
65 | # Attempt to set APP_HOME
66 |
67 | # Resolve links: $0 may be a link
68 | app_path=$0
69 |
70 | # Need this for daisy-chained symlinks.
71 | while
72 | APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
73 | [ -h "$app_path" ]
74 | do
75 | ls=$( ls -ld "$app_path" )
76 | link=${ls#*' -> '}
77 | case $link in #(
78 | /*) app_path=$link ;; #(
79 | *) app_path=$APP_HOME$link ;;
80 | esac
81 | done
82 |
83 | APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
84 |
85 | APP_NAME="Gradle"
86 | APP_BASE_NAME=${0##*/}
87 |
88 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
89 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
90 |
91 | # Use the maximum available, or set MAX_FD != -1 to use that value.
92 | MAX_FD=maximum
93 |
94 | warn () {
95 | echo "$*"
96 | } >&2
97 |
98 | die () {
99 | echo
100 | echo "$*"
101 | echo
102 | exit 1
103 | } >&2
104 |
105 | # OS specific support (must be 'true' or 'false').
106 | cygwin=false
107 | msys=false
108 | darwin=false
109 | nonstop=false
110 | case "$( uname )" in #(
111 | CYGWIN* ) cygwin=true ;; #(
112 | Darwin* ) darwin=true ;; #(
113 | MSYS* | MINGW* ) msys=true ;; #(
114 | NONSTOP* ) nonstop=true ;;
115 | esac
116 |
117 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
118 |
119 |
120 | # Determine the Java command to use to start the JVM.
121 | if [ -n "$JAVA_HOME" ] ; then
122 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
123 | # IBM's JDK on AIX uses strange locations for the executables
124 | JAVACMD=$JAVA_HOME/jre/sh/java
125 | else
126 | JAVACMD=$JAVA_HOME/bin/java
127 | fi
128 | if [ ! -x "$JAVACMD" ] ; then
129 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
130 |
131 | Please set the JAVA_HOME variable in your environment to match the
132 | location of your Java installation."
133 | fi
134 | else
135 | JAVACMD=java
136 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
137 |
138 | Please set the JAVA_HOME variable in your environment to match the
139 | location of your Java installation."
140 | fi
141 |
142 | # Increase the maximum file descriptors if we can.
143 | if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
144 | case $MAX_FD in #(
145 | max*)
146 | MAX_FD=$( ulimit -H -n ) ||
147 | warn "Could not query maximum file descriptor limit"
148 | esac
149 | case $MAX_FD in #(
150 | '' | soft) :;; #(
151 | *)
152 | ulimit -n "$MAX_FD" ||
153 | warn "Could not set maximum file descriptor limit to $MAX_FD"
154 | esac
155 | fi
156 |
157 | # Collect all arguments for the java command, stacking in reverse order:
158 | # * args from the command line
159 | # * the main class name
160 | # * -classpath
161 | # * -D...appname settings
162 | # * --module-path (only if needed)
163 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
164 |
165 | # For Cygwin or MSYS, switch paths to Windows format before running java
166 | if "$cygwin" || "$msys" ; then
167 | APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
168 | CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
169 |
170 | JAVACMD=$( cygpath --unix "$JAVACMD" )
171 |
172 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
173 | for arg do
174 | if
175 | case $arg in #(
176 | -*) false ;; # don't mess with options #(
177 | /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
178 | [ -e "$t" ] ;; #(
179 | *) false ;;
180 | esac
181 | then
182 | arg=$( cygpath --path --ignore --mixed "$arg" )
183 | fi
184 | # Roll the args list around exactly as many times as the number of
185 | # args, so each arg winds up back in the position where it started, but
186 | # possibly modified.
187 | #
188 | # NB: a `for` loop captures its iteration list before it begins, so
189 | # changing the positional parameters here affects neither the number of
190 | # iterations, nor the values presented in `arg`.
191 | shift # remove old arg
192 | set -- "$@" "$arg" # push replacement arg
193 | done
194 | fi
195 |
196 | # Collect all arguments for the java command;
197 | # * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
198 | # shell script including quotes and variable substitutions, so put them in
199 | # double quotes to make sure that they get re-expanded; and
200 | # * put everything else in single quotes, so that it's not re-expanded.
201 |
202 | set -- \
203 | "-Dorg.gradle.appname=$APP_BASE_NAME" \
204 | -classpath "$CLASSPATH" \
205 | org.gradle.wrapper.GradleWrapperMain \
206 | "$@"
207 |
208 | # Use "xargs" to parse quoted args.
209 | #
210 | # With -n1 it outputs one arg per line, with the quotes and backslashes removed.
211 | #
212 | # In Bash we could simply go:
213 | #
214 | # readarray ARGS < <( xargs -n1 <<<"$var" ) &&
215 | # set -- "${ARGS[@]}" "$@"
216 | #
217 | # but POSIX shell has neither arrays nor command substitution, so instead we
218 | # post-process each arg (as a line of input to sed) to backslash-escape any
219 | # character that might be a shell metacharacter, then use eval to reverse
220 | # that process (while maintaining the separation between arguments), and wrap
221 | # the whole thing up as a single "set" statement.
222 | #
223 | # This will of course break if any of these variables contains a newline or
224 | # an unmatched quote.
225 | #
226 |
227 | eval "set -- $(
228 | printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
229 | xargs -n1 |
230 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
231 | tr '\n' ' '
232 | )" '"$@"'
233 |
234 | exec "$JAVACMD" "$@"
235 |
--------------------------------------------------------------------------------
/android/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%" == "" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%" == "" set DIRNAME=.
29 | set APP_BASE_NAME=%~n0
30 | set APP_HOME=%DIRNAME%
31 |
32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
34 |
35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
37 |
38 | @rem Find java.exe
39 | if defined JAVA_HOME goto findJavaFromJavaHome
40 |
41 | set JAVA_EXE=java.exe
42 | %JAVA_EXE% -version >NUL 2>&1
43 | if "%ERRORLEVEL%" == "0" goto execute
44 |
45 | echo.
46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
47 | echo.
48 | echo Please set the JAVA_HOME variable in your environment to match the
49 | echo location of your Java installation.
50 |
51 | goto fail
52 |
53 | :findJavaFromJavaHome
54 | set JAVA_HOME=%JAVA_HOME:"=%
55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
56 |
57 | if exist "%JAVA_EXE%" goto execute
58 |
59 | echo.
60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
61 | echo.
62 | echo Please set the JAVA_HOME variable in your environment to match the
63 | echo location of your Java installation.
64 |
65 | goto fail
66 |
67 | :execute
68 | @rem Setup the command line
69 |
70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
71 |
72 |
73 | @rem Execute Gradle
74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
75 |
76 | :end
77 | @rem End local scope for the variables with windows NT shell
78 | if "%ERRORLEVEL%"=="0" goto mainEnd
79 |
80 | :fail
81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
82 | rem the _cmd.exe /c_ return code!
83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
84 | exit /b 1
85 |
86 | :mainEnd
87 | if "%OS%"=="Windows_NT" endlocal
88 |
89 | :omega
90 |
--------------------------------------------------------------------------------
/android/settings.gradle:
--------------------------------------------------------------------------------
1 | rootProject.name = 'ReactNativeTypeScriptExamples'
2 | apply from: file("../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesSettingsGradle(settings)
3 | include ':app'
4 | includeBuild('../node_modules/react-native-gradle-plugin')
5 |
6 | if (settings.hasProperty("newArchEnabled") && settings.newArchEnabled == "true") {
7 | include(":ReactAndroid")
8 | project(":ReactAndroid").projectDir = file('../node_modules/react-native/ReactAndroid')
9 | include(":ReactAndroid:hermes-engine")
10 | project(":ReactAndroid:hermes-engine").projectDir = file('../node_modules/react-native/ReactAndroid/hermes-engine')
11 | }
12 |
--------------------------------------------------------------------------------
/app.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ReactNativeTypeScriptExamples",
3 | "displayName": "React Native TypeScript Examples"
4 | }
5 |
--------------------------------------------------------------------------------
/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: ['module:metro-react-native-babel-preset'],
3 | plugins: ['react-native-reanimated/plugin'],
4 | };
5 |
--------------------------------------------------------------------------------
/examples/1-quiz-game/App.tsx:
--------------------------------------------------------------------------------
1 | import React, {FC, useState} from 'react';
2 | import {SafeAreaView, StatusBar} from 'react-native';
3 |
4 | import StartScreen from './screens/StartScreen';
5 | import GameScreen from './screens/GameScreen';
6 |
7 | const App: FC = () => {
8 | const [isPlaying, setPlaying] = useState(false);
9 |
10 | function startGame() {
11 | setPlaying(true);
12 | }
13 |
14 | return (
15 | <>
16 |
17 |
18 |
19 | {!isPlaying ? : }
20 |
21 | >
22 | );
23 | };
24 |
25 | export default App;
26 |
--------------------------------------------------------------------------------
/examples/1-quiz-game/mockdata.json:
--------------------------------------------------------------------------------
1 | {
2 | "questions": [
3 | {
4 | "content": "Có bao nhiêu chữ C trong câu sau đây: \"Cơm, canh, cháo, gì tớ cũng thích ăn!\"",
5 | "answers": [
6 | {"key": "A", "content": "1 chữ"},
7 | {"key": "B", "content": "2 chữ"},
8 | {"key": "C", "content": "3 chữ"},
9 | {"key": "D", "content": "4 chữ"}
10 | ],
11 | "correctAnswer": "A"
12 | },
13 | {
14 | "content": "Trong một bài kiểm tra có các câu hỏi bằng điểm nhau. Bạn trả lời sai 10 câu và tổng điểm chỉ đạt 60%. Vậy bài kiểm tra đó có tất cả bao nhiêu câu hỏi?",
15 | "answers": [
16 | {"key": "A", "content": "20"},
17 | {"key": "B", "content": "25"},
18 | {"key": "C", "content": "30"},
19 | {"key": "D", "content": "35"}
20 | ],
21 | "correctAnswer": "B"
22 | },
23 | {
24 | "content": "Nếu 8 năm trước Cường 32 tuổi thì anh ta bao nhiêu tuổi cách đây x năm?",
25 | "answers": [
26 | {"key": "A", "content": "x - 24"},
27 | {"key": "B", "content": "x - 40"},
28 | {"key": "C", "content": "24 - x"},
29 | {"key": "D", "content": "40 - x"}
30 | ],
31 | "correctAnswer": "D"
32 | }
33 | ]
34 | }
35 |
--------------------------------------------------------------------------------
/examples/1-quiz-game/screens/GameScreen.tsx:
--------------------------------------------------------------------------------
1 | import React, {FC, useState, useEffect, useCallback} from 'react';
2 | import {StyleSheet, View} from 'react-native';
3 |
4 | import Header from './game-screen-components/Header';
5 | import QuestionBox from './game-screen-components/QuestionBox';
6 | import AnswerBox from './game-screen-components/AnswerBox';
7 | import ResultModal from './game-screen-components/ResultModal';
8 |
9 | import {questions} from '../mockdata.json';
10 |
11 | const ANSWER_TIME = 10;
12 |
13 | const GameScreen: FC = () => {
14 | const [currentQuestion, setCurrentQuestion] = useState(0);
15 | const [score, setScore] = useState(0);
16 | const [remainingTime, setRemainingTime] = useState(ANSWER_TIME);
17 | const [isShowResult, setShowResult] = useState(false);
18 |
19 | const question = questions[currentQuestion];
20 |
21 | const checkAnswer = useCallback(
22 | (userAnswer: string) => {
23 | if (question.correctAnswer === userAnswer) {
24 | setScore(score + 1);
25 | }
26 |
27 | if (currentQuestion === questions.length - 1) {
28 | setShowResult(true);
29 | setRemainingTime(0);
30 | } else {
31 | setCurrentQuestion(currentQuestion + 1);
32 | setRemainingTime(ANSWER_TIME);
33 | }
34 | },
35 | [currentQuestion, question, score],
36 | );
37 |
38 | const restartGame = () => {
39 | setCurrentQuestion(0);
40 | setScore(0);
41 | setShowResult(false);
42 | setRemainingTime(ANSWER_TIME);
43 | };
44 |
45 | const answerTimeProgress = (remainingTime / ANSWER_TIME) * 100;
46 |
47 | useEffect(() => {
48 | if (remainingTime > 0 && !isShowResult) {
49 | const timeOut = setTimeout(() => {
50 | setRemainingTime(remainingTime - 1);
51 | }, 1000);
52 |
53 | return () => {
54 | clearTimeout(timeOut);
55 | };
56 | } else {
57 | checkAnswer('');
58 | }
59 | }, [remainingTime, isShowResult, checkAnswer]);
60 |
61 | return (
62 |
63 |
64 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
85 |
86 | );
87 | };
88 |
89 | const styles = StyleSheet.create({
90 | wrapper: {
91 | height: '100%',
92 | backgroundColor: '#471a45',
93 | },
94 | header: {
95 | height: 40,
96 | paddingHorizontal: 8,
97 | backgroundColor: '#262626',
98 | borderBottomWidth: 2,
99 | borderColor: '#000000',
100 | justifyContent: 'center',
101 | alignItems: 'center',
102 | },
103 | questionBox: {
104 | flex: 1,
105 | justifyContent: 'center',
106 | alignItems: 'center',
107 | padding: 5,
108 | paddingBottom: 0,
109 | },
110 | answerBox: {
111 | height: 230,
112 | padding: 5,
113 | paddingTop: 0,
114 | },
115 | });
116 |
117 | export default GameScreen;
118 |
--------------------------------------------------------------------------------
/examples/1-quiz-game/screens/StartScreen.tsx:
--------------------------------------------------------------------------------
1 | import React, {FC} from 'react';
2 | import {StyleSheet, View, Text, TouchableHighlight} from 'react-native';
3 |
4 | interface StartScreenProps {
5 | startGame: () => void;
6 | }
7 |
8 | const StartScreen: FC = ({startGame}) => {
9 | return (
10 |
11 |
12 | Funny Quiz
13 |
14 |
15 |
16 |
17 | Start
18 |
19 |
20 |
21 | );
22 | };
23 |
24 | const styles = StyleSheet.create({
25 | body: {
26 | height: '100%',
27 | justifyContent: 'center',
28 | alignItems: 'center',
29 | backgroundColor: '#141414',
30 | },
31 | heading: {
32 | marginBottom: 30,
33 | },
34 | title: {
35 | textAlign: 'center',
36 | fontSize: 40,
37 | fontWeight: 'bold',
38 | color: '#ffffff',
39 | },
40 | startButton: {
41 | backgroundColor: '#8854c0',
42 | borderRadius: 8,
43 | minWidth: 150,
44 | paddingVertical: 8,
45 | paddingHorizontal: 16,
46 | },
47 | buttonText: {
48 | textAlign: 'center',
49 | fontSize: 20,
50 | fontWeight: 'bold',
51 | color: '#ffffff',
52 | },
53 | });
54 |
55 | export default StartScreen;
56 |
--------------------------------------------------------------------------------
/examples/1-quiz-game/screens/game-screen-components/AnswerBox.tsx:
--------------------------------------------------------------------------------
1 | import React, {FC} from 'react';
2 | import {StyleSheet, View, Text, TouchableHighlight} from 'react-native';
3 |
4 | const BUTTON_BG_COLOR = ['#2c70ad', '#3d9ea6', '#eea928', '#d4546c'];
5 |
6 | interface Answer {
7 | key: string;
8 | content: string;
9 | }
10 |
11 | interface AnswerBoxProps {
12 | answers: Answer[];
13 | checkAnswer: (userAnswer: string) => void;
14 | }
15 |
16 | const AnswerBox: FC = ({answers, checkAnswer}) => {
17 | let answerContent = [];
18 |
19 | for (let i = 0; i < answers.length; i++) {
20 | const key = answers[i].key;
21 |
22 | answerContent.push(
23 | checkAnswer(key)}
26 | style={styles.answerButtonWrapper}>
27 |
29 | {answers[i].content}
30 |
31 | ,
32 | );
33 | }
34 |
35 | return {answerContent} ;
36 | };
37 |
38 | const styles = StyleSheet.create({
39 | answerButtonWrapper: {
40 | height: 50,
41 | marginTop: 5,
42 | },
43 | answerButton: {
44 | height: '100%',
45 | justifyContent: 'center',
46 | borderColor: '#fff',
47 | },
48 | answerText: {
49 | fontSize: 20,
50 | color: '#fff',
51 | textAlign: 'center',
52 | },
53 | });
54 |
55 | export default AnswerBox;
56 |
--------------------------------------------------------------------------------
/examples/1-quiz-game/screens/game-screen-components/Header.tsx:
--------------------------------------------------------------------------------
1 | import React, {FC} from 'react';
2 | import {StyleSheet, View, Text} from 'react-native';
3 |
4 | import ProgressBar from './ProgressBar';
5 |
6 | interface HeaderProps {
7 | currentQuestion: number;
8 | totalQuestions: number;
9 | progress: number;
10 | }
11 |
12 | const Header: FC = ({
13 | currentQuestion,
14 | totalQuestions,
15 | progress,
16 | }) => {
17 | return (
18 |
19 |
20 |
21 | {currentQuestion}/{totalQuestions}
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 | );
30 | };
31 |
32 | const styles = StyleSheet.create({
33 | header: {
34 | flexDirection: 'row',
35 | justifyContent: 'center',
36 | alignItems: 'center',
37 | },
38 | questionStatus: {
39 | width: 40,
40 | marginRight: 10,
41 | },
42 | questionStatusText: {
43 | color: '#ffffff',
44 | },
45 | });
46 |
47 | export default Header;
48 |
--------------------------------------------------------------------------------
/examples/1-quiz-game/screens/game-screen-components/ProgressBar.tsx:
--------------------------------------------------------------------------------
1 | import React, {FC} from 'react';
2 | import {StyleSheet, View} from 'react-native';
3 |
4 | interface ProgressBarProps {
5 | progress: number;
6 | }
7 |
8 | const ProgressBar: FC = ({progress}) => {
9 | return (
10 |
11 |
12 |
13 | );
14 | };
15 |
16 | const styles = StyleSheet.create({
17 | progressBarWrapper: {
18 | width: '100%',
19 | height: 10,
20 | borderRadius: 8,
21 | backgroundColor: '#ffffff',
22 | overflow: 'hidden',
23 | },
24 | progressBar: {
25 | height: 16,
26 | backgroundColor: '#00c985',
27 | width: 80,
28 | },
29 | });
30 |
31 | export default ProgressBar;
32 |
--------------------------------------------------------------------------------
/examples/1-quiz-game/screens/game-screen-components/QuestionBox.tsx:
--------------------------------------------------------------------------------
1 | import React, {FC} from 'react';
2 | import {StyleSheet, View, Text} from 'react-native';
3 |
4 | interface QuestionBoxProps {
5 | questionContent: string;
6 | }
7 |
8 | const QuestionBox: FC = ({questionContent}) => {
9 | return (
10 |
11 | {questionContent}
12 |
13 | );
14 | };
15 |
16 | const styles = StyleSheet.create({
17 | questionContent: {
18 | flex: 1,
19 | justifyContent: 'center',
20 | alignItems: 'center',
21 | backgroundColor: '#1f0c1e',
22 | padding: 5,
23 | },
24 | questionText: {
25 | fontSize: 24,
26 | lineHeight: 38,
27 | color: '#ffffff',
28 | textAlign: 'center',
29 | },
30 | });
31 |
32 | export default QuestionBox;
33 |
--------------------------------------------------------------------------------
/examples/1-quiz-game/screens/game-screen-components/ResultModal.tsx:
--------------------------------------------------------------------------------
1 | import React, {FC} from 'react';
2 | import {StyleSheet, View, Text, TouchableHighlight, Modal} from 'react-native';
3 |
4 | interface ResultModalProps {
5 | isVisible: boolean;
6 | restartGame: () => void;
7 | score: number;
8 | numberQuestions: number;
9 | }
10 |
11 | const ResultModal: FC = ({
12 | isVisible,
13 | restartGame,
14 | score,
15 | numberQuestions,
16 | }) => {
17 | return (
18 |
19 |
20 |
21 |
22 | Bạn trả lời đúng {score}/{numberQuestions} câu{' '}
23 |
24 |
25 | restartGame()}>
28 | Play Again
29 |
30 |
31 |
32 |
33 | );
34 | };
35 |
36 | const styles = StyleSheet.create({
37 | dialog: {
38 | height: '100%',
39 | padding: 15,
40 | backgroundColor: '#000000',
41 | justifyContent: 'center',
42 | },
43 | dialogText: {
44 | fontSize: 24,
45 | color: '#ffffff',
46 | textAlign: 'center',
47 | marginBottom: 20,
48 | },
49 | button: {
50 | justifyContent: 'center',
51 | margin: 5,
52 | padding: 10,
53 | },
54 | buttonPrimary: {
55 | backgroundColor: '#8854c0',
56 | },
57 | buttonText: {
58 | fontSize: 24,
59 | textAlign: 'center',
60 | color: '#ffffff',
61 | },
62 | });
63 |
64 | export default ResultModal;
65 |
--------------------------------------------------------------------------------
/examples/2-booking-car/App.tsx:
--------------------------------------------------------------------------------
1 | import React, {FC} from 'react';
2 | import {NativeBaseProvider} from 'native-base';
3 | import Main from './Main';
4 |
5 | const App: FC = () => {
6 | return (
7 | // https://docs.nativebase.io/install-rn
8 |
9 |
10 |
11 | );
12 | };
13 |
14 | export default App;
15 |
--------------------------------------------------------------------------------
/examples/2-booking-car/ChooseLocation.tsx:
--------------------------------------------------------------------------------
1 | import {Box, Button, HStack, Icon, Input, Stack, Text, View, VStack} from 'native-base';
2 | import React, {Dispatch, FC, SetStateAction, useState} from 'react';
3 | import {Keyboard, StyleSheet, TouchableOpacity} from 'react-native';
4 | import MapView, {LatLng} from 'react-native-maps';
5 | import FontAwesome5 from 'react-native-vector-icons/dist/FontAwesome5';
6 | import {geoCoding, GeoCodingResponse} from './googleAPI';
7 |
8 | interface ChooseLocationProps {
9 | startLocation: string;
10 | endLocation: string;
11 | mapView: MapView | null;
12 | setStartLocation: Dispatch>;
13 | setEndLocation: Dispatch>;
14 | setStartCoordinate: Dispatch>;
15 | setEndCoordinate: Dispatch>;
16 | confirmBooking: () => void;
17 | }
18 |
19 | const ChooseLocation: FC = ({
20 | startLocation,
21 | endLocation,
22 | mapView,
23 | setStartLocation,
24 | setEndLocation,
25 | setStartCoordinate,
26 | setEndCoordinate,
27 | confirmBooking,
28 | }) => {
29 | const [currentInput, setCurrentInput] = useState(2);
30 | const [suggestions, setSuggestions] = useState([]);
31 |
32 | const suggestionItems = suggestions.map((item: GeoCodingResponse) => (
33 | setInputValue(item)}>
34 |
35 |
36 | {item.formatted_address}
37 |
38 |
39 | ));
40 |
41 | const suggestLocation = async (value: string, input: number) => {
42 | if (value.length > 5) {
43 | const data = await geoCoding(encodeURIComponent(value));
44 | setSuggestions(data);
45 | setCurrentInput(input);
46 | }
47 |
48 | if (input === 1) {
49 | setStartLocation(value);
50 | } else {
51 | setEndLocation(value);
52 | }
53 | };
54 |
55 | const setInputValue = (item: GeoCodingResponse) => {
56 | const latitude = item.geometry.location.lat;
57 | const longitude = item.geometry.location.lng;
58 |
59 | if (currentInput === 1) {
60 | setStartLocation(item.formatted_address);
61 | setStartCoordinate({latitude, longitude});
62 | } else {
63 | setEndLocation(item.formatted_address);
64 | setEndCoordinate({latitude, longitude});
65 | }
66 |
67 | setSuggestions([]);
68 | Keyboard.dismiss();
69 |
70 | // Move camera to selected region
71 | const target = {
72 | latitude,
73 | longitude,
74 | latitudeDelta: 0.01,
75 | longitudeDelta: 0.01,
76 | };
77 | mapView?.animateToRegion(target, 300);
78 | };
79 |
80 | const confirm = () => {
81 | setSuggestions([]);
82 | Keyboard.dismiss();
83 | confirmBooking();
84 | };
85 |
86 | return (
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
101 |
102 |
103 |
104 |
105 |
106 | suggestLocation(value, 1)}
113 | />
114 |
115 | suggestLocation(value, 2)}
121 | />
122 |
123 |
124 |
125 |
126 | {suggestions.length > 0 && }
127 |
128 | {suggestions.length > 0 && {suggestionItems} }
129 |
130 |
131 |
135 | Confirm
136 |
137 |
138 |
139 |
140 | );
141 | };
142 |
143 | const styles = StyleSheet.create({
144 | ellipsisIcon: {
145 | marginLeft: 7,
146 | marginTop: 7,
147 | marginBottom: 7,
148 | },
149 | suggestLocationText: {
150 | fontSize: 14,
151 | lineHeight: 30,
152 | color: '#333',
153 | },
154 | input: {
155 | fontSize: 14,
156 | },
157 | divider: {
158 | borderWidth: 3,
159 | borderColor: '#ddd',
160 | },
161 | bookingButton: {
162 | marginBottom: 5,
163 | width: '100%',
164 | },
165 | });
166 |
167 | export default ChooseLocation;
168 |
--------------------------------------------------------------------------------
/examples/2-booking-car/Main.tsx:
--------------------------------------------------------------------------------
1 | import React, {FC, useEffect, useRef, useState, useCallback} from 'react';
2 | import {StyleSheet, View, Animated, Keyboard, KeyboardEvent, Dimensions} from 'react-native';
3 | import {Box, Icon} from 'native-base';
4 | import MapView, {PROVIDER_GOOGLE, Marker, Circle, Region, LatLng} from 'react-native-maps';
5 | import MapViewDirections from 'react-native-maps-directions';
6 | import ChooseLocation from './ChooseLocation';
7 | import {reverseGeoCoding} from './googleAPI';
8 | import {GOOGLE_MAPS_APIKEY, initialRegion, initialCoordinate, initialLocation} from './const';
9 | import FontAwesome5 from 'react-native-vector-icons/dist/FontAwesome5';
10 |
11 | const Main: FC = () => {
12 | const [startLocation, setStartLocation] = useState(initialLocation);
13 | const [endLocation, setEndLocation] = useState('');
14 | const [startCoordinate, setStartCoordinate] = useState(initialCoordinate);
15 | const [endCoordinate, setEndCoordinate] = useState(initialCoordinate);
16 | const [destination, setDestination] = useState(initialCoordinate);
17 | const [isBooked, setBooked] = useState(false);
18 | const slideAnimation = useRef(new Animated.Value(0)).current;
19 | const mapViewRef = useRef(null);
20 |
21 | const chooseDestination = async (currentLocation: Region) => {
22 | const {latitude, longitude} = currentLocation;
23 |
24 | if (
25 | Math.round(latitude * 100) === Math.round(startCoordinate.latitude * 100) &&
26 | Math.round(longitude * 100) === Math.round(startCoordinate.longitude * 100)
27 | ) {
28 | return;
29 | }
30 |
31 | const coordinate = {latitude, longitude};
32 | setEndCoordinate(coordinate);
33 |
34 | const location = await reverseGeoCoding(latitude, longitude);
35 | setEndLocation(location.results[0].formatted_address);
36 | };
37 |
38 | const confirmBooking = () => {
39 | setBooked(true);
40 | setDestination(endCoordinate);
41 | Keyboard.dismiss();
42 | };
43 |
44 | const keyboardWillShow = useCallback(
45 | (event: KeyboardEvent) => {
46 | Animated.timing(slideAnimation, {
47 | useNativeDriver: true,
48 | toValue: -event.endCoordinates.height,
49 | duration: 100,
50 | }).start();
51 | },
52 | [slideAnimation],
53 | );
54 |
55 | const keyboardWillHide = useCallback(() => {
56 | Animated.timing(slideAnimation, {
57 | useNativeDriver: true,
58 | toValue: 0,
59 | duration: 100,
60 | }).start();
61 | }, [slideAnimation]);
62 |
63 | useEffect(() => {
64 | // https://reactnative.dev/docs/keyboard
65 | const showSubscription = Keyboard.addListener('keyboardWillShow', keyboardWillShow);
66 | const hideSubscription = Keyboard.addListener('keyboardWillHide', keyboardWillHide);
67 |
68 | return () => {
69 | showSubscription.remove();
70 | hideSubscription.remove();
71 | };
72 | }, [keyboardWillHide, keyboardWillShow]);
73 |
74 | return (
75 | // https://docs.nativebase.io/Components.html#anatomy-headref
76 |
77 | {/* https://github.com/react-native-maps/react-native-maps */}
78 |
86 |
92 |
93 |
94 |
95 |
96 | {isBooked && (
97 | <>
98 | {/* https://github.com/bramus/react-native-maps-directions */}
99 |
106 |
107 |
108 |
109 |
110 | >
111 | )}
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
129 |
130 |
131 | );
132 | };
133 |
134 | const styles = StyleSheet.create({
135 | map: {
136 | ...StyleSheet.absoluteFillObject,
137 | width: Dimensions.get('window').width,
138 | height: Dimensions.get('window').height,
139 | },
140 | mapPinWrapper: {
141 | ...StyleSheet.absoluteFillObject,
142 | justifyContent: 'center',
143 | alignItems: 'center',
144 | },
145 | mapPin: {
146 | color: '#44b9e9',
147 | shadowColor: '#000',
148 | shadowOffset: {
149 | width: 0,
150 | height: 8,
151 | },
152 | shadowOpacity: 0.44,
153 | shadowRadius: 10.32,
154 | elevation: 16,
155 | },
156 | chooseLocation: {
157 | position: 'absolute',
158 | left: 15,
159 | right: 15,
160 | bottom: 30,
161 | },
162 | });
163 |
164 | export default Main;
165 |
--------------------------------------------------------------------------------
/examples/2-booking-car/const.ts:
--------------------------------------------------------------------------------
1 | import {LatLng, Region} from 'react-native-maps';
2 |
3 | // https://developers.google.com/maps/documentation/geocoding/get-api-key
4 | export const GOOGLE_MAPS_APIKEY = 'Your API KEY';
5 |
6 | export const initialCoordinate: LatLng = {
7 | latitude: 20.9980766,
8 | longitude: 105.7922312,
9 | };
10 |
11 | export const initialRegion: Region = {
12 | latitude: initialCoordinate.latitude,
13 | longitude: initialCoordinate.longitude,
14 | latitudeDelta: 0.01,
15 | longitudeDelta: 0.01,
16 | };
17 |
18 | export const initialLocation: string = 'Hà Nội, Vietnam';
19 |
--------------------------------------------------------------------------------
/examples/2-booking-car/googleAPI.ts:
--------------------------------------------------------------------------------
1 | import {GOOGLE_MAPS_APIKEY} from './const';
2 |
3 | // https://cloud.google.com/maps-platform/maps
4 | const BASE_URL = 'https://maps.googleapis.com/maps/api/geocode/json?';
5 |
6 | export interface GeoCodingResponse {
7 | formatted_address: string;
8 | geometry: {
9 | location: {
10 | lat: number;
11 | lng: number;
12 | };
13 | };
14 | }
15 |
16 | export async function geoCoding(address: string) {
17 | const response = await fetch(
18 | `${BASE_URL}address=${address}&components=country:VN&key=${GOOGLE_MAPS_APIKEY}`,
19 | );
20 | const data = await response.json();
21 | return data.results;
22 | }
23 |
24 | export async function reverseGeoCoding(latitude: number, longtitue: number) {
25 | const response = await fetch(
26 | `${BASE_URL}latlng=${latitude},${longtitue}&language=vi&key=${GOOGLE_MAPS_APIKEY}`,
27 | );
28 | const data = await response.json();
29 | return data;
30 | }
31 |
--------------------------------------------------------------------------------
/examples/3-gmail-clone/app/App.tsx:
--------------------------------------------------------------------------------
1 | import React, {FC} from 'react';
2 | import Store, {StoreContext} from './models/Store';
3 | import {NativeBaseProvider} from 'native-base';
4 | import Navigation from './Navigation';
5 |
6 | const App: FC = () => {
7 | return (
8 |
9 |
10 |
11 |
12 |
13 | );
14 | };
15 |
16 | export default App;
17 |
--------------------------------------------------------------------------------
/examples/3-gmail-clone/app/Navigation.tsx:
--------------------------------------------------------------------------------
1 | import 'react-native-gesture-handler';
2 | import React, {FC, useContext} from 'react';
3 | import {NavigationContainer, DefaultTheme} from '@react-navigation/native';
4 | import {createDrawerNavigator} from '@react-navigation/drawer';
5 | import {createStackNavigator} from '@react-navigation/stack';
6 | import {StoreContext} from './models/Store';
7 | import {observer} from 'mobx-react-lite';
8 | import InboxScreen from './screens/InboxScreen';
9 | import DetailScreen from './screens/DetailScreen';
10 | import TrashScreen from './screens/TrashScreen';
11 | import LoginScreen from './screens/LoginScreen';
12 | import SplashScreen from './screens/SplashScreen';
13 |
14 | const MyTheme = {
15 | ...DefaultTheme,
16 | colors: {
17 | ...DefaultTheme.colors,
18 | primary: '#002984',
19 | },
20 | };
21 |
22 | const HomeStack = createStackNavigator();
23 | const HomeStackScreen = () => {
24 | return (
25 |
26 |
27 |
28 |
29 | );
30 | };
31 |
32 | const TrashStack = createStackNavigator();
33 | const TrashStackScreen = () => {
34 | return (
35 |
36 |
37 |
38 |
39 | );
40 | };
41 |
42 | const HomeDrawer = createDrawerNavigator();
43 | const HomeDrawerScreen = () => {
44 | return (
45 |
46 |
47 |
48 |
49 | );
50 | };
51 |
52 | const MainStack = createStackNavigator();
53 |
54 | const Navigation: FC = () => {
55 | const store = useContext(StoreContext);
56 |
57 | if (store.isCheckingLoggedIn) {
58 | return ;
59 | }
60 |
61 | return (
62 |
63 |
64 | {store.isLoginSuccess === true ? (
65 |
66 | ) : (
67 |
68 | )}
69 |
70 |
71 | );
72 | };
73 |
74 | export default observer(Navigation);
75 |
--------------------------------------------------------------------------------
/examples/3-gmail-clone/app/components/EmailList.tsx:
--------------------------------------------------------------------------------
1 | import {observer} from 'mobx-react-lite';
2 | import {Box, HStack, Icon, Spinner, Text} from 'native-base';
3 | import React, {FC, useContext} from 'react';
4 | import {Alert, StyleSheet, TouchableOpacity} from 'react-native';
5 | import {SwipeListView} from 'react-native-swipe-list-view';
6 | import Ionicons from 'react-native-vector-icons/dist/Ionicons';
7 | import {Email} from '../models/models';
8 | import {StoreContext} from '../models/Store';
9 | import EmailListItem from './EmailListItem';
10 |
11 | interface EmailListProps {
12 | category: string;
13 | }
14 |
15 | const EmailList: FC = ({category}) => {
16 | const store = useContext(StoreContext);
17 | const {isLoading, emails} = store;
18 |
19 | const archiveEmail = () => {
20 | Alert.alert('Email was archived successfully!');
21 | };
22 |
23 | if (isLoading) {
24 | return (
25 |
26 |
27 |
28 | );
29 | }
30 |
31 | if (emails.length === 0) {
32 | return (
33 |
34 | No email in the box!
35 |
36 | );
37 | }
38 |
39 | return (
40 | }
43 | renderHiddenItem={() => (
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 | )}
54 | keyExtractor={(item: Email) => item.id?.toString()}
55 | leftOpenValue={75}
56 | rightOpenValue={-75}
57 | />
58 | );
59 | };
60 |
61 | const styles = StyleSheet.create({
62 | swipeListHiddenIconWrapper: {
63 | width: 75,
64 | justifyContent: 'center',
65 | alignItems: 'center',
66 | },
67 | swipeListHiddenIcon: {
68 | color: '#fff',
69 | fontSize: 30,
70 | },
71 | });
72 |
73 | export default observer(EmailList);
74 |
--------------------------------------------------------------------------------
/examples/3-gmail-clone/app/components/EmailListItem.tsx:
--------------------------------------------------------------------------------
1 | import {useNavigation} from '@react-navigation/native';
2 | import {observer} from 'mobx-react-lite';
3 | import {Box, Checkbox, HStack, Icon, Text} from 'native-base';
4 | import React, {FC, useContext} from 'react';
5 | import {TouchableOpacity} from 'react-native';
6 | import Ionicons from 'react-native-vector-icons/dist/Ionicons';
7 | import {Email} from '../models/models';
8 | import {StoreContext} from '../models/Store';
9 |
10 | interface EmailListItemProps {
11 | item: Email;
12 | category: string;
13 | }
14 |
15 | const EmailListItem: FC = ({item, category}) => {
16 | const navigation = useNavigation();
17 | const store = useContext(StoreContext);
18 | const {checkedEmailIds, checkEmail, toggleStar, setEmailContent} = store;
19 | const isChecked = checkedEmailIds.includes(item.id);
20 |
21 | const goToDetailScreen = () => {
22 | setEmailContent(item.content);
23 | navigation.navigate('Detail');
24 | };
25 |
26 | return (
27 |
35 |
36 | checkEmail(item.id)}
41 | />
42 |
43 |
44 |
45 |
46 |
47 | {item.sender}
48 |
49 | {item.title}
50 |
51 |
52 |
53 |
54 | {item.time}
55 | toggleStar(category, item.id)}
61 | />
62 |
63 |
64 | );
65 | };
66 |
67 | export default observer(EmailListItem);
68 |
--------------------------------------------------------------------------------
/examples/3-gmail-clone/app/components/ScreenHeader.tsx:
--------------------------------------------------------------------------------
1 | import {useNavigation} from '@react-navigation/native';
2 | import {observer} from 'mobx-react-lite';
3 | import {HStack, Heading, Button, Icon, Image, Box} from 'native-base';
4 | import React, {FC, useContext} from 'react';
5 | import {TouchableOpacity} from 'react-native';
6 | import {StoreContext} from '../models/Store';
7 | import Ionicons from 'react-native-vector-icons/dist/Ionicons';
8 |
9 | interface ScreenHeaderProps {
10 | hasMenuButton?: boolean;
11 | title: string;
12 | }
13 | const ScreenHeader: FC = ({hasMenuButton = false, title = ''}) => {
14 | const navigation = useNavigation();
15 | const store = useContext(StoreContext);
16 | const {avatar, logout} = store;
17 |
18 | return (
19 |
26 | {hasMenuButton ? (
27 |
28 |
29 |
30 | ) : (
31 |
32 |
33 |
34 | )}
35 |
36 | {title}
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 | );
45 | };
46 |
47 | export default observer(ScreenHeader);
48 |
--------------------------------------------------------------------------------
/examples/3-gmail-clone/app/components/Toolbar.tsx:
--------------------------------------------------------------------------------
1 | import {observer} from 'mobx-react-lite';
2 | import {Box, Button, Icon, Text} from 'native-base';
3 | import React, {FC, useContext} from 'react';
4 | import {Platform, StyleSheet} from 'react-native';
5 | import {StoreContext} from '../models/Store';
6 |
7 | interface ToolbarProps {
8 | category: string;
9 | }
10 |
11 | const Toolbar: FC = ({category}) => {
12 | const store = useContext(StoreContext);
13 | const {setShowToolbar, checkedEmailIds, setCheckedEmailIds, moveSelectedEmails} = store;
14 |
15 | const hideToolbar = () => {
16 | setShowToolbar(false);
17 | setCheckedEmailIds([]);
18 | };
19 |
20 | return (
21 |
22 |
23 |
24 |
25 |
26 | {checkedEmailIds.length}
27 |
28 | {category === 'emails' ? (
29 | moveSelectedEmails('emails', 'trashEmails')}>
30 |
31 |
32 | ) : (
33 | moveSelectedEmails('trashEmails', 'emails')}>
34 |
35 |
36 | )}
37 |
38 | );
39 | };
40 |
41 | const styles = StyleSheet.create({
42 | countText: {
43 | color: Platform.OS === 'ios' ? '#000' : '#fff',
44 | fontSize: 22,
45 | fontWeight: 'bold',
46 | },
47 | });
48 |
49 | export default observer(Toolbar);
50 |
--------------------------------------------------------------------------------
/examples/3-gmail-clone/app/models/Store.ts:
--------------------------------------------------------------------------------
1 | import {makeAutoObservable, runInAction} from 'mobx';
2 | import {createContext} from 'react';
3 | import {create} from 'apisauce';
4 | import AsyncStorage from '@react-native-community/async-storage';
5 | import {Email, User} from './models';
6 |
7 | const LOGIN_KEY = 'loginToken';
8 | const AVATAR_KEY = 'avatar';
9 | const DEFAULT_AVATAR = 'https://globalplatform.org/wp-content/uploads/2018/03/default-avatar.png';
10 |
11 | // https://github.com/infinitered/apisauce
12 | const api = create({
13 | baseURL: 'http://10.10.31.61:3000', // Change 192.168.1.111 to your machine IP
14 | headers: {'Content-Type': 'application/json'},
15 | });
16 |
17 | class Store {
18 | isCheckingLoggedIn: boolean = true;
19 | isLoginSuccess: boolean | null = null;
20 | isLoading: boolean = false;
21 | token: string = '';
22 | avatar: string = DEFAULT_AVATAR;
23 | emails: Email[] = [];
24 | checkedEmailIds: number[] = [];
25 | isShowToolbar: boolean = false;
26 | emailContent: string = '';
27 |
28 | constructor() {
29 | // https://mobx.js.org/observable-state.html
30 | makeAutoObservable(this);
31 |
32 | // Add authorization request header
33 | api.addRequestTransform(request => {
34 | if (this.token) {
35 | request.headers.Authorization = 'Bearer ' + this.token;
36 | }
37 | });
38 |
39 | // Handle unauthorized request
40 | api.addResponseTransform(response => {
41 | if (response.data === 'Unauthorized') {
42 | this.logout();
43 | }
44 | });
45 |
46 | // Check user logged in
47 | (async () => {
48 | try {
49 | const loginToken = await AsyncStorage.getItem(LOGIN_KEY);
50 | const avatar = await AsyncStorage.getItem(AVATAR_KEY);
51 |
52 | if (loginToken) {
53 | this.setLoginSuccess(true);
54 | this.setAvatar(avatar);
55 | this.setToken(loginToken);
56 | }
57 | } catch (e) {
58 | console.log(e);
59 | }
60 |
61 | // https://mobx.js.org/actions.html
62 | runInAction(() => (this.isCheckingLoggedIn = false));
63 | })();
64 | }
65 |
66 | setLoginSuccess = (result: boolean | null) => {
67 | this.isLoginSuccess = result;
68 | };
69 |
70 | setToken = (token: string | null | undefined) => {
71 | this.token = token || '';
72 | };
73 |
74 | setAvatar = (avatar: string | null | undefined) => {
75 | this.avatar = avatar || DEFAULT_AVATAR;
76 | };
77 |
78 | setShowToolbar = (data: boolean) => {
79 | this.isShowToolbar = data;
80 | };
81 |
82 | setEmails = (emails: Email[] | string | undefined) => {
83 | if (!Array.isArray(emails)) {
84 | emails = [];
85 | }
86 | this.emails = emails;
87 | };
88 |
89 | setCheckedEmailIds = (ids: number[]) => {
90 | this.checkedEmailIds = ids;
91 | };
92 |
93 | setEmailContent = (data: string) => {
94 | this.emailContent = data;
95 | };
96 |
97 | login = async (email: string, password: string) => {
98 | const res = await api.post('/login', {email, password});
99 |
100 | if (res.ok) {
101 | const user = res.data;
102 | this.setLoginSuccess(true);
103 | this.setAvatar(user?.avatar);
104 | this.setToken(user?.token);
105 | AsyncStorage.setItem(LOGIN_KEY, user?.token || '');
106 | AsyncStorage.setItem(AVATAR_KEY, user?.avatar || '');
107 | } else {
108 | this.setLoginSuccess(false);
109 | }
110 | };
111 |
112 | logout = () => {
113 | this.setLoginSuccess(null);
114 | this.setAvatar('');
115 | AsyncStorage.setItem(LOGIN_KEY, '');
116 | AsyncStorage.setItem(AVATAR_KEY, '');
117 | };
118 |
119 | getEmails = async (category: string) => {
120 | runInAction(() => (this.isLoading = true));
121 |
122 | const res = await api.get(`/${category}`);
123 |
124 | if (res.ok) {
125 | this.setEmails(res.data);
126 | }
127 |
128 | runInAction(() => (this.isLoading = false));
129 | };
130 |
131 | updateEmail = async (category: string, email: Email) => {
132 | const res = await api.put(`/${category}/${email.id}`, email);
133 |
134 | if (res.ok) {
135 | return res.data;
136 | }
137 | };
138 |
139 | moveEmails = async (fromCategory: string, toCategory: string, emails: Email[]) => {
140 | const result = await Promise.all(
141 | emails.map(email =>
142 | api.post(`/${toCategory}`, email).then(() => {
143 | api.delete(`/${fromCategory}/${email.id}`);
144 | }),
145 | ),
146 | );
147 |
148 | return result;
149 | };
150 |
151 | moveSelectedEmails = async (fromCategory: string, toCategory: string) => {
152 | let selectedEmails = [];
153 | let unselectedEmails = [];
154 | for (let item of this.emails) {
155 | if (this.checkedEmailIds.includes(item.id)) {
156 | selectedEmails.push(item);
157 | } else {
158 | unselectedEmails.push(item);
159 | }
160 | }
161 |
162 | await this.moveEmails(fromCategory, toCategory, selectedEmails);
163 |
164 | this.setEmails(unselectedEmails);
165 | this.setCheckedEmailIds([]);
166 | this.setShowToolbar(false);
167 | };
168 |
169 | toggleStar = async (category: string, emailId: number) => {
170 | this.emails = this.emails.map(email => {
171 | if (email.id === emailId) {
172 | email.isStarred = !email.isStarred;
173 | this.updateEmail(category, email);
174 | }
175 |
176 | return email;
177 | });
178 | };
179 |
180 | checkEmail = (emailId: number) => {
181 | const indexOfCheckedEmail = this.checkedEmailIds.indexOf(emailId);
182 |
183 | if (indexOfCheckedEmail !== -1) {
184 | this.checkedEmailIds.splice(indexOfCheckedEmail, 1);
185 | } else {
186 | this.checkedEmailIds.push(emailId);
187 | }
188 |
189 | if (this.checkedEmailIds.length === 0) {
190 | this.setShowToolbar(false);
191 | } else {
192 | this.setShowToolbar(true);
193 | }
194 | };
195 | }
196 |
197 | export const StoreContext = createContext(new Store());
198 |
199 | export default Store;
200 |
--------------------------------------------------------------------------------
/examples/3-gmail-clone/app/models/models.ts:
--------------------------------------------------------------------------------
1 | export interface User {
2 | id: number;
3 | name: string;
4 | email: string;
5 | password: string;
6 | avatar: string;
7 | token?: string;
8 | }
9 |
10 | export interface Email {
11 | id: number;
12 | sender: string;
13 | title: string;
14 | time: string;
15 | isRead: boolean;
16 | isStarred: boolean;
17 | content: string;
18 | }
19 |
--------------------------------------------------------------------------------
/examples/3-gmail-clone/app/screens/DetailScreen.tsx:
--------------------------------------------------------------------------------
1 | import {observer} from 'mobx-react-lite';
2 | import {Box} from 'native-base';
3 | import React, {FC, useContext} from 'react';
4 | import {WebView} from 'react-native-webview';
5 | import ScreenHeader from '../components/ScreenHeader';
6 | import {StoreContext} from '../models/Store';
7 |
8 | const DetailScreen: FC = () => {
9 | const store = useContext(StoreContext);
10 | const {emailContent} = store;
11 |
12 | const headTag = `
13 |
14 |
15 |
16 | `;
17 | const htmlContent = `${headTag}${emailContent}`;
18 |
19 | return (
20 |
21 |
22 |
23 |
24 |
25 | );
26 | };
27 |
28 | export default observer(DetailScreen);
29 |
--------------------------------------------------------------------------------
/examples/3-gmail-clone/app/screens/InboxScreen.tsx:
--------------------------------------------------------------------------------
1 | import {useFocusEffect} from '@react-navigation/native';
2 | import {observer} from 'mobx-react-lite';
3 | import {Box} from 'native-base';
4 | import React, {FC, useCallback, useContext} from 'react';
5 | import EmailList from '../components/EmailList';
6 | import ScreenHeader from '../components/ScreenHeader';
7 | import Toolbar from '../components/Toolbar';
8 | import {StoreContext} from '../models/Store';
9 |
10 | const HomeScreen: FC = () => {
11 | const store = useContext(StoreContext);
12 | const {isShowToolbar, getEmails} = store;
13 |
14 | // https://reactnavigation.org/docs/use-focus-effect/
15 | useFocusEffect(
16 | useCallback(() => {
17 | getEmails('emails');
18 | // eslint-disable-next-line react-hooks/exhaustive-deps
19 | }, []),
20 | );
21 |
22 | return (
23 |
24 | {isShowToolbar ? : }
25 |
26 |
27 |
28 | );
29 | };
30 |
31 | export default observer(HomeScreen);
32 |
--------------------------------------------------------------------------------
/examples/3-gmail-clone/app/screens/LoginScreen.tsx:
--------------------------------------------------------------------------------
1 | import {Box, Button, Heading, HStack, Text, VStack} from 'native-base';
2 | import React, {FC} from 'react';
3 | import {Image, StyleSheet, TouchableOpacity} from 'react-native';
4 |
5 | import LoginForm from './login/LoginForm';
6 |
7 | const LoginScreen: FC = () => {
8 | return (
9 |
10 |
11 |
12 | Sign in
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 | Sign up
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 | Can't access your account?
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 | © 2023 Google
41 |
42 |
43 |
44 | );
45 | };
46 |
47 | const styles = StyleSheet.create({
48 | logo: {
49 | width: 150,
50 | height: 57,
51 | },
52 | forgotPasswordText: {
53 | color: '#658fd9',
54 | marginTop: 15,
55 | },
56 | separator: {
57 | borderBottomColor: '#ddd',
58 | borderBottomWidth: 1,
59 | marginBottom: 15,
60 | },
61 | });
62 |
63 | export default LoginScreen;
64 |
--------------------------------------------------------------------------------
/examples/3-gmail-clone/app/screens/SplashScreen.tsx:
--------------------------------------------------------------------------------
1 | import {Box, Spinner} from 'native-base';
2 | import React, {FC} from 'react';
3 |
4 | const SplashScreen: FC = () => {
5 | return (
6 |
7 |
8 |
9 | );
10 | };
11 |
12 | export default SplashScreen;
13 |
--------------------------------------------------------------------------------
/examples/3-gmail-clone/app/screens/TrashScreen.tsx:
--------------------------------------------------------------------------------
1 | import {useFocusEffect} from '@react-navigation/native';
2 | import {observer} from 'mobx-react-lite';
3 | import {Box} from 'native-base';
4 | import React, {FC, useCallback, useContext} from 'react';
5 | import EmailList from '../components/EmailList';
6 | import HeaderComponent from '../components/ScreenHeader';
7 | import Toolbar from '../components/Toolbar';
8 | import {StoreContext} from '../models/Store';
9 |
10 | const TrashScreen: FC = () => {
11 | const store = useContext(StoreContext);
12 | const {isShowToolbar, getEmails} = store;
13 |
14 | useFocusEffect(
15 | useCallback(() => {
16 | getEmails('trashEmails');
17 | // eslint-disable-next-line react-hooks/exhaustive-deps
18 | }, []),
19 | );
20 |
21 | return (
22 |
23 | {isShowToolbar ? (
24 |
25 | ) : (
26 |
27 | )}
28 |
29 |
30 |
31 | );
32 | };
33 |
34 | export default observer(TrashScreen);
35 |
--------------------------------------------------------------------------------
/examples/3-gmail-clone/app/screens/login/LoginForm.tsx:
--------------------------------------------------------------------------------
1 | import {observer} from 'mobx-react-lite';
2 | import {Box, Button, Input, Heading, Text} from 'native-base';
3 | import React, {FC, useContext, useState} from 'react';
4 | import {StyleSheet} from 'react-native';
5 | import {StoreContext} from '../../models/Store';
6 |
7 | const LoginForm: FC = () => {
8 | const store = useContext(StoreContext);
9 | const {login, isLoginSuccess} = store;
10 |
11 | const [email, setEmail] = useState('');
12 | const [password, setPassword] = useState('');
13 |
14 | return (
15 |
16 | Sign In
17 |
18 | {isLoginSuccess === false && Invalid email or password }
19 |
20 |
21 |
28 |
29 |
30 |
31 |
39 |
40 |
41 | login(email, password)}>
42 | Sign In
43 |
44 |
45 | );
46 | };
47 |
48 | const styles = StyleSheet.create({
49 | errorMsg: {
50 | fontSize: 16,
51 | marginBottom: 15,
52 | marginLeft: 3,
53 | fontStyle: 'italic',
54 | color: 'red',
55 | },
56 | item: {
57 | marginBottom: 15,
58 | padding: 0,
59 | backgroundColor: '#fff',
60 | },
61 | input: {
62 | fontSize: 16,
63 | },
64 | });
65 |
66 | export default observer(LoginForm);
67 |
--------------------------------------------------------------------------------
/examples/3-gmail-clone/app/screens/login/google-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/robinhuy/react-native-typescript-examples/3a088e6b7407fde40b8161c38872fc482b5f8118/examples/3-gmail-clone/app/screens/login/google-logo.png
--------------------------------------------------------------------------------
/examples/3-gmail-clone/server/README.md:
--------------------------------------------------------------------------------
1 | # Fake REST API NodeJS
2 |
3 | Get a full fake REST API as soon as possible. Base on [NodeJS](https://nodejs.org/en/) + [JSON Server](https://github.com/typicode/json-server).
4 |
5 | Support more features:
6 |
7 | - Register user with username & password or email & password.
8 |
9 | - Login with registered users.
10 |
11 | - Protect resources using JWT Bearer authentication.
12 |
13 | - Upload files.
14 |
15 | Preview: [https://fake-rest-api-nodejs.herokuapp.com](https://fake-rest-api-nodejs.herokuapp.com/)
16 |
17 | ## Getting started
18 |
19 | ### 1. Clone this repository
20 |
21 | ```bash
22 | git clone https://github.com/robinhuy/fake-rest-api-nodejs.git
23 | ```
24 |
25 | or fork to your account and clone the forked repo
26 |
27 | ### 2. Install dependencies
28 |
29 | ```bash
30 | cd fake-rest-api-nodejs
31 | npm install
32 | ```
33 |
34 | or if you using yarn
35 |
36 | ```bash
37 | cd fake-rest-api-nodejs
38 | yarn install
39 | ```
40 |
41 | ### 3. Run server
42 |
43 | - Production mode:
44 |
45 | ```bash
46 | npm start
47 | ```
48 |
49 | or
50 |
51 | ```bash
52 | yarn start
53 | ```
54 |
55 | - Development mode (auto reload server when editing using [nodemon](https://github.com/remy/nodemon)):
56 |
57 | ```bash
58 | npm run dev
59 | ```
60 |
61 | or
62 |
63 | ```bash
64 | yarn dev
65 | ```
66 |
67 | - The server will run on `http://localhost:3000`. You can test with public endpoint: `http://localhost:3000/products` (GET method).
68 |
69 | ## Modify your data
70 |
71 | All the data was placed in `database.json`. Edit it to suit your purpose.
72 |
73 | You can use [https://mockaroo.com/](https://mockaroo.com/) to mock data, and publish your code to [https://heroku.com/](https://heroku.com/) or similar hosting to get a Public API.
74 |
75 | **Note**:
76 |
77 | - To protect resources, decleare resources and protected methods in `database.json`:
78 |
79 | ```json
80 | "protected_resources": {
81 | "users": ["GET", "POST", "PUT", "PATCH", "DELETE"],
82 | "products": ["POST", "PUT", "PATCH", "DELETE"]
83 | }
84 | ```
85 |
86 | - To register new user, using endpoint `/register`, method `POST`, request type `application/json`. Body request like `users` resources:
87 |
88 | - To login, using endpoint `/login`, method `POST`, request type `application/json`. Body request like this:
89 |
90 | ```json
91 | {
92 | "username": "admin",
93 | "password": "admin"
94 | }
95 | ```
96 |
97 | or
98 |
99 | ```json
100 | {
101 | "email": "admin@gmail.com",
102 | "password": "admin"
103 | }
104 | ```
105 |
106 | - To upload single file, using endpoint `/upload-file`, method `POST`, request type `form-data`, field `file`. Uploaded file stored in `/public/uploads/`.
107 |
108 | - To upload multiple files, using endpoint `/upload-files`, method `POST`, request type `form-data`, field `files`. Uploaded files stored in `/public/uploads/`.
109 |
110 | - Change default port, database file, jwt secret or jwt token expires in `config.json`.
111 |
112 | ## Access & modify API
113 |
114 | Please view detailed document in [https://github.com/typicode/json-server/blob/master/README.md#table-of-contents](https://github.com/typicode/json-server/blob/master/README.md#table-of-contents)
115 |
116 | If you want to change logic of authentication or add more feature, please edit file `server.js` or `additional_routes.js`.
117 |
118 | ## Default Endpoints
119 |
120 | View and modify resources in `database.json`.
121 |
122 | ### Open Endpoints
123 |
124 | Open endpoints require no Authentication.
125 |
126 | #### User
127 |
128 | - Login: POST /login
129 |
130 | - Register: POST /register
131 |
132 | #### Product
133 |
134 | - Get products: GET /products
135 |
136 | - Get product by ID: GET /products/:id
137 |
138 | #### Media
139 |
140 | - Upload single file: POST /upload-file
141 |
142 | - Upload multiple files: POST /upload-files
143 |
144 | ### Private Endpoints (require Authentication)
145 |
146 | Private endpoints require a valid Token to be included in the header of the request. A Token can be acquired from the Login view above.
147 |
148 | #### User
149 |
150 | - Get users: GET /users
151 |
152 | - Get user by ID: GET /users/:id
153 |
154 | - Create user: POST /users
155 |
156 | - Update user (entire information): PUT /users/:id
157 |
158 | - Update user (partial information) PATCH /users/:id
159 |
160 | #### Product
161 |
162 | - Create product: POST /products
163 |
164 | - Update product (entire information): PUT /products/:id
165 |
166 | - Update product (partial information) PATCH /products/:id
--------------------------------------------------------------------------------
/examples/3-gmail-clone/server/additional_routes.js:
--------------------------------------------------------------------------------
1 | const formidable = require('formidable');
2 | const {copyFile, unlink} = require('fs/promises');
3 | const {generateJwtToken} = require('./jwt-authenticate');
4 |
5 | const handleUploadFile = async (req, file) => {
6 | const uploadFolder = 'uploads';
7 |
8 | try {
9 | // Copy file from temp folder to uploads folder (not rename to allow cross-device link)
10 | await copyFile(file.path, `./public/${uploadFolder}/${file.name}`);
11 |
12 | // Remove temp file
13 | await unlink(file.path);
14 |
15 | // Return new path of uploaded file
16 | file.path = `${req.protocol}://${req.get('host')}/${uploadFolder}/${
17 | file.name
18 | }`;
19 |
20 | return file;
21 | } catch (err) {
22 | throw err;
23 | }
24 | };
25 |
26 | module.exports = {
27 | loginHandler: (db, req, res) => {
28 | const {username, email, password: pwd} = req.body;
29 |
30 | const user = db
31 | .get('users')
32 | .find(
33 | (u) =>
34 | (u.username === username || u.email === email) && u.password === pwd,
35 | )
36 | .value();
37 |
38 | if (user && user.password === pwd) {
39 | const token = generateJwtToken(user.id);
40 | const {password, ...userWithoutPassword} = user;
41 |
42 | res.jsonp({
43 | ...userWithoutPassword,
44 | token,
45 | });
46 | } else {
47 | res.status(400).jsonp({message: 'Username or password is incorrect!'});
48 | }
49 | },
50 |
51 | registerHandler: (db, req, res) => {
52 | const {username, email, password} = req.body;
53 |
54 | if (!password && (!email || !username)) {
55 | res.status(400).jsonp({message: 'Please input all required fields!'});
56 | return;
57 | }
58 |
59 | const existUsername = db
60 | .get('users')
61 | .find((user) => username && user.username === username)
62 | .value();
63 |
64 | if (existUsername) {
65 | res.status(400).jsonp({
66 | message:
67 | 'The username already exists. Please use a different username!',
68 | });
69 | return;
70 | }
71 |
72 | const existEmail = db
73 | .get('users')
74 | .find((user) => email && user.email === email)
75 | .value();
76 |
77 | if (existEmail) {
78 | res.status(400).jsonp({
79 | message:
80 | 'The email address is already being used! Please use a different email!',
81 | });
82 | return;
83 | }
84 |
85 | const lastUser = db.get('users').maxBy('id').value();
86 | const newUserId = parseInt(lastUser.id, 10) + 1;
87 | const newUser = {id: newUserId, ...req.body};
88 |
89 | db.get('users').push(newUser).write();
90 |
91 | res.jsonp(newUser);
92 | },
93 |
94 | uploadFileHandler: (req, res) => {
95 | if (req.headers['content-type'] === 'application/json') {
96 | res
97 | .status(400)
98 | .jsonp({message: 'Content-Type "application/json" is not allowed.'});
99 | return;
100 | }
101 |
102 | const form = formidable();
103 |
104 | form.parse(req, async (error, fields, files) => {
105 | let file = files.file;
106 |
107 | if (error || !file) {
108 | res.status(400).jsonp({message: 'Missing "file" field.'});
109 | return;
110 | }
111 |
112 | try {
113 | file = await handleUploadFile(req, file);
114 | res.jsonp(file);
115 | } catch (err) {
116 | console.log(err);
117 | res.status(500).jsonp({message: 'Cannot upload file.'});
118 | }
119 | });
120 | },
121 |
122 | uploadFilesHandler: (req, res) => {
123 | if (req.headers['content-type'] === 'application/json') {
124 | res
125 | .status(400)
126 | .jsonp({message: 'Content-Type "application/json" is not allowed.'});
127 | return;
128 | }
129 |
130 | const form = formidable({multiples: true});
131 |
132 | form.parse(req, async (error, fields, files) => {
133 | let filesUploaded = files.files;
134 |
135 | if (error || !filesUploaded) {
136 | res.status(400).jsonp({message: 'Missing "files" field.'});
137 | return;
138 | }
139 |
140 | // If user upload 1 file, transform data to array
141 | if (!Array.isArray(filesUploaded)) {
142 | filesUploaded = [filesUploaded];
143 | }
144 |
145 | try {
146 | // Handle all uploaded files
147 | filesUploaded = await Promise.all(
148 | filesUploaded.map(async (file) => {
149 | try {
150 | file = await handleUploadFile(req, file);
151 | return file;
152 | } catch (err) {
153 | throw err;
154 | }
155 | }),
156 | );
157 |
158 | res.jsonp(filesUploaded);
159 | } catch (err) {
160 | console.log(err);
161 | res.status(500).jsonp({message: 'Cannot upload files.'});
162 | }
163 | });
164 | },
165 | };
166 |
--------------------------------------------------------------------------------
/examples/3-gmail-clone/server/config.json:
--------------------------------------------------------------------------------
1 | {
2 | "defaultPort": 3000,
3 | "databaseFile": "database.json",
4 | "jwtSecret": "robin_huy",
5 | "jwtTokenexpiresInMinutes": "60"
6 | }
7 |
--------------------------------------------------------------------------------
/examples/3-gmail-clone/server/database.json:
--------------------------------------------------------------------------------
1 | {
2 | "protected_resources": {
3 | "users": [
4 | "GET",
5 | "POST",
6 | "PUT",
7 | "PATCH",
8 | "DELETE"
9 | ],
10 | "emails": [
11 | "GET",
12 | "POST",
13 | "PUT",
14 | "PATCH",
15 | "DELETE"
16 | ],
17 | "trashEmails": [
18 | "GET",
19 | "POST",
20 | "PUT",
21 | "PATCH",
22 | "DELETE"
23 | ]
24 | },
25 | "users": [
26 | {
27 | "id": 1,
28 | "name": "Robin Huy",
29 | "username": "admin",
30 | "email": "admin@gmail.com",
31 | "password": "123456",
32 | "avatar": "https://avatars0.githubusercontent.com/u/12640832?s=460&u=a57e7a0a0f8f0b7740adb942e2d76e599cbd217b&v=4"
33 | },
34 | {
35 | "id": 2,
36 | "name": "Robin 2",
37 | "username": "admin2",
38 | "email": "admin2@gmail.com",
39 | "password": "123",
40 | "avatar": "https://avatars0.githubusercontent.com/u/12640832?s=460&u=a57e7a0a0f8f0b7740adb942e2d76e599cbd217b&v=4"
41 | }
42 | ],
43 | "emails": [
44 | {
45 | "id": 3,
46 | "sender": "Firebase",
47 | "title": "Cloud Storage for Firebase",
48 | "time": "06:06 pm",
49 | "isRead": true,
50 | "isStarred": true,
51 | "content": " Hi Robin,
We are updating our product API for Cloud Storage for Firebase to provide more security, so that each Firebase project has its own dedicated Storage service account. You will see our API enabled and added service account(s) on your project(s) by December 1, 2020.
Thanks,
Ke on behalf of the Firebase team
"
52 | },
53 | {
54 | "id": 2,
55 | "sender": "Google Analytics",
56 | "title": "Discover the latest updates to Google Analytics",
57 | "time": "09:07 am",
58 | "isRead": true,
59 | "isStarred": true,
60 | "content": "August 2020 - Product Update PRODUCT & FEATURE HIGHLIGHTS
Improve Performance and Security With Server-Side Tagging We are introducing Server-Side Tagging to Google Tag Manager and Tag Manager 360. You'll now be able to move many third-party tags off your site and into a new server container hosted in your Google Cloud account. That means when customers interact with a page on your site, third-party tags are loaded directly in the server container rather than the site.
LEARN MORE
"
61 | },
62 | {
63 | "id": 4,
64 | "sender": "Postgres Weekly",
65 | "title": "The tale of two little regexes",
66 | "time": "04:44 pm",
67 | "isRead": true,
68 | "isStarred": true,
69 | "content": "Postgres Weekly
A Seamless MongoDB to PostgreSQL Migration — Coinbase is a large digital currency exchange so having a solid foundation for its data is a must. Here they share some lessons learned from a large cross-database data migration to AWS RDS PostgreSQL.
Alex Ghise (Coinbase)
",
70 | "modifiedAt": 1671184999231
71 | }
72 | ],
73 | "trashEmails": [
74 | {
75 | "id": 1,
76 | "sender": "Node Weekly",
77 | "title": "Spelunking Node's event loop",
78 | "time": "03:43 am",
79 | "isRead": false,
80 | "isStarred": false,
81 | "content": ""
82 | }
83 | ]
84 | }
--------------------------------------------------------------------------------
/examples/3-gmail-clone/server/jwt-authenticate.js:
--------------------------------------------------------------------------------
1 | const jwt = require('jsonwebtoken');
2 | const {jwtSecret, jwtTokenexpiresInMinutes} = require('./config.json');
3 |
4 | function generateJwtToken(userId) {
5 | return jwt.sign({sub: userId}, jwtSecret, {
6 | expiresIn: jwtTokenexpiresInMinutes + 'm',
7 | });
8 | }
9 |
10 | function isAuthenticated(req) {
11 | let token = '';
12 | if (
13 | req.headers.authorization &&
14 | req.headers.authorization.split(' ')[0] === 'Bearer'
15 | ) {
16 | token = req.headers.authorization.split(' ')[1];
17 | }
18 |
19 | try {
20 | jwt.verify(token, jwtSecret);
21 | } catch (err) {
22 | return false;
23 | }
24 |
25 | return true;
26 | }
27 |
28 | module.exports = {
29 | generateJwtToken,
30 | isAuthenticated,
31 | };
32 |
--------------------------------------------------------------------------------
/examples/3-gmail-clone/server/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "fake-rest-api-nodejs",
3 | "version": "1.0.0",
4 | "description": "Fake REST API using NodeJS + JSON Server",
5 | "main": "server.js",
6 | "scripts": {
7 | "start": "node server.js",
8 | "dev": "nodemon server.js"
9 | },
10 | "repository": {
11 | "type": "git",
12 | "url": "git+https://github.com/robinhuy/fake-rest-api-nodejs.git"
13 | },
14 | "keywords": [
15 | "json-server",
16 | "rest-api"
17 | ],
18 | "author": "Robin Huy",
19 | "license": "MIT",
20 | "bugs": {
21 | "url": "https://github.com/robinhuy/fake-rest-api-nodejs/issues"
22 | },
23 | "homepage": "https://github.com/robinhuy/fake-rest-api-nodejs#readme",
24 | "dependencies": {
25 | "date-fns": "^2.25.0",
26 | "formidable": "^1.2.2",
27 | "json-server": "^0.16.1",
28 | "jsonwebtoken": "^8.5.1",
29 | "lowdb": "^1.0.0"
30 | },
31 | "devDependencies": {
32 | "nodemon": "^2.0.13"
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/examples/3-gmail-clone/server/server.js:
--------------------------------------------------------------------------------
1 | const jsonServer = require('json-server');
2 | const {isAuthenticated} = require('./jwt-authenticate');
3 | const {
4 | loginHandler,
5 | uploadFileHandler,
6 | uploadFilesHandler,
7 | registerHandler,
8 | } = require('./additional_routes');
9 | const {defaultPort, databaseFile} = require('./config.json');
10 |
11 | const low = require('lowdb');
12 | const FileSync = require('lowdb/adapters/FileSync');
13 | const adapter = new FileSync(databaseFile);
14 | const db = low(adapter);
15 |
16 | const server = jsonServer.create();
17 | const router = jsonServer.router(db);
18 | const middlewares = jsonServer.defaults();
19 | const port = process.env.PORT || defaultPort;
20 |
21 | // Set default middlewares (logger, static, cors and no-cache)
22 | server.use(middlewares);
23 |
24 | // Handle POST, PUT and PATCH request
25 | server.use(jsonServer.bodyParser);
26 |
27 | // Save createdAt and updatedAt automatically
28 | server.use((req, res, next) => {
29 | const currentTime = Date.now();
30 |
31 | if (req.method === 'POST') {
32 | req.body.createdAt = currentTime;
33 | req.body.modifiedAt = currentTime;
34 | } else if (['PUT', 'PATCH'].includes(req.method)) {
35 | req.body.modifiedAt = currentTime;
36 | }
37 |
38 | next();
39 | });
40 |
41 | // Register request
42 | server.post('/register', (req, res) => {
43 | registerHandler(db, req, res);
44 | });
45 |
46 | // Login in request
47 | server.post('/login', (req, res) => {
48 | loginHandler(db, req, res);
49 | });
50 |
51 | // Upload 1 file
52 | server.post('/upload-file', uploadFileHandler);
53 |
54 | // Upload multiple files
55 | server.post('/upload-files', uploadFilesHandler);
56 |
57 | // Access control
58 | server.use((req, res, next) => {
59 | const protectedResources = db.get('protected_resources').value();
60 | if (!protectedResources) {
61 | next();
62 | return;
63 | }
64 |
65 | const resource = req.path.slice(1).split('/')[0];
66 | const protectedResource =
67 | protectedResources[resource] &&
68 | protectedResources[resource].map((item) => item.toUpperCase());
69 | const reqMethod = req.method.toUpperCase();
70 |
71 | if (protectedResource && protectedResource.includes(reqMethod)) {
72 | if (isAuthenticated(req)) {
73 | next();
74 | } else {
75 | res.sendStatus(401);
76 | }
77 | } else {
78 | next();
79 | }
80 | });
81 |
82 | // Setup others routes
83 | server.use(router);
84 |
85 | // Start server
86 | server.listen(port, () => {
87 | console.log('Server is running on port ' + port);
88 | });
89 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | import {AppRegistry} from 'react-native';
2 | import App from './App';
3 | import {name as appName} from './app.json';
4 |
5 | AppRegistry.registerComponent(appName, () => App);
6 |
--------------------------------------------------------------------------------
/ios/.xcode.env:
--------------------------------------------------------------------------------
1 | # This `.xcode.env` file is versioned and is used to source the environment
2 | # used when running script phases inside Xcode.
3 | # To customize your local environment, you can create an `.xcode.env.local`
4 | # file that is not versioned.
5 |
6 | # NODE_BINARY variable contains the PATH to the node executable.
7 | #
8 | # Customize the NODE_BINARY variable here.
9 | # For example, to use nvm with brew, add the following line
10 | # . "$(brew --prefix nvm)/nvm.sh" --no-use
11 | export NODE_BINARY=$(command -v node)
12 |
--------------------------------------------------------------------------------
/ios/Podfile:
--------------------------------------------------------------------------------
1 | require_relative '../node_modules/react-native/scripts/react_native_pods'
2 | require_relative '../node_modules/@react-native-community/cli-platform-ios/native_modules'
3 |
4 | platform :ios, '12.4'
5 | install! 'cocoapods', :deterministic_uuids => false
6 |
7 | target 'ReactNativeTypeScriptExamples' do
8 | config = use_native_modules!
9 |
10 | # React Native Maps dependencies
11 | rn_maps_path = '../node_modules/react-native-maps'
12 | pod 'react-native-google-maps', :path => rn_maps_path
13 | pod 'GoogleMaps'
14 | pod 'Google-Maps-iOS-Utils'
15 |
16 | # Flags change depending on the env values.
17 | flags = get_default_flags()
18 |
19 | use_react_native!(
20 | :path => config[:reactNativePath],
21 | # Hermes is now enabled by default. Disable by setting this flag to false.
22 | # Upcoming versions of React Native may rely on get_default_flags(), but
23 | # we make it explicit here to aid in the React Native upgrade process.
24 | :hermes_enabled => true,
25 | :fabric_enabled => flags[:fabric_enabled],
26 | # Enables Flipper.
27 | #
28 | # Note that if you have use_frameworks! enabled, Flipper will not work and
29 | # you should disable the next line.
30 | :flipper_configuration => FlipperConfiguration.enabled,
31 | # An absolute path to your application root.
32 | :app_path => "#{Pod::Config.instance.installation_root}/.."
33 | )
34 |
35 | target 'ReactNativeTypeScriptExamplesTests' do
36 | inherit! :complete
37 | # Pods for testing
38 | end
39 |
40 | post_install do |installer|
41 | react_native_post_install(
42 | installer,
43 | # Set `mac_catalyst_enabled` to `true` in order to apply patches
44 | # necessary for Mac Catalyst builds
45 | :mac_catalyst_enabled => false
46 | )
47 | __apply_Xcode_12_5_M1_post_install_workaround(installer)
48 | end
49 | end
50 |
--------------------------------------------------------------------------------
/ios/ReactNativeTypescriptExamples.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 54;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 00E356F31AD99517003FC87E /* ReactNativeTypeScriptExamplesTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 00E356F21AD99517003FC87E /* ReactNativeTypeScriptExamplesTests.m */; };
11 | 0C80B921A6F3F58F76C31292 /* libPods-ReactNativeTypeScriptExamples.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5DCACB8F33CDC322A6C60F78 /* libPods-ReactNativeTypeScriptExamples.a */; };
12 | 13B07FBC1A68108700A75B9A /* AppDelegate.mm in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB01A68108700A75B9A /* AppDelegate.mm */; };
13 | 13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; };
14 | 13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; };
15 | 7699B88040F8A987B510C191 /* libPods-ReactNativeTypeScriptExamples-ReactNativeTypeScriptExamplesTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 19F6CBCC0A4E27FBF8BF4A61 /* libPods-ReactNativeTypeScriptExamples-ReactNativeTypeScriptExamplesTests.a */; };
16 | 81AB9BB82411601600AC10FF /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */; };
17 | /* End PBXBuildFile section */
18 |
19 | /* Begin PBXContainerItemProxy section */
20 | 00E356F41AD99517003FC87E /* PBXContainerItemProxy */ = {
21 | isa = PBXContainerItemProxy;
22 | containerPortal = 83CBB9F71A601CBA00E9B192 /* Project object */;
23 | proxyType = 1;
24 | remoteGlobalIDString = 13B07F861A680F5B00A75B9A;
25 | remoteInfo = ReactNativeTypeScriptExamples;
26 | };
27 | /* End PBXContainerItemProxy section */
28 |
29 | /* Begin PBXFileReference section */
30 | 00E356EE1AD99517003FC87E /* ReactNativeTypeScriptExamplesTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ReactNativeTypeScriptExamplesTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
31 | 00E356F11AD99517003FC87E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
32 | 00E356F21AD99517003FC87E /* ReactNativeTypeScriptExamplesTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ReactNativeTypeScriptExamplesTests.m; sourceTree = ""; };
33 | 13B07F961A680F5B00A75B9A /* ReactNativeTypeScriptExamples.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ReactNativeTypeScriptExamples.app; sourceTree = BUILT_PRODUCTS_DIR; };
34 | 13B07FAF1A68108700A75B9A /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = ReactNativeTypeScriptExamples/AppDelegate.h; sourceTree = ""; };
35 | 13B07FB01A68108700A75B9A /* AppDelegate.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = AppDelegate.mm; path = ReactNativeTypeScriptExamples/AppDelegate.mm; sourceTree = ""; };
36 | 13B07FB51A68108700A75B9A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = ReactNativeTypeScriptExamples/Images.xcassets; sourceTree = ""; };
37 | 13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = ReactNativeTypeScriptExamples/Info.plist; sourceTree = ""; };
38 | 13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = ReactNativeTypeScriptExamples/main.m; sourceTree = ""; };
39 | 19F6CBCC0A4E27FBF8BF4A61 /* libPods-ReactNativeTypeScriptExamples-ReactNativeTypeScriptExamplesTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-ReactNativeTypeScriptExamples-ReactNativeTypeScriptExamplesTests.a"; sourceTree = BUILT_PRODUCTS_DIR; };
40 | 3B4392A12AC88292D35C810B /* Pods-ReactNativeTypeScriptExamples.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ReactNativeTypeScriptExamples.debug.xcconfig"; path = "Target Support Files/Pods-ReactNativeTypeScriptExamples/Pods-ReactNativeTypeScriptExamples.debug.xcconfig"; sourceTree = ""; };
41 | 5709B34CF0A7D63546082F79 /* Pods-ReactNativeTypeScriptExamples.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ReactNativeTypeScriptExamples.release.xcconfig"; path = "Target Support Files/Pods-ReactNativeTypeScriptExamples/Pods-ReactNativeTypeScriptExamples.release.xcconfig"; sourceTree = ""; };
42 | 5B7EB9410499542E8C5724F5 /* Pods-ReactNativeTypeScriptExamples-ReactNativeTypeScriptExamplesTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ReactNativeTypeScriptExamples-ReactNativeTypeScriptExamplesTests.debug.xcconfig"; path = "Target Support Files/Pods-ReactNativeTypeScriptExamples-ReactNativeTypeScriptExamplesTests/Pods-ReactNativeTypeScriptExamples-ReactNativeTypeScriptExamplesTests.debug.xcconfig"; sourceTree = ""; };
43 | 5DCACB8F33CDC322A6C60F78 /* libPods-ReactNativeTypeScriptExamples.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-ReactNativeTypeScriptExamples.a"; sourceTree = BUILT_PRODUCTS_DIR; };
44 | 81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = LaunchScreen.storyboard; path = ReactNativeTypeScriptExamples/LaunchScreen.storyboard; sourceTree = ""; };
45 | 89C6BE57DB24E9ADA2F236DE /* Pods-ReactNativeTypeScriptExamples-ReactNativeTypeScriptExamplesTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ReactNativeTypeScriptExamples-ReactNativeTypeScriptExamplesTests.release.xcconfig"; path = "Target Support Files/Pods-ReactNativeTypeScriptExamples-ReactNativeTypeScriptExamplesTests/Pods-ReactNativeTypeScriptExamples-ReactNativeTypeScriptExamplesTests.release.xcconfig"; sourceTree = ""; };
46 | ED297162215061F000B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; };
47 | /* End PBXFileReference section */
48 |
49 | /* Begin PBXFrameworksBuildPhase section */
50 | 00E356EB1AD99517003FC87E /* Frameworks */ = {
51 | isa = PBXFrameworksBuildPhase;
52 | buildActionMask = 2147483647;
53 | files = (
54 | 7699B88040F8A987B510C191 /* libPods-ReactNativeTypeScriptExamples-ReactNativeTypeScriptExamplesTests.a in Frameworks */,
55 | );
56 | runOnlyForDeploymentPostprocessing = 0;
57 | };
58 | 13B07F8C1A680F5B00A75B9A /* Frameworks */ = {
59 | isa = PBXFrameworksBuildPhase;
60 | buildActionMask = 2147483647;
61 | files = (
62 | 0C80B921A6F3F58F76C31292 /* libPods-ReactNativeTypeScriptExamples.a in Frameworks */,
63 | );
64 | runOnlyForDeploymentPostprocessing = 0;
65 | };
66 | /* End PBXFrameworksBuildPhase section */
67 |
68 | /* Begin PBXGroup section */
69 | 00E356EF1AD99517003FC87E /* ReactNativeTypeScriptExamplesTests */ = {
70 | isa = PBXGroup;
71 | children = (
72 | 00E356F21AD99517003FC87E /* ReactNativeTypeScriptExamplesTests.m */,
73 | 00E356F01AD99517003FC87E /* Supporting Files */,
74 | );
75 | path = ReactNativeTypeScriptExamplesTests;
76 | sourceTree = "";
77 | };
78 | 00E356F01AD99517003FC87E /* Supporting Files */ = {
79 | isa = PBXGroup;
80 | children = (
81 | 00E356F11AD99517003FC87E /* Info.plist */,
82 | );
83 | name = "Supporting Files";
84 | sourceTree = "";
85 | };
86 | 13B07FAE1A68108700A75B9A /* ReactNativeTypeScriptExamples */ = {
87 | isa = PBXGroup;
88 | children = (
89 | 13B07FAF1A68108700A75B9A /* AppDelegate.h */,
90 | 13B07FB01A68108700A75B9A /* AppDelegate.mm */,
91 | 13B07FB51A68108700A75B9A /* Images.xcassets */,
92 | 13B07FB61A68108700A75B9A /* Info.plist */,
93 | 81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */,
94 | 13B07FB71A68108700A75B9A /* main.m */,
95 | );
96 | name = ReactNativeTypeScriptExamples;
97 | sourceTree = "";
98 | };
99 | 2D16E6871FA4F8E400B85C8A /* Frameworks */ = {
100 | isa = PBXGroup;
101 | children = (
102 | ED297162215061F000B7C4FE /* JavaScriptCore.framework */,
103 | 5DCACB8F33CDC322A6C60F78 /* libPods-ReactNativeTypeScriptExamples.a */,
104 | 19F6CBCC0A4E27FBF8BF4A61 /* libPods-ReactNativeTypeScriptExamples-ReactNativeTypeScriptExamplesTests.a */,
105 | );
106 | name = Frameworks;
107 | sourceTree = "";
108 | };
109 | 832341AE1AAA6A7D00B99B32 /* Libraries */ = {
110 | isa = PBXGroup;
111 | children = (
112 | );
113 | name = Libraries;
114 | sourceTree = "";
115 | };
116 | 83CBB9F61A601CBA00E9B192 = {
117 | isa = PBXGroup;
118 | children = (
119 | 13B07FAE1A68108700A75B9A /* ReactNativeTypeScriptExamples */,
120 | 832341AE1AAA6A7D00B99B32 /* Libraries */,
121 | 00E356EF1AD99517003FC87E /* ReactNativeTypeScriptExamplesTests */,
122 | 83CBBA001A601CBA00E9B192 /* Products */,
123 | 2D16E6871FA4F8E400B85C8A /* Frameworks */,
124 | BBD78D7AC51CEA395F1C20DB /* Pods */,
125 | );
126 | indentWidth = 2;
127 | sourceTree = "";
128 | tabWidth = 2;
129 | usesTabs = 0;
130 | };
131 | 83CBBA001A601CBA00E9B192 /* Products */ = {
132 | isa = PBXGroup;
133 | children = (
134 | 13B07F961A680F5B00A75B9A /* ReactNativeTypeScriptExamples.app */,
135 | 00E356EE1AD99517003FC87E /* ReactNativeTypeScriptExamplesTests.xctest */,
136 | );
137 | name = Products;
138 | sourceTree = "";
139 | };
140 | BBD78D7AC51CEA395F1C20DB /* Pods */ = {
141 | isa = PBXGroup;
142 | children = (
143 | 3B4392A12AC88292D35C810B /* Pods-ReactNativeTypeScriptExamples.debug.xcconfig */,
144 | 5709B34CF0A7D63546082F79 /* Pods-ReactNativeTypeScriptExamples.release.xcconfig */,
145 | 5B7EB9410499542E8C5724F5 /* Pods-ReactNativeTypeScriptExamples-ReactNativeTypeScriptExamplesTests.debug.xcconfig */,
146 | 89C6BE57DB24E9ADA2F236DE /* Pods-ReactNativeTypeScriptExamples-ReactNativeTypeScriptExamplesTests.release.xcconfig */,
147 | );
148 | path = Pods;
149 | sourceTree = "";
150 | };
151 | /* End PBXGroup section */
152 |
153 | /* Begin PBXNativeTarget section */
154 | 00E356ED1AD99517003FC87E /* ReactNativeTypeScriptExamplesTests */ = {
155 | isa = PBXNativeTarget;
156 | buildConfigurationList = 00E357021AD99517003FC87E /* Build configuration list for PBXNativeTarget "ReactNativeTypeScriptExamplesTests" */;
157 | buildPhases = (
158 | A55EABD7B0C7F3A422A6CC61 /* [CP] Check Pods Manifest.lock */,
159 | 00E356EA1AD99517003FC87E /* Sources */,
160 | 00E356EB1AD99517003FC87E /* Frameworks */,
161 | 00E356EC1AD99517003FC87E /* Resources */,
162 | C59DA0FBD6956966B86A3779 /* [CP] Embed Pods Frameworks */,
163 | F6A41C54EA430FDDC6A6ED99 /* [CP] Copy Pods Resources */,
164 | );
165 | buildRules = (
166 | );
167 | dependencies = (
168 | 00E356F51AD99517003FC87E /* PBXTargetDependency */,
169 | );
170 | name = ReactNativeTypeScriptExamplesTests;
171 | productName = ReactNativeTypeScriptExamplesTests;
172 | productReference = 00E356EE1AD99517003FC87E /* ReactNativeTypeScriptExamplesTests.xctest */;
173 | productType = "com.apple.product-type.bundle.unit-test";
174 | };
175 | 13B07F861A680F5B00A75B9A /* ReactNativeTypeScriptExamples */ = {
176 | isa = PBXNativeTarget;
177 | buildConfigurationList = 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "ReactNativeTypeScriptExamples" */;
178 | buildPhases = (
179 | C38B50BA6285516D6DCD4F65 /* [CP] Check Pods Manifest.lock */,
180 | FD10A7F022414F080027D42C /* Start Packager */,
181 | 13B07F871A680F5B00A75B9A /* Sources */,
182 | 13B07F8C1A680F5B00A75B9A /* Frameworks */,
183 | 13B07F8E1A680F5B00A75B9A /* Resources */,
184 | 00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */,
185 | 00EEFC60759A1932668264C0 /* [CP] Embed Pods Frameworks */,
186 | E235C05ADACE081382539298 /* [CP] Copy Pods Resources */,
187 | );
188 | buildRules = (
189 | );
190 | dependencies = (
191 | );
192 | name = ReactNativeTypeScriptExamples;
193 | productName = ReactNativeTypeScriptExamples;
194 | productReference = 13B07F961A680F5B00A75B9A /* ReactNativeTypeScriptExamples.app */;
195 | productType = "com.apple.product-type.application";
196 | };
197 | /* End PBXNativeTarget section */
198 |
199 | /* Begin PBXProject section */
200 | 83CBB9F71A601CBA00E9B192 /* Project object */ = {
201 | isa = PBXProject;
202 | attributes = {
203 | LastUpgradeCheck = 1210;
204 | TargetAttributes = {
205 | 00E356ED1AD99517003FC87E = {
206 | CreatedOnToolsVersion = 6.2;
207 | TestTargetID = 13B07F861A680F5B00A75B9A;
208 | };
209 | 13B07F861A680F5B00A75B9A = {
210 | LastSwiftMigration = 1120;
211 | };
212 | };
213 | };
214 | buildConfigurationList = 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "ReactNativeTypeScriptExamples" */;
215 | compatibilityVersion = "Xcode 12.0";
216 | developmentRegion = en;
217 | hasScannedForEncodings = 0;
218 | knownRegions = (
219 | en,
220 | Base,
221 | );
222 | mainGroup = 83CBB9F61A601CBA00E9B192;
223 | productRefGroup = 83CBBA001A601CBA00E9B192 /* Products */;
224 | projectDirPath = "";
225 | projectRoot = "";
226 | targets = (
227 | 13B07F861A680F5B00A75B9A /* ReactNativeTypeScriptExamples */,
228 | 00E356ED1AD99517003FC87E /* ReactNativeTypeScriptExamplesTests */,
229 | );
230 | };
231 | /* End PBXProject section */
232 |
233 | /* Begin PBXResourcesBuildPhase section */
234 | 00E356EC1AD99517003FC87E /* Resources */ = {
235 | isa = PBXResourcesBuildPhase;
236 | buildActionMask = 2147483647;
237 | files = (
238 | );
239 | runOnlyForDeploymentPostprocessing = 0;
240 | };
241 | 13B07F8E1A680F5B00A75B9A /* Resources */ = {
242 | isa = PBXResourcesBuildPhase;
243 | buildActionMask = 2147483647;
244 | files = (
245 | 81AB9BB82411601600AC10FF /* LaunchScreen.storyboard in Resources */,
246 | 13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */,
247 | );
248 | runOnlyForDeploymentPostprocessing = 0;
249 | };
250 | /* End PBXResourcesBuildPhase section */
251 |
252 | /* Begin PBXShellScriptBuildPhase section */
253 | 00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */ = {
254 | isa = PBXShellScriptBuildPhase;
255 | buildActionMask = 2147483647;
256 | files = (
257 | );
258 | inputPaths = (
259 | "$(SRCROOT)/.xcode.env.local",
260 | "$(SRCROOT)/.xcode.env",
261 | );
262 | name = "Bundle React Native code and images";
263 | outputPaths = (
264 | );
265 | runOnlyForDeploymentPostprocessing = 0;
266 | shellPath = /bin/sh;
267 | shellScript = "set -e\n\nWITH_ENVIRONMENT=\"../node_modules/react-native/scripts/xcode/with-environment.sh\"\nREACT_NATIVE_XCODE=\"../node_modules/react-native/scripts/react-native-xcode.sh\"\n\n/bin/sh -c \"$WITH_ENVIRONMENT $REACT_NATIVE_XCODE\"\n";
268 | };
269 | 00EEFC60759A1932668264C0 /* [CP] Embed Pods Frameworks */ = {
270 | isa = PBXShellScriptBuildPhase;
271 | buildActionMask = 2147483647;
272 | files = (
273 | );
274 | inputFileListPaths = (
275 | "${PODS_ROOT}/Target Support Files/Pods-ReactNativeTypeScriptExamples/Pods-ReactNativeTypeScriptExamples-frameworks-${CONFIGURATION}-input-files.xcfilelist",
276 | );
277 | name = "[CP] Embed Pods Frameworks";
278 | outputFileListPaths = (
279 | "${PODS_ROOT}/Target Support Files/Pods-ReactNativeTypeScriptExamples/Pods-ReactNativeTypeScriptExamples-frameworks-${CONFIGURATION}-output-files.xcfilelist",
280 | );
281 | runOnlyForDeploymentPostprocessing = 0;
282 | shellPath = /bin/sh;
283 | shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-ReactNativeTypeScriptExamples/Pods-ReactNativeTypeScriptExamples-frameworks.sh\"\n";
284 | showEnvVarsInLog = 0;
285 | };
286 | A55EABD7B0C7F3A422A6CC61 /* [CP] Check Pods Manifest.lock */ = {
287 | isa = PBXShellScriptBuildPhase;
288 | buildActionMask = 2147483647;
289 | files = (
290 | );
291 | inputFileListPaths = (
292 | );
293 | inputPaths = (
294 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
295 | "${PODS_ROOT}/Manifest.lock",
296 | );
297 | name = "[CP] Check Pods Manifest.lock";
298 | outputFileListPaths = (
299 | );
300 | outputPaths = (
301 | "$(DERIVED_FILE_DIR)/Pods-ReactNativeTypeScriptExamples-ReactNativeTypeScriptExamplesTests-checkManifestLockResult.txt",
302 | );
303 | runOnlyForDeploymentPostprocessing = 0;
304 | shellPath = /bin/sh;
305 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
306 | showEnvVarsInLog = 0;
307 | };
308 | C38B50BA6285516D6DCD4F65 /* [CP] Check Pods Manifest.lock */ = {
309 | isa = PBXShellScriptBuildPhase;
310 | buildActionMask = 2147483647;
311 | files = (
312 | );
313 | inputFileListPaths = (
314 | );
315 | inputPaths = (
316 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
317 | "${PODS_ROOT}/Manifest.lock",
318 | );
319 | name = "[CP] Check Pods Manifest.lock";
320 | outputFileListPaths = (
321 | );
322 | outputPaths = (
323 | "$(DERIVED_FILE_DIR)/Pods-ReactNativeTypeScriptExamples-checkManifestLockResult.txt",
324 | );
325 | runOnlyForDeploymentPostprocessing = 0;
326 | shellPath = /bin/sh;
327 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
328 | showEnvVarsInLog = 0;
329 | };
330 | C59DA0FBD6956966B86A3779 /* [CP] Embed Pods Frameworks */ = {
331 | isa = PBXShellScriptBuildPhase;
332 | buildActionMask = 2147483647;
333 | files = (
334 | );
335 | inputFileListPaths = (
336 | "${PODS_ROOT}/Target Support Files/Pods-ReactNativeTypeScriptExamples-ReactNativeTypeScriptExamplesTests/Pods-ReactNativeTypeScriptExamples-ReactNativeTypeScriptExamplesTests-frameworks-${CONFIGURATION}-input-files.xcfilelist",
337 | );
338 | name = "[CP] Embed Pods Frameworks";
339 | outputFileListPaths = (
340 | "${PODS_ROOT}/Target Support Files/Pods-ReactNativeTypeScriptExamples-ReactNativeTypeScriptExamplesTests/Pods-ReactNativeTypeScriptExamples-ReactNativeTypeScriptExamplesTests-frameworks-${CONFIGURATION}-output-files.xcfilelist",
341 | );
342 | runOnlyForDeploymentPostprocessing = 0;
343 | shellPath = /bin/sh;
344 | shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-ReactNativeTypeScriptExamples-ReactNativeTypeScriptExamplesTests/Pods-ReactNativeTypeScriptExamples-ReactNativeTypeScriptExamplesTests-frameworks.sh\"\n";
345 | showEnvVarsInLog = 0;
346 | };
347 | E235C05ADACE081382539298 /* [CP] Copy Pods Resources */ = {
348 | isa = PBXShellScriptBuildPhase;
349 | buildActionMask = 2147483647;
350 | files = (
351 | );
352 | inputFileListPaths = (
353 | "${PODS_ROOT}/Target Support Files/Pods-ReactNativeTypeScriptExamples/Pods-ReactNativeTypeScriptExamples-resources-${CONFIGURATION}-input-files.xcfilelist",
354 | );
355 | name = "[CP] Copy Pods Resources";
356 | outputFileListPaths = (
357 | "${PODS_ROOT}/Target Support Files/Pods-ReactNativeTypeScriptExamples/Pods-ReactNativeTypeScriptExamples-resources-${CONFIGURATION}-output-files.xcfilelist",
358 | );
359 | runOnlyForDeploymentPostprocessing = 0;
360 | shellPath = /bin/sh;
361 | shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-ReactNativeTypeScriptExamples/Pods-ReactNativeTypeScriptExamples-resources.sh\"\n";
362 | showEnvVarsInLog = 0;
363 | };
364 | F6A41C54EA430FDDC6A6ED99 /* [CP] Copy Pods Resources */ = {
365 | isa = PBXShellScriptBuildPhase;
366 | buildActionMask = 2147483647;
367 | files = (
368 | );
369 | inputFileListPaths = (
370 | "${PODS_ROOT}/Target Support Files/Pods-ReactNativeTypeScriptExamples-ReactNativeTypeScriptExamplesTests/Pods-ReactNativeTypeScriptExamples-ReactNativeTypeScriptExamplesTests-resources-${CONFIGURATION}-input-files.xcfilelist",
371 | );
372 | name = "[CP] Copy Pods Resources";
373 | outputFileListPaths = (
374 | "${PODS_ROOT}/Target Support Files/Pods-ReactNativeTypeScriptExamples-ReactNativeTypeScriptExamplesTests/Pods-ReactNativeTypeScriptExamples-ReactNativeTypeScriptExamplesTests-resources-${CONFIGURATION}-output-files.xcfilelist",
375 | );
376 | runOnlyForDeploymentPostprocessing = 0;
377 | shellPath = /bin/sh;
378 | shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-ReactNativeTypeScriptExamples-ReactNativeTypeScriptExamplesTests/Pods-ReactNativeTypeScriptExamples-ReactNativeTypeScriptExamplesTests-resources.sh\"\n";
379 | showEnvVarsInLog = 0;
380 | };
381 | FD10A7F022414F080027D42C /* Start Packager */ = {
382 | isa = PBXShellScriptBuildPhase;
383 | buildActionMask = 2147483647;
384 | files = (
385 | );
386 | inputFileListPaths = (
387 | );
388 | inputPaths = (
389 | );
390 | name = "Start Packager";
391 | outputFileListPaths = (
392 | );
393 | outputPaths = (
394 | );
395 | runOnlyForDeploymentPostprocessing = 0;
396 | shellPath = /bin/sh;
397 | shellScript = "export RCT_METRO_PORT=\"${RCT_METRO_PORT:=8081}\"\necho \"export RCT_METRO_PORT=${RCT_METRO_PORT}\" > \"${SRCROOT}/../node_modules/react-native/scripts/.packager.env\"\nif [ -z \"${RCT_NO_LAUNCH_PACKAGER+xxx}\" ] ; then\n if nc -w 5 -z localhost ${RCT_METRO_PORT} ; then\n if ! curl -s \"http://localhost:${RCT_METRO_PORT}/status\" | grep -q \"packager-status:running\" ; then\n echo \"Port ${RCT_METRO_PORT} already in use, packager is either not running or not running correctly\"\n exit 2\n fi\n else\n open \"$SRCROOT/../node_modules/react-native/scripts/launchPackager.command\" || echo \"Can't start packager automatically\"\n fi\nfi\n";
398 | showEnvVarsInLog = 0;
399 | };
400 | /* End PBXShellScriptBuildPhase section */
401 |
402 | /* Begin PBXSourcesBuildPhase section */
403 | 00E356EA1AD99517003FC87E /* Sources */ = {
404 | isa = PBXSourcesBuildPhase;
405 | buildActionMask = 2147483647;
406 | files = (
407 | 00E356F31AD99517003FC87E /* ReactNativeTypeScriptExamplesTests.m in Sources */,
408 | );
409 | runOnlyForDeploymentPostprocessing = 0;
410 | };
411 | 13B07F871A680F5B00A75B9A /* Sources */ = {
412 | isa = PBXSourcesBuildPhase;
413 | buildActionMask = 2147483647;
414 | files = (
415 | 13B07FBC1A68108700A75B9A /* AppDelegate.mm in Sources */,
416 | 13B07FC11A68108700A75B9A /* main.m in Sources */,
417 | );
418 | runOnlyForDeploymentPostprocessing = 0;
419 | };
420 | /* End PBXSourcesBuildPhase section */
421 |
422 | /* Begin PBXTargetDependency section */
423 | 00E356F51AD99517003FC87E /* PBXTargetDependency */ = {
424 | isa = PBXTargetDependency;
425 | target = 13B07F861A680F5B00A75B9A /* ReactNativeTypeScriptExamples */;
426 | targetProxy = 00E356F41AD99517003FC87E /* PBXContainerItemProxy */;
427 | };
428 | /* End PBXTargetDependency section */
429 |
430 | /* Begin XCBuildConfiguration section */
431 | 00E356F61AD99517003FC87E /* Debug */ = {
432 | isa = XCBuildConfiguration;
433 | baseConfigurationReference = 5B7EB9410499542E8C5724F5 /* Pods-ReactNativeTypeScriptExamples-ReactNativeTypeScriptExamplesTests.debug.xcconfig */;
434 | buildSettings = {
435 | BUNDLE_LOADER = "$(TEST_HOST)";
436 | GCC_PREPROCESSOR_DEFINITIONS = (
437 | "DEBUG=1",
438 | "$(inherited)",
439 | );
440 | INFOPLIST_FILE = ReactNativeTypeScriptExamplesTests/Info.plist;
441 | IPHONEOS_DEPLOYMENT_TARGET = 12.4;
442 | LD_RUNPATH_SEARCH_PATHS = (
443 | "$(inherited)",
444 | "@executable_path/Frameworks",
445 | "@loader_path/Frameworks",
446 | );
447 | OTHER_LDFLAGS = (
448 | "-ObjC",
449 | "-lc++",
450 | "$(inherited)",
451 | );
452 | PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)";
453 | PRODUCT_NAME = "$(TARGET_NAME)";
454 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/ReactNativeTypeScriptExamples.app/ReactNativeTypeScriptExamples";
455 | };
456 | name = Debug;
457 | };
458 | 00E356F71AD99517003FC87E /* Release */ = {
459 | isa = XCBuildConfiguration;
460 | baseConfigurationReference = 89C6BE57DB24E9ADA2F236DE /* Pods-ReactNativeTypeScriptExamples-ReactNativeTypeScriptExamplesTests.release.xcconfig */;
461 | buildSettings = {
462 | BUNDLE_LOADER = "$(TEST_HOST)";
463 | COPY_PHASE_STRIP = NO;
464 | INFOPLIST_FILE = ReactNativeTypeScriptExamplesTests/Info.plist;
465 | IPHONEOS_DEPLOYMENT_TARGET = 12.4;
466 | LD_RUNPATH_SEARCH_PATHS = (
467 | "$(inherited)",
468 | "@executable_path/Frameworks",
469 | "@loader_path/Frameworks",
470 | );
471 | OTHER_LDFLAGS = (
472 | "-ObjC",
473 | "-lc++",
474 | "$(inherited)",
475 | );
476 | PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)";
477 | PRODUCT_NAME = "$(TARGET_NAME)";
478 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/ReactNativeTypeScriptExamples.app/ReactNativeTypeScriptExamples";
479 | };
480 | name = Release;
481 | };
482 | 13B07F941A680F5B00A75B9A /* Debug */ = {
483 | isa = XCBuildConfiguration;
484 | baseConfigurationReference = 3B4392A12AC88292D35C810B /* Pods-ReactNativeTypeScriptExamples.debug.xcconfig */;
485 | buildSettings = {
486 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
487 | CLANG_ENABLE_MODULES = YES;
488 | CURRENT_PROJECT_VERSION = 1;
489 | ENABLE_BITCODE = NO;
490 | INFOPLIST_FILE = ReactNativeTypeScriptExamples/Info.plist;
491 | LD_RUNPATH_SEARCH_PATHS = (
492 | "$(inherited)",
493 | "@executable_path/Frameworks",
494 | );
495 | OTHER_LDFLAGS = (
496 | "$(inherited)",
497 | "-ObjC",
498 | "-lc++",
499 | );
500 | PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)";
501 | PRODUCT_NAME = ReactNativeTypeScriptExamples;
502 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
503 | SWIFT_VERSION = 5.0;
504 | VERSIONING_SYSTEM = "apple-generic";
505 | };
506 | name = Debug;
507 | };
508 | 13B07F951A680F5B00A75B9A /* Release */ = {
509 | isa = XCBuildConfiguration;
510 | baseConfigurationReference = 5709B34CF0A7D63546082F79 /* Pods-ReactNativeTypeScriptExamples.release.xcconfig */;
511 | buildSettings = {
512 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
513 | CLANG_ENABLE_MODULES = YES;
514 | CURRENT_PROJECT_VERSION = 1;
515 | INFOPLIST_FILE = ReactNativeTypeScriptExamples/Info.plist;
516 | LD_RUNPATH_SEARCH_PATHS = (
517 | "$(inherited)",
518 | "@executable_path/Frameworks",
519 | );
520 | OTHER_LDFLAGS = (
521 | "$(inherited)",
522 | "-ObjC",
523 | "-lc++",
524 | );
525 | PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)";
526 | PRODUCT_NAME = ReactNativeTypeScriptExamples;
527 | SWIFT_VERSION = 5.0;
528 | VERSIONING_SYSTEM = "apple-generic";
529 | };
530 | name = Release;
531 | };
532 | 83CBBA201A601CBA00E9B192 /* Debug */ = {
533 | isa = XCBuildConfiguration;
534 | buildSettings = {
535 | ALWAYS_SEARCH_USER_PATHS = NO;
536 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
537 | CLANG_CXX_LANGUAGE_STANDARD = "c++17";
538 | CLANG_CXX_LIBRARY = "libc++";
539 | CLANG_ENABLE_MODULES = YES;
540 | CLANG_ENABLE_OBJC_ARC = YES;
541 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
542 | CLANG_WARN_BOOL_CONVERSION = YES;
543 | CLANG_WARN_COMMA = YES;
544 | CLANG_WARN_CONSTANT_CONVERSION = YES;
545 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
546 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
547 | CLANG_WARN_EMPTY_BODY = YES;
548 | CLANG_WARN_ENUM_CONVERSION = YES;
549 | CLANG_WARN_INFINITE_RECURSION = YES;
550 | CLANG_WARN_INT_CONVERSION = YES;
551 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
552 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
553 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
554 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
555 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
556 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
557 | CLANG_WARN_STRICT_PROTOTYPES = YES;
558 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
559 | CLANG_WARN_UNREACHABLE_CODE = YES;
560 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
561 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
562 | COPY_PHASE_STRIP = NO;
563 | ENABLE_STRICT_OBJC_MSGSEND = YES;
564 | ENABLE_TESTABILITY = YES;
565 | "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = "";
566 | GCC_C_LANGUAGE_STANDARD = gnu99;
567 | GCC_DYNAMIC_NO_PIC = NO;
568 | GCC_NO_COMMON_BLOCKS = YES;
569 | GCC_OPTIMIZATION_LEVEL = 0;
570 | GCC_PREPROCESSOR_DEFINITIONS = (
571 | "DEBUG=1",
572 | "$(inherited)",
573 | );
574 | GCC_SYMBOLS_PRIVATE_EXTERN = NO;
575 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
576 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
577 | GCC_WARN_UNDECLARED_SELECTOR = YES;
578 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
579 | GCC_WARN_UNUSED_FUNCTION = YES;
580 | GCC_WARN_UNUSED_VARIABLE = YES;
581 | IPHONEOS_DEPLOYMENT_TARGET = 12.4;
582 | LD_RUNPATH_SEARCH_PATHS = (
583 | /usr/lib/swift,
584 | "$(inherited)",
585 | );
586 | LIBRARY_SEARCH_PATHS = (
587 | "\"$(SDKROOT)/usr/lib/swift\"",
588 | "\"$(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME)\"",
589 | "\"$(inherited)\"",
590 | );
591 | MTL_ENABLE_DEBUG_INFO = YES;
592 | ONLY_ACTIVE_ARCH = YES;
593 | OTHER_CPLUSPLUSFLAGS = (
594 | "$(OTHER_CFLAGS)",
595 | "-DFOLLY_NO_CONFIG",
596 | "-DFOLLY_MOBILE=1",
597 | "-DFOLLY_USE_LIBCPP=1",
598 | );
599 | SDKROOT = iphoneos;
600 | };
601 | name = Debug;
602 | };
603 | 83CBBA211A601CBA00E9B192 /* Release */ = {
604 | isa = XCBuildConfiguration;
605 | buildSettings = {
606 | ALWAYS_SEARCH_USER_PATHS = NO;
607 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
608 | CLANG_CXX_LANGUAGE_STANDARD = "c++17";
609 | CLANG_CXX_LIBRARY = "libc++";
610 | CLANG_ENABLE_MODULES = YES;
611 | CLANG_ENABLE_OBJC_ARC = YES;
612 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
613 | CLANG_WARN_BOOL_CONVERSION = YES;
614 | CLANG_WARN_COMMA = YES;
615 | CLANG_WARN_CONSTANT_CONVERSION = YES;
616 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
617 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
618 | CLANG_WARN_EMPTY_BODY = YES;
619 | CLANG_WARN_ENUM_CONVERSION = YES;
620 | CLANG_WARN_INFINITE_RECURSION = YES;
621 | CLANG_WARN_INT_CONVERSION = YES;
622 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
623 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
624 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
625 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
626 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
627 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
628 | CLANG_WARN_STRICT_PROTOTYPES = YES;
629 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
630 | CLANG_WARN_UNREACHABLE_CODE = YES;
631 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
632 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
633 | COPY_PHASE_STRIP = YES;
634 | ENABLE_NS_ASSERTIONS = NO;
635 | ENABLE_STRICT_OBJC_MSGSEND = YES;
636 | "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = "";
637 | GCC_C_LANGUAGE_STANDARD = gnu99;
638 | GCC_NO_COMMON_BLOCKS = YES;
639 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
640 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
641 | GCC_WARN_UNDECLARED_SELECTOR = YES;
642 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
643 | GCC_WARN_UNUSED_FUNCTION = YES;
644 | GCC_WARN_UNUSED_VARIABLE = YES;
645 | IPHONEOS_DEPLOYMENT_TARGET = 12.4;
646 | LD_RUNPATH_SEARCH_PATHS = (
647 | /usr/lib/swift,
648 | "$(inherited)",
649 | );
650 | LIBRARY_SEARCH_PATHS = (
651 | "\"$(SDKROOT)/usr/lib/swift\"",
652 | "\"$(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME)\"",
653 | "\"$(inherited)\"",
654 | );
655 | MTL_ENABLE_DEBUG_INFO = NO;
656 | OTHER_CPLUSPLUSFLAGS = (
657 | "$(OTHER_CFLAGS)",
658 | "-DFOLLY_NO_CONFIG",
659 | "-DFOLLY_MOBILE=1",
660 | "-DFOLLY_USE_LIBCPP=1",
661 | );
662 | SDKROOT = iphoneos;
663 | VALIDATE_PRODUCT = YES;
664 | };
665 | name = Release;
666 | };
667 | /* End XCBuildConfiguration section */
668 |
669 | /* Begin XCConfigurationList section */
670 | 00E357021AD99517003FC87E /* Build configuration list for PBXNativeTarget "ReactNativeTypeScriptExamplesTests" */ = {
671 | isa = XCConfigurationList;
672 | buildConfigurations = (
673 | 00E356F61AD99517003FC87E /* Debug */,
674 | 00E356F71AD99517003FC87E /* Release */,
675 | );
676 | defaultConfigurationIsVisible = 0;
677 | defaultConfigurationName = Release;
678 | };
679 | 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "ReactNativeTypeScriptExamples" */ = {
680 | isa = XCConfigurationList;
681 | buildConfigurations = (
682 | 13B07F941A680F5B00A75B9A /* Debug */,
683 | 13B07F951A680F5B00A75B9A /* Release */,
684 | );
685 | defaultConfigurationIsVisible = 0;
686 | defaultConfigurationName = Release;
687 | };
688 | 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "ReactNativeTypeScriptExamples" */ = {
689 | isa = XCConfigurationList;
690 | buildConfigurations = (
691 | 83CBBA201A601CBA00E9B192 /* Debug */,
692 | 83CBBA211A601CBA00E9B192 /* Release */,
693 | );
694 | defaultConfigurationIsVisible = 0;
695 | defaultConfigurationName = Release;
696 | };
697 | /* End XCConfigurationList section */
698 | };
699 | rootObject = 83CBB9F71A601CBA00E9B192 /* Project object */;
700 | }
701 |
--------------------------------------------------------------------------------
/ios/ReactNativeTypescriptExamples.xcodeproj/xcshareddata/xcschemes/ReactNativeTypescriptExamples.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
33 |
39 |
40 |
41 |
42 |
43 |
53 |
55 |
61 |
62 |
63 |
64 |
70 |
72 |
78 |
79 |
80 |
81 |
83 |
84 |
87 |
88 |
89 |
--------------------------------------------------------------------------------
/ios/ReactNativeTypescriptExamples/AppDelegate.h:
--------------------------------------------------------------------------------
1 | #import
2 | #import
3 |
4 | @interface AppDelegate : UIResponder
5 |
6 | @property (nonatomic, strong) UIWindow *window;
7 |
8 | @end
9 |
--------------------------------------------------------------------------------
/ios/ReactNativeTypescriptExamples/AppDelegate.mm:
--------------------------------------------------------------------------------
1 | #import "AppDelegate.h"
2 |
3 | #import
4 | #import
5 | #import
6 |
7 | #import
8 |
9 | #if RCT_NEW_ARCH_ENABLED
10 | #import
11 | #import
12 | #import
13 | #import
14 | #import
15 | #import
16 |
17 | #import
18 |
19 | static NSString *const kRNConcurrentRoot = @"concurrentRoot";
20 |
21 | @interface AppDelegate () {
22 | RCTTurboModuleManager *_turboModuleManager;
23 | RCTSurfacePresenterBridgeAdapter *_bridgeAdapter;
24 | std::shared_ptr _reactNativeConfig;
25 | facebook::react::ContextContainer::Shared _contextContainer;
26 | }
27 | @end
28 | #endif
29 |
30 | @implementation AppDelegate
31 |
32 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
33 | {
34 | RCTAppSetupPrepareApp(application);
35 |
36 | RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions];
37 |
38 | #if RCT_NEW_ARCH_ENABLED
39 | _contextContainer = std::make_shared();
40 | _reactNativeConfig = std::make_shared();
41 | _contextContainer->insert("ReactNativeConfig", _reactNativeConfig);
42 | _bridgeAdapter = [[RCTSurfacePresenterBridgeAdapter alloc] initWithBridge:bridge contextContainer:_contextContainer];
43 | bridge.surfacePresenter = _bridgeAdapter.surfacePresenter;
44 | #endif
45 |
46 | NSDictionary *initProps = [self prepareInitialProps];
47 | UIView *rootView = RCTAppSetupDefaultRootView(bridge, @"ReactNativeTypeScriptExamples", initProps);
48 |
49 | if (@available(iOS 13.0, *)) {
50 | rootView.backgroundColor = [UIColor systemBackgroundColor];
51 | } else {
52 | rootView.backgroundColor = [UIColor whiteColor];
53 | }
54 |
55 | self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
56 | UIViewController *rootViewController = [UIViewController new];
57 | rootViewController.view = rootView;
58 | self.window.rootViewController = rootViewController;
59 | [self.window makeKeyAndVisible];
60 | return YES;
61 | }
62 |
63 | /// This method controls whether the `concurrentRoot`feature of React18 is turned on or off.
64 | ///
65 | /// @see: https://reactjs.org/blog/2022/03/29/react-v18.html
66 | /// @note: This requires to be rendering on Fabric (i.e. on the New Architecture).
67 | /// @return: `true` if the `concurrentRoot` feture is enabled. Otherwise, it returns `false`.
68 | - (BOOL)concurrentRootEnabled
69 | {
70 | // Switch this bool to turn on and off the concurrent root
71 | return true;
72 | }
73 |
74 | - (NSDictionary *)prepareInitialProps
75 | {
76 | NSMutableDictionary *initProps = [NSMutableDictionary new];
77 |
78 | #ifdef RCT_NEW_ARCH_ENABLED
79 | initProps[kRNConcurrentRoot] = @([self concurrentRootEnabled]);
80 | #endif
81 |
82 | return initProps;
83 | }
84 |
85 | - (NSURL *)sourceURLForBridge:(RCTBridge *)bridge
86 | {
87 | #if DEBUG
88 | return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index"];
89 | #else
90 | return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
91 | #endif
92 | }
93 |
94 | #if RCT_NEW_ARCH_ENABLED
95 |
96 | #pragma mark - RCTCxxBridgeDelegate
97 |
98 | - (std::unique_ptr)jsExecutorFactoryForBridge:(RCTBridge *)bridge
99 | {
100 | _turboModuleManager = [[RCTTurboModuleManager alloc] initWithBridge:bridge
101 | delegate:self
102 | jsInvoker:bridge.jsCallInvoker];
103 | return RCTAppSetupDefaultJsExecutorFactory(bridge, _turboModuleManager);
104 | }
105 |
106 | #pragma mark RCTTurboModuleManagerDelegate
107 |
108 | - (Class)getModuleClassFromName:(const char *)name
109 | {
110 | return RCTCoreModulesClassProvider(name);
111 | }
112 |
113 | - (std::shared_ptr)getTurboModule:(const std::string &)name
114 | jsInvoker:(std::shared_ptr)jsInvoker
115 | {
116 | return nullptr;
117 | }
118 |
119 | - (std::shared_ptr)getTurboModule:(const std::string &)name
120 | initParams:
121 | (const facebook::react::ObjCTurboModule::InitParams &)params
122 | {
123 | return nullptr;
124 | }
125 |
126 | - (id)getModuleInstanceFromClass:(Class)moduleClass
127 | {
128 | return RCTAppSetupDefaultModuleFromClass(moduleClass);
129 | }
130 |
131 | #endif
132 |
133 | @end
134 |
--------------------------------------------------------------------------------
/ios/ReactNativeTypescriptExamples/Images.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "scale" : "2x",
6 | "size" : "20x20"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "scale" : "3x",
11 | "size" : "20x20"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "scale" : "2x",
16 | "size" : "29x29"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "scale" : "3x",
21 | "size" : "29x29"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "scale" : "2x",
26 | "size" : "40x40"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "scale" : "3x",
31 | "size" : "40x40"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "scale" : "2x",
36 | "size" : "60x60"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "scale" : "3x",
41 | "size" : "60x60"
42 | },
43 | {
44 | "idiom" : "ios-marketing",
45 | "scale" : "1x",
46 | "size" : "1024x1024"
47 | }
48 | ],
49 | "info" : {
50 | "author" : "xcode",
51 | "version" : 1
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/ios/ReactNativeTypescriptExamples/Images.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/ios/ReactNativeTypescriptExamples/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleDisplayName
8 | ReactNativeTypeScriptExamples
9 | CFBundleExecutable
10 | $(EXECUTABLE_NAME)
11 | CFBundleIdentifier
12 | $(PRODUCT_BUNDLE_IDENTIFIER)
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | $(PRODUCT_NAME)
17 | CFBundlePackageType
18 | APPL
19 | CFBundleShortVersionString
20 | 1.0
21 | CFBundleSignature
22 | ????
23 | CFBundleVersion
24 | 1
25 | LSRequiresIPhoneOS
26 |
27 | NSAppTransportSecurity
28 |
29 | NSExceptionDomains
30 |
31 | localhost
32 |
33 | NSExceptionAllowsInsecureHTTPLoads
34 |
35 |
36 |
37 |
38 | NSLocationWhenInUseUsageDescription
39 |
40 | UILaunchStoryboardName
41 | LaunchScreen
42 | UIRequiredDeviceCapabilities
43 |
44 | armv7
45 |
46 | UISupportedInterfaceOrientations
47 |
48 | UIInterfaceOrientationPortrait
49 | UIInterfaceOrientationLandscapeLeft
50 | UIInterfaceOrientationLandscapeRight
51 |
52 | UIViewControllerBasedStatusBarAppearance
53 |
54 | UIAppFonts
55 |
56 | FontAwesome5_Brands.ttf
57 | FontAwesome5_Regular.ttf
58 | FontAwesome5_Solid.ttf
59 | Ionicons.ttf
60 |
61 | NSLocationAlwaysUsageDescription
62 | Get your location to booking car
63 | NSLocationWhenInUseUsageDescription
64 | Get your location to booking car
65 |
66 |
67 |
--------------------------------------------------------------------------------
/ios/ReactNativeTypescriptExamples/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/ios/ReactNativeTypescriptExamples/main.m:
--------------------------------------------------------------------------------
1 | #import
2 |
3 | #import "AppDelegate.h"
4 |
5 | int main(int argc, char *argv[])
6 | {
7 | @autoreleasepool {
8 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/ios/ReactNativeTypescriptExamplesTests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 |
24 |
25 |
--------------------------------------------------------------------------------
/ios/ReactNativeTypescriptExamplesTests/ReactNativeTypescriptExamplesTests.m:
--------------------------------------------------------------------------------
1 | #import
2 | #import
3 |
4 | #import
5 | #import
6 |
7 | #define TIMEOUT_SECONDS 600
8 | #define TEXT_TO_LOOK_FOR @"Welcome to React"
9 |
10 | @interface ReactNativeTypeScriptExamplesTests : XCTestCase
11 |
12 | @end
13 |
14 | @implementation ReactNativeTypeScriptExamplesTests
15 |
16 | - (BOOL)findSubviewInView:(UIView *)view matching:(BOOL (^)(UIView *view))test
17 | {
18 | if (test(view)) {
19 | return YES;
20 | }
21 | for (UIView *subview in [view subviews]) {
22 | if ([self findSubviewInView:subview matching:test]) {
23 | return YES;
24 | }
25 | }
26 | return NO;
27 | }
28 |
29 | - (void)testRendersWelcomeScreen
30 | {
31 | UIViewController *vc = [[[RCTSharedApplication() delegate] window] rootViewController];
32 | NSDate *date = [NSDate dateWithTimeIntervalSinceNow:TIMEOUT_SECONDS];
33 | BOOL foundElement = NO;
34 |
35 | __block NSString *redboxError = nil;
36 | #ifdef DEBUG
37 | RCTSetLogFunction(
38 | ^(RCTLogLevel level, RCTLogSource source, NSString *fileName, NSNumber *lineNumber, NSString *message) {
39 | if (level >= RCTLogLevelError) {
40 | redboxError = message;
41 | }
42 | });
43 | #endif
44 |
45 | while ([date timeIntervalSinceNow] > 0 && !foundElement && !redboxError) {
46 | [[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
47 | [[NSRunLoop mainRunLoop] runMode:NSRunLoopCommonModes beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
48 |
49 | foundElement = [self findSubviewInView:vc.view
50 | matching:^BOOL(UIView *view) {
51 | if ([view.accessibilityLabel isEqualToString:TEXT_TO_LOOK_FOR]) {
52 | return YES;
53 | }
54 | return NO;
55 | }];
56 | }
57 |
58 | #ifdef DEBUG
59 | RCTSetLogFunction(RCTDefaultLogFunction);
60 | #endif
61 |
62 | XCTAssertNil(redboxError, @"RedBox error: %@", redboxError);
63 | XCTAssertTrue(foundElement, @"Couldn't find element with text '%@' in %d seconds", TEXT_TO_LOOK_FOR, TIMEOUT_SECONDS);
64 | }
65 |
66 | @end
67 |
--------------------------------------------------------------------------------
/metro.config.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Metro configuration for React Native
3 | * https://github.com/facebook/react-native
4 | *
5 | * @format
6 | */
7 |
8 | module.exports = {
9 | transformer: {
10 | getTransformOptions: async () => ({
11 | transform: {
12 | experimentalImportSupport: false,
13 | inlineRequires: false,
14 | },
15 | }),
16 | },
17 | };
18 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ReactNativeTypeScriptExamples",
3 | "version": "0.0.1",
4 | "private": true,
5 | "scripts": {
6 | "android": "react-native run-android",
7 | "ios": "react-native run-ios",
8 | "start": "react-native start",
9 | "test": "jest",
10 | "lint": "eslint . --ext .js,.jsx,.ts,.tsx"
11 | },
12 | "dependencies": {
13 | "@react-native-community/async-storage": "^1.12.1",
14 | "@react-native-community/masked-view": "^0.1.11",
15 | "@react-navigation/drawer": "^6.5.5",
16 | "@react-navigation/native": "^6.1.1",
17 | "@react-navigation/stack": "^6.3.9",
18 | "apisauce": "^2.1.6",
19 | "lodash": "^4.17.21",
20 | "mobx": "^6.3.5",
21 | "mobx-react-lite": "^3.2.1",
22 | "native-base": "^3.4.25",
23 | "react": "^18.2.0",
24 | "react-native": "^0.70.6",
25 | "react-native-gesture-handler": "^2.8.0",
26 | "react-native-maps": "^1.3.2",
27 | "react-native-maps-directions": "^1.8.0",
28 | "react-native-reanimated": "^2.13.0",
29 | "react-native-safe-area-context": "3.3.2",
30 | "react-native-screens": "^3.18.2",
31 | "react-native-svg": "12.1.1",
32 | "react-native-swipe-list-view": "^3.2.9",
33 | "react-native-vector-icons": "^9.2.0",
34 | "react-native-webview": "^11.26.0"
35 | },
36 | "devDependencies": {
37 | "@babel/core": "^7.15.8",
38 | "@babel/runtime": "^7.15.4",
39 | "@react-native-community/eslint-config": "^2.0.0",
40 | "@tsconfig/react-native": "^2.0.2",
41 | "@types/jest": "^26.0.23",
42 | "@types/react": "^18.0.21",
43 | "@types/react-native": "^0.70.6",
44 | "@types/react-test-renderer": "^18.0.0",
45 | "@typescript-eslint/eslint-plugin": "^5.37.0",
46 | "@typescript-eslint/parser": "^5.37.0",
47 | "babel-jest": "^26.6.3",
48 | "eslint": "^7.32.0",
49 | "jest": "^26.6.3",
50 | "metro-react-native-babel-preset": "^0.72.3",
51 | "react-test-renderer": "^18.2.0",
52 | "typescript": "^4.8.3"
53 | },
54 | "jest": {
55 | "preset": "react-native",
56 | "moduleFileExtensions": [
57 | "ts",
58 | "tsx",
59 | "js",
60 | "jsx",
61 | "json",
62 | "node"
63 | ]
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | // prettier-ignore
2 | {
3 | "extends": "@tsconfig/react-native/tsconfig.json", /* Recommended React Native TSConfig base */
4 | "compilerOptions": {
5 | /* Visit https://aka.ms/tsconfig.json to read more about this file */
6 |
7 | /* Completeness */
8 | "skipLibCheck": true /* Skip type checking all .d.ts files. */
9 | }
10 | }
11 |
--------------------------------------------------------------------------------