From 26eff3faf5a0aaef5d70fc64757bc35edec0a51d Mon Sep 17 00:00:00 2001 From: Abishek Bashyal Date: Thu, 19 Oct 2023 13:02:52 +0545 Subject: [PATCH] enable react native sdk (#716) * feat: react native sdk setup done * refactor: precommit fix * refactor: pgp and crypto helper functions * feat: user functions for react-native * feat: intent functions for react-native * test: add rn sdk and tests in example app * feat: created function for chat decrypt, create group, update group for rn-sdk * fix: example app create user * chore: resolve conflict issues * chore: add random functions to create/update grp * chore: fix linting issues * chore: add test for rn approve req * feat: rn-sdk * feat: rn sdk done --------- Co-authored-by: kalashshah <202051096@iiitvadodara.ac.in> Co-authored-by: KlausMikhaelson Co-authored-by: Satyam <100528412+KlausMikhaelson@users.noreply.github.com> Co-authored-by: Kalash Shah <81062983+kalashshah@users.noreply.github.com> --- lefthook.yml | 35 + packages/reactnative/.babelrc | 11 - packages/reactnative/.editorconfig | 15 + packages/reactnative/.eslintrc.json | 20 - packages/reactnative/.gitattributes | 3 + packages/reactnative/.gitignore | 70 ++ packages/reactnative/.nvmrc | 1 + packages/reactnative/.watchmanconfig | 1 + packages/reactnative/.yarnrc | 3 + packages/reactnative/CHANGELOG.md | 32 - packages/reactnative/README.md | 214 +----- packages/reactnative/android/build.gradle | 77 ++ .../reactnative/android/gradle.properties | 5 + .../android/src/main/AndroidManifest.xml | 4 + .../reactnativesdk/ReactNativeSdkPackage.java | 22 + .../ReactNativeSdkViewManager.java | 31 + packages/reactnative/babel.config.js | 3 + packages/reactnative/example/.bundle/config | 2 + .../tests => reactnative/example}/.env.sample | 6 +- packages/reactnative/example/.node-version | 1 + packages/reactnative/example/.watchmanconfig | 1 + packages/reactnative/example/Gemfile | 6 + .../example/android/app/build.gradle | 170 +++++ .../example/android/app/debug.keystore | Bin 0 -> 2257 bytes .../example/android/app/proguard-rules.pro | 10 + .../android/app/src/debug/AndroidManifest.xml | 13 + .../ReactNativeFlipper.java | 75 ++ .../android/app/src/main/AndroidManifest.xml | 25 + .../reactnativesdkexample/MainActivity.java | 35 + .../MainApplication.java | 62 ++ .../res/drawable/rn_edit_text_material.xml | 36 + .../src/main/res/mipmap-hdpi/ic_launcher.png | Bin 0 -> 3056 bytes .../res/mipmap-hdpi/ic_launcher_round.png | Bin 0 -> 5024 bytes .../src/main/res/mipmap-mdpi/ic_launcher.png | Bin 0 -> 2096 bytes .../res/mipmap-mdpi/ic_launcher_round.png | Bin 0 -> 2858 bytes .../src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 0 -> 4569 bytes .../res/mipmap-xhdpi/ic_launcher_round.png | Bin 0 -> 7098 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 0 -> 6464 bytes .../res/mipmap-xxhdpi/ic_launcher_round.png | Bin 0 -> 10676 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 0 -> 9250 bytes .../res/mipmap-xxxhdpi/ic_launcher_round.png | Bin 0 -> 15523 bytes .../app/src/main/res/values/strings.xml | 3 + .../app/src/main/res/values/styles.xml | 9 + .../ReactNativeFlipper.java | 20 + .../reactnative/example/android/build.gradle | 21 + .../example/android/gradle.properties | 44 ++ .../android/gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 59821 bytes .../gradle/wrapper/gradle-wrapper.properties | 5 + packages/reactnative/example/android/gradlew | 234 ++++++ .../reactnative/example/android/gradlew.bat | 89 +++ .../example/android/settings.gradle | 4 + packages/reactnative/example/app.json | 4 + packages/reactnative/example/babel.config.js | 25 + packages/reactnative/example/index.js | 5 + packages/reactnative/example/ios/File.swift | 6 + packages/reactnative/example/ios/Podfile | 60 ++ packages/reactnative/example/ios/Podfile.lock | 641 ++++++++++++++++ .../ReactNativeSdkExample-Bridging-Header.h | 3 + .../project.pbxproj | 704 ++++++++++++++++++ .../xcschemes/ReactNativeSdkExample.xcscheme | 88 +++ .../contents.xcworkspacedata | 10 + .../ios/ReactNativeSdkExample/AppDelegate.h | 6 + .../ios/ReactNativeSdkExample/AppDelegate.mm | 36 + .../AppIcon.appiconset/Contents.json | 53 ++ .../Images.xcassets/Contents.json | 6 + .../ios/ReactNativeSdkExample/Info.plist | 55 ++ .../LaunchScreen.storyboard | 47 ++ .../example/ios/ReactNativeSdkExample/main.m | 10 + .../ios/ReactNativeSdkExampleTests/Info.plist | 24 + .../ReactNativeSdkExampleTests.m | 66 ++ packages/reactnative/example/metro.config.js | 40 + packages/reactnative/example/package.json | 33 + .../example/react-native.config.js | 10 + packages/reactnative/example/shim.js | 26 + packages/reactnative/example/src/App.tsx | 442 +++++++++++ packages/reactnative/example/tsconfig.json | 3 + packages/reactnative/example/types/env.d.ts | 12 + .../ReactNativeSdk.xcodeproj/project.pbxproj | 274 +++++++ .../ios/ReactNativeSdkViewManager.m | 34 + packages/reactnative/package.json | 228 +++++- .../patches/micro-ftch+0.3.1.patch | 17 + .../react-native-randombytes+3.6.1.patch | 23 + .../reactnative/push-react-native-sdk.podspec | 36 + packages/reactnative/rollup.config.cjs | 26 - packages/reactnative/scripts/bootstrap.js | 29 + packages/reactnative/shim.js | 26 + .../reactnative/src/__tests__/index.test.tsx | 4 + packages/reactnative/src/index.ts | 1 - packages/reactnative/src/index.tsx | 140 ++++ .../reactnative/src/lib/assets/epnsbot.png | Bin 2281 -> 0 bytes .../reactnative/src/lib/assets/epnsbot@2x.png | Bin 5130 -> 0 bytes .../reactnative/src/lib/assets/epnsbot@3x.png | Bin 8524 -> 0 bytes .../reactnative/src/lib/assets/frownface.png | Bin 6020 -> 0 bytes .../src/lib/assets/frownface@2x.png | Bin 14054 -> 0 bytes .../src/lib/assets/frownface@3x.png | Bin 23045 -> 0 bytes .../src/lib/components/DownloadHelper.ts | 93 --- .../components/chainDetails/arbitrumSVG.tsx | 29 - .../lib/components/chainDetails/bscSVG.tsx | 22 - .../components/chainDetails/ethereumSVG.tsx | 34 - .../src/lib/components/chainDetails/index.tsx | 30 - .../components/chainDetails/optimismSVG.tsx | 27 - .../components/chainDetails/polygonSVG.tsx | 24 - .../chainDetails/polygonZkEVMSVG.tsx | 44 -- .../components/chainDetails/thegraphSVG.tsx | 35 - .../reactnative/src/lib/components/index.tsx | 1 - .../lib/components/loaders/EPNSActivity.tsx | 102 --- .../loaders/ImageDownloadWithIndicator.tsx | 299 -------- .../loaders/VideoDownloadWithIndicator.tsx | 340 --------- .../src/lib/components/loaders/index.tsx | 3 - .../lib/components/notifications/index.tsx | 1 - .../components/notifications/notification.tsx | 427 ----------- .../src/lib/components/notifications/utils.ts | 43 -- .../src/lib/components/parsetext/index.tsx | 1 - .../lib/components/parsetext/parsetext.tsx | 227 ------ packages/reactnative/src/lib/globals.ts | 137 ---- packages/reactnative/src/lib/index.tsx | 1 - packages/reactnative/test-setup.ts | 1 - packages/reactnative/tsconfig.build.json | 5 + packages/reactnative/tsconfig.json | 35 +- packages/reactnative/tsconfig.lib.json | 10 - .../restapi/src/lib/chat/approveRequest.ts | 23 +- packages/restapi/src/lib/chat/chats.ts | 7 +- .../restapi/src/lib/chat/conversationHash.ts | 5 +- packages/restapi/src/lib/chat/createGroup.ts | 23 +- .../restapi/src/lib/chat/helpers/crypto.ts | 90 ++- .../src/lib/chat/helpers/payloadHelper.ts | 41 +- packages/restapi/src/lib/chat/helpers/pgp.ts | 42 ++ packages/restapi/src/lib/chat/helpers/user.ts | 15 +- .../src/lib/chat/historicalMessages.ts | 12 +- .../restapi/src/lib/chat/latestMessage.ts | 5 + packages/restapi/src/lib/chat/send.ts | 20 +- packages/restapi/src/lib/chat/updateGroup.ts | 18 +- packages/restapi/src/lib/user/createUser.ts | 16 +- packages/restapi/src/lib/user/index.ts | 4 +- .../src/lib/user/profile.updateUser.ts | 13 +- workspace.json | 1 - 136 files changed, 4660 insertions(+), 2317 deletions(-) create mode 100644 lefthook.yml delete mode 100644 packages/reactnative/.babelrc create mode 100644 packages/reactnative/.editorconfig delete mode 100644 packages/reactnative/.eslintrc.json create mode 100644 packages/reactnative/.gitattributes create mode 100644 packages/reactnative/.gitignore create mode 100644 packages/reactnative/.nvmrc create mode 100644 packages/reactnative/.watchmanconfig create mode 100644 packages/reactnative/.yarnrc delete mode 100644 packages/reactnative/CHANGELOG.md create mode 100644 packages/reactnative/android/build.gradle create mode 100644 packages/reactnative/android/gradle.properties create mode 100644 packages/reactnative/android/src/main/AndroidManifest.xml create mode 100644 packages/reactnative/android/src/main/java/com/push/reactnativesdk/ReactNativeSdkPackage.java create mode 100644 packages/reactnative/android/src/main/java/com/push/reactnativesdk/ReactNativeSdkViewManager.java create mode 100644 packages/reactnative/babel.config.js create mode 100644 packages/reactnative/example/.bundle/config rename packages/{restapi/tests => reactnative/example}/.env.sample (69%) create mode 100644 packages/reactnative/example/.node-version create mode 100644 packages/reactnative/example/.watchmanconfig create mode 100644 packages/reactnative/example/Gemfile create mode 100644 packages/reactnative/example/android/app/build.gradle create mode 100644 packages/reactnative/example/android/app/debug.keystore create mode 100644 packages/reactnative/example/android/app/proguard-rules.pro create mode 100644 packages/reactnative/example/android/app/src/debug/AndroidManifest.xml create mode 100644 packages/reactnative/example/android/app/src/debug/java/com/reactnativesdkexample/ReactNativeFlipper.java create mode 100644 packages/reactnative/example/android/app/src/main/AndroidManifest.xml create mode 100644 packages/reactnative/example/android/app/src/main/java/com/reactnativesdkexample/MainActivity.java create mode 100644 packages/reactnative/example/android/app/src/main/java/com/reactnativesdkexample/MainApplication.java create mode 100644 packages/reactnative/example/android/app/src/main/res/drawable/rn_edit_text_material.xml create mode 100644 packages/reactnative/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png create mode 100644 packages/reactnative/example/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png create mode 100644 packages/reactnative/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png create mode 100644 packages/reactnative/example/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png create mode 100644 packages/reactnative/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png create mode 100644 packages/reactnative/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png create mode 100644 packages/reactnative/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png create mode 100644 packages/reactnative/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png create mode 100644 packages/reactnative/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png create mode 100644 packages/reactnative/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png create mode 100644 packages/reactnative/example/android/app/src/main/res/values/strings.xml create mode 100644 packages/reactnative/example/android/app/src/main/res/values/styles.xml create mode 100644 packages/reactnative/example/android/app/src/release/java/com/reactnativesdkexample/ReactNativeFlipper.java create mode 100644 packages/reactnative/example/android/build.gradle create mode 100644 packages/reactnative/example/android/gradle.properties create mode 100644 packages/reactnative/example/android/gradle/wrapper/gradle-wrapper.jar create mode 100644 packages/reactnative/example/android/gradle/wrapper/gradle-wrapper.properties create mode 100755 packages/reactnative/example/android/gradlew create mode 100644 packages/reactnative/example/android/gradlew.bat create mode 100644 packages/reactnative/example/android/settings.gradle create mode 100644 packages/reactnative/example/app.json create mode 100644 packages/reactnative/example/babel.config.js create mode 100644 packages/reactnative/example/index.js create mode 100644 packages/reactnative/example/ios/File.swift create mode 100644 packages/reactnative/example/ios/Podfile create mode 100644 packages/reactnative/example/ios/Podfile.lock create mode 100644 packages/reactnative/example/ios/ReactNativeSdkExample-Bridging-Header.h create mode 100644 packages/reactnative/example/ios/ReactNativeSdkExample.xcodeproj/project.pbxproj create mode 100644 packages/reactnative/example/ios/ReactNativeSdkExample.xcodeproj/xcshareddata/xcschemes/ReactNativeSdkExample.xcscheme create mode 100644 packages/reactnative/example/ios/ReactNativeSdkExample.xcworkspace/contents.xcworkspacedata create mode 100644 packages/reactnative/example/ios/ReactNativeSdkExample/AppDelegate.h create mode 100644 packages/reactnative/example/ios/ReactNativeSdkExample/AppDelegate.mm create mode 100644 packages/reactnative/example/ios/ReactNativeSdkExample/Images.xcassets/AppIcon.appiconset/Contents.json create mode 100644 packages/reactnative/example/ios/ReactNativeSdkExample/Images.xcassets/Contents.json create mode 100644 packages/reactnative/example/ios/ReactNativeSdkExample/Info.plist create mode 100644 packages/reactnative/example/ios/ReactNativeSdkExample/LaunchScreen.storyboard create mode 100644 packages/reactnative/example/ios/ReactNativeSdkExample/main.m create mode 100644 packages/reactnative/example/ios/ReactNativeSdkExampleTests/Info.plist create mode 100644 packages/reactnative/example/ios/ReactNativeSdkExampleTests/ReactNativeSdkExampleTests.m create mode 100644 packages/reactnative/example/metro.config.js create mode 100644 packages/reactnative/example/package.json create mode 100644 packages/reactnative/example/react-native.config.js create mode 100644 packages/reactnative/example/shim.js create mode 100644 packages/reactnative/example/src/App.tsx create mode 100644 packages/reactnative/example/tsconfig.json create mode 100644 packages/reactnative/example/types/env.d.ts create mode 100644 packages/reactnative/ios/ReactNativeSdk.xcodeproj/project.pbxproj create mode 100644 packages/reactnative/ios/ReactNativeSdkViewManager.m create mode 100644 packages/reactnative/patches/micro-ftch+0.3.1.patch create mode 100644 packages/reactnative/patches/react-native-randombytes+3.6.1.patch create mode 100644 packages/reactnative/push-react-native-sdk.podspec delete mode 100644 packages/reactnative/rollup.config.cjs create mode 100644 packages/reactnative/scripts/bootstrap.js create mode 100644 packages/reactnative/shim.js create mode 100644 packages/reactnative/src/__tests__/index.test.tsx delete mode 100644 packages/reactnative/src/index.ts create mode 100644 packages/reactnative/src/index.tsx delete mode 100644 packages/reactnative/src/lib/assets/epnsbot.png delete mode 100644 packages/reactnative/src/lib/assets/epnsbot@2x.png delete mode 100644 packages/reactnative/src/lib/assets/epnsbot@3x.png delete mode 100644 packages/reactnative/src/lib/assets/frownface.png delete mode 100644 packages/reactnative/src/lib/assets/frownface@2x.png delete mode 100644 packages/reactnative/src/lib/assets/frownface@3x.png delete mode 100644 packages/reactnative/src/lib/components/DownloadHelper.ts delete mode 100644 packages/reactnative/src/lib/components/chainDetails/arbitrumSVG.tsx delete mode 100644 packages/reactnative/src/lib/components/chainDetails/bscSVG.tsx delete mode 100644 packages/reactnative/src/lib/components/chainDetails/ethereumSVG.tsx delete mode 100644 packages/reactnative/src/lib/components/chainDetails/index.tsx delete mode 100644 packages/reactnative/src/lib/components/chainDetails/optimismSVG.tsx delete mode 100644 packages/reactnative/src/lib/components/chainDetails/polygonSVG.tsx delete mode 100644 packages/reactnative/src/lib/components/chainDetails/polygonZkEVMSVG.tsx delete mode 100644 packages/reactnative/src/lib/components/chainDetails/thegraphSVG.tsx delete mode 100644 packages/reactnative/src/lib/components/index.tsx delete mode 100644 packages/reactnative/src/lib/components/loaders/EPNSActivity.tsx delete mode 100644 packages/reactnative/src/lib/components/loaders/ImageDownloadWithIndicator.tsx delete mode 100644 packages/reactnative/src/lib/components/loaders/VideoDownloadWithIndicator.tsx delete mode 100644 packages/reactnative/src/lib/components/loaders/index.tsx delete mode 100644 packages/reactnative/src/lib/components/notifications/index.tsx delete mode 100644 packages/reactnative/src/lib/components/notifications/notification.tsx delete mode 100644 packages/reactnative/src/lib/components/notifications/utils.ts delete mode 100644 packages/reactnative/src/lib/components/parsetext/index.tsx delete mode 100644 packages/reactnative/src/lib/components/parsetext/parsetext.tsx delete mode 100644 packages/reactnative/src/lib/globals.ts delete mode 100644 packages/reactnative/src/lib/index.tsx delete mode 100644 packages/reactnative/test-setup.ts create mode 100644 packages/reactnative/tsconfig.build.json delete mode 100644 packages/reactnative/tsconfig.lib.json diff --git a/lefthook.yml b/lefthook.yml new file mode 100644 index 000000000..c8ba01326 --- /dev/null +++ b/lefthook.yml @@ -0,0 +1,35 @@ +EXAMPLE USAGE: + + Refer for explanation to following link: + https://github.com/evilmartians/lefthook/blob/master/docs/configuration.md + +pre-push: + commands: + packages-audit: + tags: frontend security + run: yarn audit + gems-audit: + tags: backend security + run: bundle audit + +pre-commit: + parallel: true + commands: + eslint: + glob: "*.{js,ts,jsx,tsx}" + run: yarn eslint {staged_files} + rubocop: + tags: backend style + glob: "*.rb" + exclude: "application.rb|routes.rb" + run: bundle exec rubocop --force-exclusion {all_files} + govet: + tags: backend style + files: git ls-files -m + glob: "*.go" + run: go vet {files} + scripts: + "hello.js": + runner: node + "any.go": + runner: go run diff --git a/packages/reactnative/.babelrc b/packages/reactnative/.babelrc deleted file mode 100644 index 677d99a4c..000000000 --- a/packages/reactnative/.babelrc +++ /dev/null @@ -1,11 +0,0 @@ -{ - "presets": [ - [ - "@nrwl/react/babel", - { - "runtime": "automatic", - "useBuiltIns": "usage" - } - ] - ] -} \ No newline at end of file diff --git a/packages/reactnative/.editorconfig b/packages/reactnative/.editorconfig new file mode 100644 index 000000000..65365be68 --- /dev/null +++ b/packages/reactnative/.editorconfig @@ -0,0 +1,15 @@ +# EditorConfig helps developers define and maintain consistent +# coding styles between different editors and IDEs +# editorconfig.org + +root = true + +[*] + +indent_style = space +indent_size = 2 + +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true diff --git a/packages/reactnative/.eslintrc.json b/packages/reactnative/.eslintrc.json deleted file mode 100644 index ba6f759dd..000000000 --- a/packages/reactnative/.eslintrc.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "extends": ["plugin:@nrwl/nx/react", "../../.eslintrc.json"], - "ignorePatterns": ["!**/*", "public", ".cache", "node_modules"], - "overrides": [ - { - "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], - "rules": { - "@typescript-eslint/ban-ts-comment": "off" - } - }, - { - "files": ["*.ts", "*.tsx"], - "rules": {} - }, - { - "files": ["*.js", "*.jsx"], - "rules": {} - } - ] -} diff --git a/packages/reactnative/.gitattributes b/packages/reactnative/.gitattributes new file mode 100644 index 000000000..030ef1448 --- /dev/null +++ b/packages/reactnative/.gitattributes @@ -0,0 +1,3 @@ +*.pbxproj -text +# specific for windows script files +*.bat text eol=crlf \ No newline at end of file diff --git a/packages/reactnative/.gitignore b/packages/reactnative/.gitignore new file mode 100644 index 000000000..75356714f --- /dev/null +++ b/packages/reactnative/.gitignore @@ -0,0 +1,70 @@ +# OSX +# +.DS_Store + +# XDE +.expo/ + +# VSCode +.vscode/ +jsconfig.json + +# Xcode +# +build/ +*.pbxuser +!default.pbxuser +*.mode1v3 +!default.mode1v3 +*.mode2v3 +!default.mode2v3 +*.perspectivev3 +!default.perspectivev3 +xcuserdata +*.xccheckout +*.moved-aside +DerivedData +*.hmap +*.ipa +*.xcuserstate +project.xcworkspace + +# Android/IJ +# +.classpath +.cxx +.gradle +.idea +.project +.settings +local.properties +android.iml + +# Cocoapods +# +example/ios/Pods + +# Ruby +example/vendor/ + +# node.js +# +node_modules/ +npm-debug.log +yarn-debug.log +yarn-error.log + +# BUCK +buck-out/ +\.buckd/ +android/app/libs +android/keystores/debug.keystore + +# Expo +.expo/ + +# Turborepo +.turbo/ + +# generated by bob +lib/ diff --git a/packages/reactnative/.nvmrc b/packages/reactnative/.nvmrc new file mode 100644 index 000000000..5397c87fa --- /dev/null +++ b/packages/reactnative/.nvmrc @@ -0,0 +1 @@ +16.18.1 diff --git a/packages/reactnative/.watchmanconfig b/packages/reactnative/.watchmanconfig new file mode 100644 index 000000000..9e26dfeeb --- /dev/null +++ b/packages/reactnative/.watchmanconfig @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/packages/reactnative/.yarnrc b/packages/reactnative/.yarnrc new file mode 100644 index 000000000..fedc0f117 --- /dev/null +++ b/packages/reactnative/.yarnrc @@ -0,0 +1,3 @@ +# Override Yarn command so we can automatically setup the repo on running `yarn` + +yarn-path "scripts/bootstrap.js" diff --git a/packages/reactnative/CHANGELOG.md b/packages/reactnative/CHANGELOG.md deleted file mode 100644 index 96a81f32b..000000000 --- a/packages/reactnative/CHANGELOG.md +++ /dev/null @@ -1,32 +0,0 @@ -# Changelog - -This file was generated using [@jscutlery/semver](https://github.com/jscutlery/semver). - -# [0.2.0](https://github.com/ethereum-push-notification-service/push-sdk/compare/reactnative-0.1.0...reactnative-0.2.0) (2023-01-13) - - -### Features - -* Bsc chain config changes added ([#113](https://github.com/ethereum-push-notification-service/push-sdk/issues/113)) ([e1af11b](https://github.com/ethereum-push-notification-service/push-sdk/commit/e1af11b1fa444e30f8aa08ee6b54a30bb03d6070)) - - - -# [0.1.0](https://github.com/ethereum-push-notification-service/sdk/compare/reactnative-0.0.2...reactnative-0.1.0) (2022-10-07) - - -### Features - -* **reactnative:** stable 0.1.0 ([fbcaac1](https://github.com/ethereum-push-notification-service/sdk/commit/fbcaac12df32935d798903bbafafd9e41a6553b6)) - - - -## [0.0.2](https://github.com/ethereum-push-notification-service/sdk/compare/reactnative-0.0.1...reactnative-0.0.2) (2022-10-07) - - -### Bug Fixes - -* **reactnative:** docs update ([fb39df9](https://github.com/ethereum-push-notification-service/sdk/commit/fb39df9d37cf960bc1498f9f51189221a6d52271)) - - - -## 0.0.1 (2022-10-07) diff --git a/packages/reactnative/README.md b/packages/reactnative/README.md index d3e665c64..f0d3d9f26 100644 --- a/packages/reactnative/README.md +++ b/packages/reactnative/README.md @@ -1,212 +1,8 @@ -# reactnative +# @push/react-native-sdk +PUSH -Package for React Native Views for React Native based mobile apps. +## Installation -## How to use in your Mobile app? - -### Installation -``` - yarn add @pushprotocol/reactnative -``` - or -``` - npm install @pushprotocol/reactnative -``` - -### **Please read this carefullly** - -We need to install peer dependencies for `@pushprotocol/reactnative` in your mobile app. And have it set up as below to make it run. - -``` -yarn add @react-native-masked-view/masked-view react-native-svg react-native-video react-native-youtube -``` -Then for different types of react native apps use the below instructions. -### FOR EXPO APPS -``` -expo install expo-file-system -expo install expo-linear-gradient -``` - -### Running IOS -``` -cd ios && pod install -``` -``` -yarn ios -``` - -#### [ViewPropTypes Error](https://github.com/facebook/react-native/issues/33734#issuecomment-1190506381) - -If only you get below error -``` -Invariant Violation: ViewPropTypes has been removed from React Native. Migrate to ViewPropTypes exported from 'deprecated-react-native-prop-types' -``` - -#### ViewPropTypes Error Fix -1. In `node_modules/react-native/index.js` -Replace the below code -``` -// Deprecated Prop Types -get ColorPropType(): $FlowFixMe { - invariant( - false, - "ColorPropType has been removed from React Native. Migrate to " + - "ColorPropType exported from 'deprecated-react-native-prop-types'.", - ); -}, -get EdgeInsetsPropType(): $FlowFixMe { - invariant( - false, - "EdgeInsetsPropType has been removed from React Native. Migrate to " + - "EdgeInsetsPropType exported from 'deprecated-react-native-prop-types'.", - ); -}, -get PointPropType(): $FlowFixMe { - invariant( - false, - "PointPropType has been removed from React Native. Migrate to " + - "PointPropType exported from 'deprecated-react-native-prop-types'.", - ); -}, -get ViewPropTypes(): $FlowFixMe { - invariant( - false, - "ViewPropTypes has been removed from React Native. Migrate to " + - "ViewPropTypes exported from 'deprecated-react-native-prop-types'.", - ); -}, -``` -with below snippet -``` -// Deprecated Prop Types -get ColorPropType(): $FlowFixMe { - return require("deprecated-react-native-prop-types").ColorPropType -}, -get EdgeInsetsPropType(): $FlowFixMe { - return require("deprecated-react-native-prop-types").EdgeInsetsPropType -}, -get PointPropType(): $FlowFixMe { - return require("deprecated-react-native-prop-types").PointPropType -}, -get ViewPropTypes(): $FlowFixMe { - return require("deprecated-react-native-prop-types").ViewPropTypes -}, -``` - -2. `yarn add -D patch-package` -3. `yarn patch-package react-native` -4. `cd ios && pod install` -5. `yarn ios` - -#### [Image.propTypes.resizeMode error](https://github.com/react-native-video/react-native-video/issues/2714) -``` -ERROR TypeError: undefined is not an object (evaluating '_reactNative.Image.propTypes.resizeMode') -``` -then use this -#### [Image.propTypes fix](https://github.com/react-native-video/react-native-video/pull/2795/files) - -After that, -``` -yarn patch-package react-native-video -cd ios && pod install -yarn ios -``` - -### Running Android -If you get this Error -``` -Could not find com.yqritc:android-scalablevideoview:1.0.4. - Required by: - project :react-native-video - -``` -add this in `android/build.gradle` -``` -jcenter() { - content { - includeModule("com.yqritc", "android-scalablevideoview") - } -} -``` - -Run `yarn android` - - -### FOR REACT NATIVE CLI GENERATED APPS - -``` -npx install-expo-modules -expo install expo-file-system -expo install expo-linear-gradient -``` -``` -cd iOS && pod install -yarn iOS -``` - -Similarly, -if you get this [ViewPropTypes error](#viewproptypes-errorhttpsgithubcomfacebookreact-nativeissues33734issuecomment-1190506381) then use this [fix](#viewproptypes-error-fix) - -and [ImagePropTypes error](#imageproptypesresizemode-errorhttpsgithubcomreact-native-videoreact-native-videoissues2714) then use this [fix](https://github.com/react-native-video/react-native-video/pull/2795/files) - -## Notification Item View - -Import in your file -```typescript -import { Notification } from "@pushprotocol/reactnative"; -``` - -Inside JSX, - -After you get the Notification data from the API - -``` -const [notifData, setNotifData] = React.useState([]); - -// fetch data, parse and set it in state -import * as PushAPI from '@pushprotocol/restapi'; - - -const notifications = await PushAPI.user.getFeeds({ - user: 'eip155:5:0xD8634C39BBFd4033c0d3289C4515275102423681', - env: 'dev', - limit: parseInt(pageSize, 10) -}); -setNotifData(notifications); -``` - - -``` - - {notifData.map((oneNotification: any, idx: number) => { - const {cta, title, message, app, icon, image, blockchain, appbot } = oneNotification; - return ( - - ); - })} - +```sh +npm install @push/react-native-sdk ``` - -where - -| Prop | Type | Remarks | -|----------|--------|--------------------------------------------| -| notificationTitle | string | Title of the notification (given during notification creation) | -| notificationBody | number | Message body of the notification (given during notification creation) | -| icon | string | Channel Icon (IPFS url) (given during channel setup) | -| app | string | Channel Name (given during channel setup) | -| cta | string | Call To Action Link (given during notification creation) | -| image | string | Any media link (given during notification creation) | -| appbot | string | is the notification is from EPNS bot the value is "1" else "0" | -| chainName | string | Can be anyone of the following blockchain networks on which the notification was sent - "ETH_MAINNET", "ETH_TEST_GOERLI", "POLYGON_MAINNET", "POLYGON_TEST_MUMBAI", "BSC_MAINNET, "BSC_TESTNET", "OPTIMISM_MAINNET", "OPTIMISM_TESTNET", "POLYGON_ZK_EVM_TESTNET", "POLYGON_ZK_EVM_MAINNET", "ARBITRUM_TESTNET", "ARBITRUMONE_MAINNET", "THE_GRAPH" | -| youTubeAPIKey | string | Your generated Youtube API key | \ No newline at end of file diff --git a/packages/reactnative/android/build.gradle b/packages/reactnative/android/build.gradle new file mode 100644 index 000000000..d6bc45ca6 --- /dev/null +++ b/packages/reactnative/android/build.gradle @@ -0,0 +1,77 @@ +buildscript { + repositories { + google() + mavenCentral() + } + + dependencies { + classpath "com.android.tools.build:gradle:7.2.1" + } +} + +def isNewArchitectureEnabled() { + return rootProject.hasProperty("newArchEnabled") && rootProject.getProperty("newArchEnabled") == "true" +} + +apply plugin: "com.android.library" + + +def appProject = rootProject.allprojects.find { it.plugins.hasPlugin('com.android.application') } + +if (isNewArchitectureEnabled()) { + apply plugin: "com.facebook.react" +} + +def getExtOrDefault(name) { + return rootProject.ext.has(name) ? rootProject.ext.get(name) : project.properties["ReactNativeSdk_" + name] +} + +def getExtOrIntegerDefault(name) { + return rootProject.ext.has(name) ? rootProject.ext.get(name) : (project.properties["ReactNativeSdk_" + name]).toInteger() +} + +android { + compileSdkVersion getExtOrIntegerDefault("compileSdkVersion") + + defaultConfig { + minSdkVersion getExtOrIntegerDefault("minSdkVersion") + targetSdkVersion getExtOrIntegerDefault("targetSdkVersion") + buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString() + } + buildTypes { + release { + minifyEnabled false + } + } + + lintOptions { + disable "GradleCompatible" + } + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + +} + +repositories { + mavenCentral() + google() +} + + +dependencies { + // For < 0.71, this will be from the local maven repo + // For > 0.71, this will be replaced by `com.facebook.react:react-android:$version` by react gradle plugin + //noinspection GradleDynamicVersion + implementation "com.facebook.react:react-native:+" +} + +if (isNewArchitectureEnabled()) { + react { + jsRootDir = file("../src/") + libraryName = "ReactNativeSdkView" + codegenJavaPackageName = "com.push.reactnativesdk" + } +} diff --git a/packages/reactnative/android/gradle.properties b/packages/reactnative/android/gradle.properties new file mode 100644 index 000000000..f360eea5f --- /dev/null +++ b/packages/reactnative/android/gradle.properties @@ -0,0 +1,5 @@ +ReactNativeSdk_kotlinVersion=1.7.0 +ReactNativeSdk_minSdkVersion=21 +ReactNativeSdk_targetSdkVersion=31 +ReactNativeSdk_compileSdkVersion=31 +ReactNativeSdk_ndkversion=21.4.7075529 diff --git a/packages/reactnative/android/src/main/AndroidManifest.xml b/packages/reactnative/android/src/main/AndroidManifest.xml new file mode 100644 index 000000000..e3f2fadb7 --- /dev/null +++ b/packages/reactnative/android/src/main/AndroidManifest.xml @@ -0,0 +1,4 @@ + + + diff --git a/packages/reactnative/android/src/main/java/com/push/reactnativesdk/ReactNativeSdkPackage.java b/packages/reactnative/android/src/main/java/com/push/reactnativesdk/ReactNativeSdkPackage.java new file mode 100644 index 000000000..300149461 --- /dev/null +++ b/packages/reactnative/android/src/main/java/com/push/reactnativesdk/ReactNativeSdkPackage.java @@ -0,0 +1,22 @@ +package com.push.reactnativesdk; + +import com.facebook.react.ReactPackage; +import com.facebook.react.bridge.NativeModule; +import com.facebook.react.bridge.ReactApplicationContext; +import com.facebook.react.uimanager.ViewManager; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +public class ReactNativeSdkPackage implements ReactPackage { + @Override + public List createNativeModules(ReactApplicationContext reactContext) { + return Collections.emptyList(); + } + + @Override + public List createViewManagers(ReactApplicationContext reactContext) { + return Arrays.asList(new ReactNativeSdkViewManager()); + } +} diff --git a/packages/reactnative/android/src/main/java/com/push/reactnativesdk/ReactNativeSdkViewManager.java b/packages/reactnative/android/src/main/java/com/push/reactnativesdk/ReactNativeSdkViewManager.java new file mode 100644 index 000000000..d8339ec09 --- /dev/null +++ b/packages/reactnative/android/src/main/java/com/push/reactnativesdk/ReactNativeSdkViewManager.java @@ -0,0 +1,31 @@ +package com.push.reactnativesdk; + +import android.graphics.Color; +import android.view.View; + +import androidx.annotation.NonNull; + +import com.facebook.react.uimanager.SimpleViewManager; +import com.facebook.react.uimanager.ThemedReactContext; +import com.facebook.react.uimanager.annotations.ReactProp; + +public class ReactNativeSdkViewManager extends SimpleViewManager { + public static final String REACT_CLASS = "ReactNativeSdkView"; + + @Override + @NonNull + public String getName() { + return REACT_CLASS; + } + + @Override + @NonNull + public View createViewInstance(ThemedReactContext reactContext) { + return new View(reactContext); + } + + @ReactProp(name = "color") + public void setColor(View view, String color) { + view.setBackgroundColor(Color.parseColor(color)); + } +} diff --git a/packages/reactnative/babel.config.js b/packages/reactnative/babel.config.js new file mode 100644 index 000000000..f842b77fc --- /dev/null +++ b/packages/reactnative/babel.config.js @@ -0,0 +1,3 @@ +module.exports = { + presets: ['module:metro-react-native-babel-preset'], +}; diff --git a/packages/reactnative/example/.bundle/config b/packages/reactnative/example/.bundle/config new file mode 100644 index 000000000..848943bb5 --- /dev/null +++ b/packages/reactnative/example/.bundle/config @@ -0,0 +1,2 @@ +BUNDLE_PATH: "vendor/bundle" +BUNDLE_FORCE_RUBY_PLATFORM: 1 diff --git a/packages/restapi/tests/.env.sample b/packages/reactnative/example/.env.sample similarity index 69% rename from packages/restapi/tests/.env.sample rename to packages/reactnative/example/.env.sample index 746fefeb5..f6d444362 100644 --- a/packages/restapi/tests/.env.sample +++ b/packages/reactnative/example/.env.sample @@ -2,9 +2,9 @@ WALLET_PRIVATE_KEY=your_wallet_private_key NFT_CONTRACT_ADDRESS_1=your_nft_contract_address NFT_CHAIN_ID_1=your_nft_chainid -NFT_TOKEN_ID_1=tour_nft_token_id +NFT_TOKEN_ID_1=your_nft_token_id NFT_HOLDER_WALLET_PRIVATE_KEY_1=wallet_private_key NFT_CONTRACT_ADDRESS_2=your_nft_contract_address NFT_CHAIN_ID_2=your_nft_chainid -NFT_TOKEN_ID_2=tour_nft_token_id -NFT_HOLDER_WALLET_PRIVATE_KEY_2=wallet_private_key \ No newline at end of file +NFT_TOKEN_ID_2=your_nft_token_id +NFT_HOLDER_WALLET_PRIVATE_KEY_2=wallet_private_key diff --git a/packages/reactnative/example/.node-version b/packages/reactnative/example/.node-version new file mode 100644 index 000000000..3c032078a --- /dev/null +++ b/packages/reactnative/example/.node-version @@ -0,0 +1 @@ +18 diff --git a/packages/reactnative/example/.watchmanconfig b/packages/reactnative/example/.watchmanconfig new file mode 100644 index 000000000..9e26dfeeb --- /dev/null +++ b/packages/reactnative/example/.watchmanconfig @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/packages/reactnative/example/Gemfile b/packages/reactnative/example/Gemfile new file mode 100644 index 000000000..1142b1b20 --- /dev/null +++ b/packages/reactnative/example/Gemfile @@ -0,0 +1,6 @@ +source 'https://rubygems.org' + +# You may use http://rbenv.org/ or https://rvm.io/ to install and use this version +ruby '>= 2.6.10' + +gem 'cocoapods', '>= 1.11.3' diff --git a/packages/reactnative/example/android/app/build.gradle b/packages/reactnative/example/android/app/build.gradle new file mode 100644 index 000000000..146e8e65c --- /dev/null +++ b/packages/reactnative/example/android/app/build.gradle @@ -0,0 +1,170 @@ +apply plugin: "com.android.application" +apply plugin: "com.facebook.react" + +import com.android.build.OutputFile + +/** + * This is the configuration block to customize your React Native Android app. + * By default you don't need to apply any configuration, just uncomment the lines you need. + */ +react { + /* Folders */ + // The root of your project, i.e. where "package.json" lives. Default is '..' + // root = file("../") + // The folder where the react-native NPM package is. Default is ../node_modules/react-native + // reactNativeDir = file("../node_modules/react-native") + // The folder where the react-native Codegen package is. Default is ../node_modules/react-native-codegen + // codegenDir = file("../node_modules/react-native-codegen") + // The cli.js file which is the React Native CLI entrypoint. Default is ../node_modules/react-native/cli.js + // cliFile = file("../node_modules/react-native/cli.js") + + /* Variants */ + // The list of variants to that are debuggable. For those we're going to + // skip the bundling of the JS bundle and the assets. By default is just 'debug'. + // If you add flavors like lite, prod, etc. you'll have to list your debuggableVariants. + // debuggableVariants = ["liteDebug", "prodDebug"] + + /* Bundling */ + // A list containing the node command and its flags. Default is just 'node'. + // nodeExecutableAndArgs = ["node"] + // + // The command to run when bundling. By default is 'bundle' + // bundleCommand = "ram-bundle" + // + // The path to the CLI configuration file. Default is empty. + // bundleConfig = file(../rn-cli.config.js) + // + // The name of the generated asset file containing your JS bundle + // bundleAssetName = "MyApplication.android.bundle" + // + // The entry file for bundle generation. Default is 'index.android.js' or 'index.js' + // entryFile = file("../js/MyApplication.android.js") + // + // A list of extra flags to pass to the 'bundle' commands. + // See https://github.com/react-native-community/cli/blob/main/docs/commands.md#bundle + // extraPackagerArgs = [] + + /* Hermes Commands */ + // The hermes compiler command to run. By default it is 'hermesc' + // hermesCommand = "$rootDir/my-custom-hermesc/bin/hermesc" + // + // The list of flags to pass to the Hermes compiler. By default is "-O", "-output-source-map" + // hermesFlags = ["-O", "-output-source-map"] +} + +/** + * Set this to true to create four separate APKs instead of one, + * one for each native architecture. This is useful if you don't + * use App Bundles (https://developer.android.com/guide/app-bundle/) + * and want to have separate APKs to upload to the Play Store. + */ +def enableSeparateBuildPerCPUArchitecture = false + +/** + * Set this to true to Run Proguard on Release builds to minify the Java bytecode. + */ +def enableProguardInReleaseBuilds = false + +/** + * The preferred build flavor of JavaScriptCore (JSC) + * + * For example, to use the international variant, you can use: + * `def jscFlavor = 'org.webkit:android-jsc-intl:+'` + * + * The international variant includes ICU i18n library and necessary data + * allowing to use e.g. `Date.toLocaleString` and `String.localeCompare` that + * give correct results when using with locales other than en-US. Note that + * this variant is about 6MiB larger per architecture than default. + */ +def jscFlavor = 'org.webkit:android-jsc:+' + +/** + * Private function to get the list of Native Architectures you want to build. + * This reads the value from reactNativeArchitectures in your gradle.properties + * file and works together with the --active-arch-only flag of react-native run-android. + */ +def reactNativeArchitectures() { + def value = project.getProperties().get("reactNativeArchitectures") + return value ? value.split(",") : ["armeabi-v7a", "x86", "x86_64", "arm64-v8a"] +} + +android { + ndkVersion rootProject.ext.ndkVersion + + compileSdkVersion rootProject.ext.compileSdkVersion + + namespace "com.reactnativesdkexample" + defaultConfig { + applicationId "com.reactnativesdkexample" + minSdkVersion rootProject.ext.minSdkVersion + targetSdkVersion rootProject.ext.targetSdkVersion + versionCode 1 + versionName "1.0" + } + + splits { + abi { + reset() + enable enableSeparateBuildPerCPUArchitecture + universalApk false // If true, also generate a universal APK + include (*reactNativeArchitectures()) + } + } + signingConfigs { + debug { + storeFile file('debug.keystore') + storePassword 'android' + keyAlias 'androiddebugkey' + keyPassword 'android' + } + } + buildTypes { + debug { + signingConfig signingConfigs.debug + } + release { + // Caution! In production, you need to generate your own keystore file. + // see https://reactnative.dev/docs/signed-apk-android. + signingConfig signingConfigs.debug + minifyEnabled enableProguardInReleaseBuilds + proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro" + } + } + + // applicationVariants are e.g. debug, release + applicationVariants.all { variant -> + variant.outputs.each { output -> + // For each separate APK per architecture, set a unique version code as described here: + // https://developer.android.com/studio/build/configure-apk-splits.html + // Example: versionCode 1 will generate 1001 for armeabi-v7a, 1002 for x86, etc. + def versionCodes = ["armeabi-v7a": 1, "x86": 2, "arm64-v8a": 3, "x86_64": 4] + def abi = output.getFilter(OutputFile.ABI) + if (abi != null) { // null for the universal-debug, universal-release variants + output.versionCodeOverride = + defaultConfig.versionCode * 1000 + versionCodes.get(abi) + } + + } + } +} + +dependencies { + // The version of react-native is set by the React Native Gradle Plugin + implementation("com.facebook.react:react-android") + + implementation("androidx.swiperefreshlayout:swiperefreshlayout:1.0.0") + + debugImplementation("com.facebook.flipper:flipper:${FLIPPER_VERSION}") + debugImplementation("com.facebook.flipper:flipper-network-plugin:${FLIPPER_VERSION}") { + exclude group:'com.squareup.okhttp3', module:'okhttp' + } + + debugImplementation("com.facebook.flipper:flipper-fresco-plugin:${FLIPPER_VERSION}") + if (hermesEnabled.toBoolean()) { + implementation("com.facebook.react:hermes-android") + } else { + implementation jscFlavor + } +} + +apply from: file("../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesAppBuildGradle(project) diff --git a/packages/reactnative/example/android/app/debug.keystore b/packages/reactnative/example/android/app/debug.keystore new file mode 100644 index 0000000000000000000000000000000000000000..364e105ed39fbfd62001429a68140672b06ec0de GIT binary patch literal 2257 zcmchYXEfYt8;7T1^dLH$VOTZ%2NOdOH5j5LYLtZ0q7x-V8_6gU5)#7dkq{HTmsfNq zB3ZqcAxeY^G10@?efK?Q&)M(qInVv!xjx+IKEL}p*K@LYvIzo#AZG>st5|P)KF1_Z;y){W{<7K{nl!CPuE z_^(!C(Ol0n8 zK13*rzAtW>(wULKPRYLd7G18F8#1P`V*9`(Poj26eOXYyBVZPno~Cvvhx7vPjAuZo zF?VD!zB~QG(!zbw#qsxT8%BSpqMZ4f70ZPn-3y$L8{EVbbN9$H`B&Z1quk9tgp5FM zuxp3pJ0b8u|3+#5bkJ4SRnCF2l7#DyLYXYY8*?OuAwK4E6J{0N=O3QNVzQ$L#FKkR zi-c@&!nDvezOV$i$Lr}iF$XEcwnybQ6WZrMKuw8gCL^U#D;q3t&HpTbqyD%vG=TeDlzCT~MXUPC|Leb-Uk+ z=vnMd(|>ld?Fh>V8poP;q;;nc@en$|rnP0ytzD&fFkCeUE^kG9Kx4wUh!!rpjwKDP zyw_e|a^x_w3E zP}}@$g>*LLJ4i0`Gx)qltL}@;mDv}D*xR^oeWcWdPkW@Uu)B^X&4W1$p6}ze!zudJ zyiLg@uggoMIArBr*27EZV7djDg@W1MaL+rcZ-lrANJQ%%>u8)ZMWU@R2qtnmG(acP z0d_^!t>}5W zpT`*2NR+0+SpTHb+6Js4b;%LJB;B_-ChhnU5py}iJtku*hm5F0!iql8Hrpcy1aYbT z1*dKC5ua6pMX@@iONI?Hpr%h;&YaXp9n!ND7-=a%BD7v&g zOO41M6EbE24mJ#S$Ui0-brR5ML%@|ndz^)YLMMV1atna{Fw<;TF@>d&F|!Z>8eg>>hkFrV)W+uv=`^F9^e zzzM2*oOjT9%gLoub%(R57p-`TXFe#oh1_{&N-YN z<}artH|m=d8TQuKSWE)Z%puU|g|^^NFwC#N=@dPhasyYjoy(fdEVfKR@cXKHZV-`06HsP`|Ftx;8(YD$fFXumLWbGnu$GMqRncXYY9mwz9$ap zQtfZB^_BeNYITh^hA7+(XNFox5WMeG_LtJ%*Q}$8VKDI_p8^pqX)}NMb`0e|wgF7D zuQACY_Ua<1ri{;Jwt@_1sW9zzdgnyh_O#8y+C;LcZq6=4e^cs6KvmK@$vVpKFGbQ= z$)Eux5C|Fx;Gtmv9^#Y-g@7Rt7*eLp5n!gJmn7&B_L$G?NCN`AP>cXQEz}%F%K;vUs{+l4Q{}eWW;ATe2 zqvXzxoIDy(u;F2q1JH7Sf;{jy_j})F+cKlIOmNfjBGHoG^CN zM|Ho&&X|L-36f}Q-obEACz`sI%2f&k>z5c$2TyTSj~vmO)BW~+N^kt`Jt@R|s!){H ze1_eCrlNaPkJQhL$WG&iRvF*YG=gXd1IyYQ9ew|iYn7r~g!wOnw;@n42>enAxBv*A zEmV*N#sxdicyNM=A4|yaOC5MByts}s_Hpfj|y<6G=o=!3S@eIFKDdpR7|FY>L&Wat&oW&cm&X~ z5Bt>Fcq(fgnvlvLSYg&o6>&fY`ODg4`V^lWWD=%oJ#Kbad2u~! zLECFS*??>|vDsNR&pH=Ze0Eo`sC_G`OjoEKVHY|wmwlX&(XBE<@sx3Hd^gtd-fNwUHsylg06p`U2y_={u}Bc + + + + + + + + diff --git a/packages/reactnative/example/android/app/src/debug/java/com/reactnativesdkexample/ReactNativeFlipper.java b/packages/reactnative/example/android/app/src/debug/java/com/reactnativesdkexample/ReactNativeFlipper.java new file mode 100644 index 000000000..28e270b48 --- /dev/null +++ b/packages/reactnative/example/android/app/src/debug/java/com/reactnativesdkexample/ReactNativeFlipper.java @@ -0,0 +1,75 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + *

This source code is licensed under the MIT license found in the LICENSE file in the root + * directory of this source tree. + */ +package com.reactnativesdkexample; + +import android.content.Context; +import com.facebook.flipper.android.AndroidFlipperClient; +import com.facebook.flipper.android.utils.FlipperUtils; +import com.facebook.flipper.core.FlipperClient; +import com.facebook.flipper.plugins.crashreporter.CrashReporterPlugin; +import com.facebook.flipper.plugins.databases.DatabasesFlipperPlugin; +import com.facebook.flipper.plugins.fresco.FrescoFlipperPlugin; +import com.facebook.flipper.plugins.inspector.DescriptorMapping; +import com.facebook.flipper.plugins.inspector.InspectorFlipperPlugin; +import com.facebook.flipper.plugins.network.FlipperOkhttpInterceptor; +import com.facebook.flipper.plugins.network.NetworkFlipperPlugin; +import com.facebook.flipper.plugins.sharedpreferences.SharedPreferencesFlipperPlugin; +import com.facebook.react.ReactInstanceEventListener; +import com.facebook.react.ReactInstanceManager; +import com.facebook.react.bridge.ReactContext; +import com.facebook.react.modules.network.NetworkingModule; +import okhttp3.OkHttpClient; + +/** + * Class responsible of loading Flipper inside your React Native application. This is the debug + * flavor of it. Here you can add your own plugins and customize the Flipper setup. + */ +public class ReactNativeFlipper { + public static void initializeFlipper(Context context, ReactInstanceManager reactInstanceManager) { + if (FlipperUtils.shouldEnableFlipper(context)) { + final FlipperClient client = AndroidFlipperClient.getInstance(context); + + client.addPlugin(new InspectorFlipperPlugin(context, DescriptorMapping.withDefaults())); + client.addPlugin(new DatabasesFlipperPlugin(context)); + client.addPlugin(new SharedPreferencesFlipperPlugin(context)); + client.addPlugin(CrashReporterPlugin.getInstance()); + + NetworkFlipperPlugin networkFlipperPlugin = new NetworkFlipperPlugin(); + NetworkingModule.setCustomClientBuilder( + new NetworkingModule.CustomClientBuilder() { + @Override + public void apply(OkHttpClient.Builder builder) { + builder.addNetworkInterceptor(new FlipperOkhttpInterceptor(networkFlipperPlugin)); + } + }); + client.addPlugin(networkFlipperPlugin); + client.start(); + + // Fresco Plugin needs to ensure that ImagePipelineFactory is initialized + // Hence we run if after all native modules have been initialized + ReactContext reactContext = reactInstanceManager.getCurrentReactContext(); + if (reactContext == null) { + reactInstanceManager.addReactInstanceEventListener( + new ReactInstanceEventListener() { + @Override + public void onReactContextInitialized(ReactContext reactContext) { + reactInstanceManager.removeReactInstanceEventListener(this); + reactContext.runOnNativeModulesQueueThread( + new Runnable() { + @Override + public void run() { + client.addPlugin(new FrescoFlipperPlugin()); + } + }); + } + }); + } else { + client.addPlugin(new FrescoFlipperPlugin()); + } + } + } +} diff --git a/packages/reactnative/example/android/app/src/main/AndroidManifest.xml b/packages/reactnative/example/android/app/src/main/AndroidManifest.xml new file mode 100644 index 000000000..4122f36a5 --- /dev/null +++ b/packages/reactnative/example/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + diff --git a/packages/reactnative/example/android/app/src/main/java/com/reactnativesdkexample/MainActivity.java b/packages/reactnative/example/android/app/src/main/java/com/reactnativesdkexample/MainActivity.java new file mode 100644 index 000000000..93585fbcf --- /dev/null +++ b/packages/reactnative/example/android/app/src/main/java/com/reactnativesdkexample/MainActivity.java @@ -0,0 +1,35 @@ +package com.reactnativesdkexample; + +import com.facebook.react.ReactActivity; +import com.facebook.react.ReactActivityDelegate; +import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint; +import com.facebook.react.defaults.DefaultReactActivityDelegate; + +public class MainActivity extends ReactActivity { + + /** + * Returns the name of the main component registered from JavaScript. This is used to schedule + * rendering of the component. + */ + @Override + protected String getMainComponentName() { + return "ReactNativeSdkExample"; + } + + /** + * Returns the instance of the {@link ReactActivityDelegate}. Here we use a util class {@link + * DefaultReactActivityDelegate} which allows you to easily enable Fabric and Concurrent React + * (aka React 18) with two boolean flags. + */ + @Override + protected ReactActivityDelegate createReactActivityDelegate() { + return new DefaultReactActivityDelegate( + this, + getMainComponentName(), + // If you opted-in for the New Architecture, we enable the Fabric Renderer. + DefaultNewArchitectureEntryPoint.getFabricEnabled(), // fabricEnabled + // If you opted-in for the New Architecture, we enable Concurrent React (i.e. React 18). + DefaultNewArchitectureEntryPoint.getConcurrentReactEnabled() // concurrentRootEnabled + ); + } +} diff --git a/packages/reactnative/example/android/app/src/main/java/com/reactnativesdkexample/MainApplication.java b/packages/reactnative/example/android/app/src/main/java/com/reactnativesdkexample/MainApplication.java new file mode 100644 index 000000000..9f81d13c3 --- /dev/null +++ b/packages/reactnative/example/android/app/src/main/java/com/reactnativesdkexample/MainApplication.java @@ -0,0 +1,62 @@ +package com.reactnativesdkexample; + +import android.app.Application; +import com.facebook.react.PackageList; +import com.facebook.react.ReactApplication; +import com.facebook.react.ReactNativeHost; +import com.facebook.react.ReactPackage; +import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint; +import com.facebook.react.defaults.DefaultReactNativeHost; +import com.facebook.soloader.SoLoader; +import java.util.List; + +public class MainApplication extends Application implements ReactApplication { + + private final ReactNativeHost mReactNativeHost = + new DefaultReactNativeHost(this) { + @Override + public boolean getUseDeveloperSupport() { + return BuildConfig.DEBUG; + } + + @Override + protected List getPackages() { + @SuppressWarnings("UnnecessaryLocalVariable") + List packages = new PackageList(this).getPackages(); + // Packages that cannot be autolinked yet can be added manually here, for example: + // packages.add(new MyReactNativePackage()); + return packages; + } + + @Override + protected String getJSMainModuleName() { + return "index"; + } + + @Override + protected boolean isNewArchEnabled() { + return BuildConfig.IS_NEW_ARCHITECTURE_ENABLED; + } + + @Override + protected Boolean isHermesEnabled() { + return BuildConfig.IS_HERMES_ENABLED; + } + }; + + @Override + public ReactNativeHost getReactNativeHost() { + return mReactNativeHost; + } + + @Override + public void onCreate() { + super.onCreate(); + SoLoader.init(this, /* native exopackage */ false); + if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) { + // If you opted-in for the New Architecture, we load the native entry point for this app. + DefaultNewArchitectureEntryPoint.load(); + } + ReactNativeFlipper.initializeFlipper(this, getReactNativeHost().getReactInstanceManager()); + } +} diff --git a/packages/reactnative/example/android/app/src/main/res/drawable/rn_edit_text_material.xml b/packages/reactnative/example/android/app/src/main/res/drawable/rn_edit_text_material.xml new file mode 100644 index 000000000..f35d99620 --- /dev/null +++ b/packages/reactnative/example/android/app/src/main/res/drawable/rn_edit_text_material.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + diff --git a/packages/reactnative/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/packages/reactnative/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..a2f5908281d070150700378b64a84c7db1f97aa1 GIT binary patch literal 3056 zcmV(P)KhZB4W`O-$6PEY7dL@435|%iVhscI7#HXTET` zzkBaFzt27A{C?*?2n!1>p(V70me4Z57os7_P3wngt7(|N?Oyh#`(O{OZ1{A4;H+Oi zbkJV-pnX%EV7$w+V1moMaYCgzJI-a^GQPsJHL=>Zb!M$&E7r9HyP>8`*Pg_->7CeN zOX|dqbE6DBJL=}Mqt2*1e1I>(L-HP&UhjA?q1x7zSXD}D&D-Om%sC#AMr*KVk>dy;pT>Dpn#K6-YX8)fL(Q8(04+g?ah97XT2i$m2u z-*XXz7%$`O#x&6Oolq?+sA+c; zdg7fXirTUG`+!=-QudtfOZR*6Z3~!#;X;oEv56*-B z&gIGE3os@3O)sFP?zf;Z#kt18-o>IeueS!=#X^8WfI@&mfI@)!F(BkYxSfC*Gb*AM zau9@B_4f3=m1I71l8mRD>8A(lNb6V#dCpSKW%TT@VIMvFvz!K$oN1v#E@%Fp3O_sQ zmbSM-`}i8WCzSyPl?NqS^NqOYg4+tXT52ItLoTA;4mfx3-lev-HadLiA}!)%PwV)f zumi|*v}_P;*hk9-c*ibZqBd_ixhLQA+Xr>akm~QJCpfoT!u5JA_l@4qgMRf+Bi(Gh zBOtYM<*PnDOA}ls-7YrTVWimdA{y^37Q#BV>2&NKUfl(9F9G}lZ{!-VfTnZh-}vANUA=kZz5}{^<2t=| z{D>%{4**GFekzA~Ja)m81w<3IaIXdft(FZDD2oTruW#SJ?{Iv&cKenn!x!z;LfueD zEgN@#Px>AgO$sc`OMv1T5S~rp@e3-U7LqvJvr%uyV7jUKDBZYor^n# zR8bDS*jTTdV4l8ug<>o_Wk~%F&~lzw`sQGMi5{!yoTBs|8;>L zD=nbWe5~W67Tx`B@_@apzLKH@q=Nnj$a1EoQ%5m|;3}WxR@U0q^=umZUcB}dz5n^8 zPRAi!1T)V8qs-eWs$?h4sVncF`)j&1`Rr+-4of)XCppcuoV#0EZ8^>0Z2LYZirw#G7=POO0U*?2*&a7V zn|Dx3WhqT{6j8J_PmD=@ItKmb-GlN>yH5eJe%-WR0D8jh1;m54AEe#}goz`fh*C%j zA@%m2wr3qZET9NLoVZ5wfGuR*)rV2cmQPWftN8L9hzEHxlofT@rc|PhXZ&SGk>mLC z97(xCGaSV+)DeysP_%tl@Oe<6k9|^VIM*mQ(IU5vme)80qz-aOT3T(VOxU><7R4#;RZfTQeI$^m&cw@}f=eBDYZ+b&N$LyX$Au8*J1b9WPC zk_wIhRHgu=f&&@Yxg-Xl1xEnl3xHOm1xE(NEy@oLx8xXme*uJ-7cg)a=lVq}gm3{! z0}fh^fyW*tAa%6Dcq0I5z(K2#0Ga*a*!mkF5#0&|BxSS`fXa(?^Be)lY0}Me1R$45 z6OI7HbFTOffV^;gfOt%b+SH$3e*q)_&;q0p$}uAcAiX>XkqU#c790SX&E2~lkOB_G zKJ`C9ki9?xz)+Cm2tYb{js(c8o9FleQsy}_Ad5d7F((TOP!GQbT(nFhx6IBlIHLQ zgXXeN84Yfl5^NsSQ!kRoGoVyhyQXsYTgXWy@*K>_h02S>)Io^59+E)h zGFV5n!hjqv%Oc>+V;J$A_ekQjz$f-;Uace07pQvY6}%aIZUZ}_m*>DHx|mL$gUlGo zpJtxJ-3l!SVB~J4l=zq>$T4VaQ7?R}!7V7tvO_bJ8`$|ImsvN@kpXGtISd6|N&r&B zkpY!Z%;q4z)rd81@12)8F>qUU_(dxjkWQYX4XAxEmH?G>4ruF!AX<2qpdqxJ3I!SaZj(bdjDpXdS%NK!YvET$}#ao zW-QD5;qF}ZN4;`6g&z16w|Qd=`#4hg+UF^02UgmQka=%|A!5CjRL86{{mwzf=~v{&!Uo zYhJ00Shva@yJ59^Qq~$b)+5%gl79Qv*Gl#YS+BO+RQrr$dmQX)o6o-P_wHC$#H%aa z5o>q~f8c=-2(k3lb!CqFQJ;;7+2h#B$V_anm}>Zr(v{I_-09@zzZ yco6bG9zMVq_|y~s4rIt6QD_M*p(V5oh~@tmE4?#%!pj)|0000T-ViIFIPY+_yk1-RB&z5bHD$YnPieqLK5EI`ThRCq%$YyeCI#k z>wI&j0Rb2DV5|p6T3Syaq)GU^8BR8(!9qaEe6w+TJxLZtBeQf z`>{w%?oW}WhJSMi-;YIE3P2FtzE8p;}`HCT>Lt1o3h65;M`4J@U(hJSYlTt_?Ucf5~AOFjBT-*WTiV_&id z?xIZPQ`>7M-B?*vptTsj)0XBk37V2zTSQ5&6`0#pVU4dg+Hj7pb;*Hq8nfP(P;0i% zZ7k>Q#cTGyguV?0<0^_L$;~g|Qqw58DUr~LB=oigZFOvHc|MCM(KB_4-l{U|t!kPu z{+2Mishq{vnwb2YD{vj{q`%Pz?~D4B&S9Jdt##WlwvtR2)d5RdqcIvrs!MY#BgDI# z+FHxTmgQp-UG66D4?!;I0$Csk<6&IL09jn+yWmHxUf)alPUi3jBIdLtG|Yhn?vga< zJQBnaQ=Z?I+FZj;ke@5f{TVVT$$CMK74HfIhE?eMQ#fvN2%FQ1PrC+PAcEu?B*`Ek zcMD{^pd?8HMV94_qC0g+B1Z0CE-pcWpK=hDdq`{6kCxxq^X`oAYOb3VU6%K=Tx;aG z*aW$1G~wsy!mL})tMisLXN<*g$Kv)zHl{2OA=?^BLb)Q^Vqgm?irrLM$ds;2n7gHt zCDfI8Y=i4)=cx_G!FU+g^_nE(Xu7tj&a&{ln46@U3)^aEf}FHHud~H%_0~Jv>X{Pm z+E&ljy!{$my1j|HYXdy;#&&l9YpovJ;5yoQYJ+hw9>!H{(^6+$(%!(HeR~&MP-UER zPR&hH$w*_)D3}#A2joDlamSP}n%Y3H@pNb1wE=G1TFH_~Lp-&?b+q%;2IF8njO(rq zQVx(bn#@hTaqZZ1V{T#&p)zL%!r8%|p|TJLgSztxmyQo|0P;eUU~a0y&4)u?eEeGZ z9M6iN2(zw9a(WoxvL%S*jx5!2$E`ACG}F|2_)UTkqb*jyXm{3{73tLMlU%IiPK(UR4}Uv87uZIacp(XTRUs?6D25qn)QV%Xe&LZ-4bUJM!ZXtnKhY#Ws)^axZkui_Z=7 zOlc@%Gj$nLul=cEH-leGY`0T)`IQzNUSo}amQtL)O>v* zNJH1}B2znb;t8tf4-S6iL2_WuMVr~! zwa+Are(1_>{zqfTcoYN)&#lg$AVibhUwnFA33`np7$V)-5~MQcS~aE|Ha>IxGu+iU z`5{4rdTNR`nUc;CL5tfPI63~BlehRcnJ!4ecxOkD-b&G%-JG+r+}RH~wwPQoxuR(I z-89hLhH@)Hs}fNDM1>DUEO%{C;roF6#Q7w~76179D?Y9}nIJFZhWtv`=QNbzNiUmk zDSV5#xXQtcn9 zM{aI;AO6EH6GJ4^Qk!^F?$-lTQe+9ENYIeS9}cAj>Ir`dLe`4~Dulck2#9{o}JJ8v+QRsAAp*}|A^ z1PxxbEKFxar-$a&mz95(E1mAEVp{l!eF9?^K43Ol`+3Xh5z`aC(r}oEBpJK~e>zRtQ4J3K*r1f79xFs>v z5yhl1PoYg~%s#*ga&W@K>*NW($n~au>D~{Rrf@Tg z^DN4&Bf0C`6J*kHg5nCZIsyU%2RaiZkklvEqTMo0tFeq7{pp8`8oAs7 z6~-A=MiytuV+rI2R*|N=%Y));j8>F)XBFn`Aua-)_GpV`#%pda&MxsalV15+%Oy#U zg!?Gu&m@yfCi8xHM>9*N8|p5TPNucv?3|1$aN$&X6&Ge#g}?H`)4ncN@1whNDHF7u z2vU*@9OcC-MZK}lJ-H5CC@og69P#Ielf`le^Om4BZ|}OK33~dC z9o-007j1SXiTo3P#6`YJ^T4tN;KHfgA=+Bc0h1?>NT@P?=}W;Z=U;!nqzTHQbbu37 zOawJK2$GYeHtTr7EIjL_BS8~lBKT^)+ba(OWBsQT=QR3Ka((u#*VvW=A35XWkJ#?R zpRksL`?_C~VJ9Vz?VlXr?cJgMlaJZX!yWW}pMZni(bBP>?f&c#+p2KwnKwy;D3V1{ zdcX-Pb`YfI=B5+oN?J5>?Ne>U!2oCNarQ&KW7D61$fu$`2FQEWo&*AF%68{fn%L<4 zOsDg%m|-bklj!%zjsYZr0y6BFY|dpfDvJ0R9Qkr&a*QG0F`u&Rh{8=gq(fuuAaWc8 zRmup;5F zR3altfgBJbCrF7LP7t+8-2#HL9pn&HMVoEnPLE@KqNA~~s+Ze0ilWm}ucD8EVHs;p z@@l_VDhtt@6q zmV7pb1RO&XaRT)NOe-&7x7C>07@CZLYyn0GZl-MhPBNddM0N}0jayB22swGh3C!m6~r;0uCdOJ6>+nYo*R9J7Pzo%#X_imc=P;u^O*#06g*l)^?9O^cwu z>?m{qW(CawISAnzIf^A@vr*J$(bj4fMWG!DVMK9umxeS;rF)rOmvZY8%sF7i3NLrQ zCMI5u5>e<&Y4tpb@?!%PGzlgm_c^Z7Y6cO6C?)qfuF)!vOkifE(aGmXko*nI3Yr5_ zB%dP>Y)esVRQrVbP5?CtAV%1ftbeAX zSO5O8m|H+>?Ag7NFznXY-Y8iI#>Xdz<)ojC6nCuqwTY9Hlxg=lc7i-4fdWA$x8y)$ z1cEAfv{E7mnX=ZTvo30>Vc{EJ_@UqAo91Co;@r;u7&viaAa=(LUNnDMq#?t$WP2mu zy5`rr8b||Z0+BS)Iiwj0lqg10xE8QkK#>Cp6zNdxLb-wi+CW5b7zH2+M4p3Cj%WpQ zvV+J2IY@kOFU_|NN}2O}n#&F1oX*)lDd-WJICcPhckHVB{_D}UMo!YA)`reITkCv& z+h-AyO1k3@ZEIrpHB)j~Z(*sF@TFpx2IVtytZ1!gf7rg2x94b*P|1@%EFX{|BMC&F zgHR4<48Z5Wte`o!m*m@iyK=>9%pqjT=xfgQua>)1| zzH!~jLG!rggat+qAIR%H=jrI#Ppid$J{TDkck^wb>Cbnli}}Mj8!tNfx{tXtDDVA6#7kU4k)m;JoI1>JM_ zq-flQ5dpn>kG~=9u{Kp+hETG^OCq!Y^l7JkwUJNUU7izHmd|F@nB0=X2`Ui?!twzb zGEx%cIl)h?ZV$NTnhB6KFgkkRg&@c7ldg>o!`sBcgi%9RE?paz`QmZ@sF(jo1bt^} zOO5xhg(FXLQ|z)6CE=`kWOCVJNJCs#Lx)8bDSWkN@122J_Z`gpPK4kwk4&%uxnuQ z^m`!#WD#Y$Wd7NSpiP4Y;lHtj;pJ#m@{GmdPp+;QnX&E&oUq!YlgQ%hIuM43b=cWO zKEo!Er{mwD8T1>Qs$i2XjF2i zo0yfpKQUwdThrD(TOIY_s`L@_<}B|w^!j*FThM0+#t0G?oR`l(S(2v&bXR}F6HLMU zhVvD4K!6s}uUD^L;|Sxgrb+kFs%8d8Ma>5A9p~uUO=yF*;%~xvAJiA`lls1pq5J%k z6&-yQ$_vP5`-Tr56ws&75Y&Q2;zD?CB_KpRHxzC9hKCR0889>jef)|@@$A?!QIu3r qa)363hF;Bq?>HxvTY6qhhx>m(`%O(!)s{N|0000xsEBz6iy~SX+W%nrKL2KH{`gFsDCOB6ZW0@Yj?g&st+$-t|2c4&NM7M5Tk(z5p1+IN@y}=N)4$Vmgo_?Y@Ck5u}3=}@K z);Ns<{X)3-we^O|gm)Oh1^>hg6g=|b7E-r?H6QeeKvv7{-kP9)eb76lZ>I5?WDjiX z7Qu}=I4t9`G435HO)Jpt^;4t zottB%?uUE#zt^RaO&$**I5GbJM-Nj&Z#XT#=iLsG7*JO@)I~kH1#tl@P}J@i#`XX! zEUc>l4^`@w2_Fsoa*|Guk5hF2XJq0TQ{QXsjnJ)~K{EG*sHQW(a<^vuQkM07vtNw= z{=^9J-YI<#TM>DTE6u^^Z5vsVZx{Lxr@$j8f2PsXr^)~M97)OdjJOe81=H#lTbl`!5}35~o;+uSbUHP+6L00V99ox@t5JT2~=-{-Zvti4(UkQKDs{%?4V4AV3L`G476;|CgCH%rI z;0kA=z$nkcwu1-wIX=yE5wwUO)D;dT0m~o7z(f`*<1B>zJhsG0hYGMgQ0h>ylQYP; zbY|ogjI;7_P6BwI^6ZstC}cL&6%I8~cYe1LP)2R}amKG>qavWEwL0HNzwt@3hu-i0 z>tX4$uXNRX_<>h#Q`kvWAs3Y+9)i~VyAb3%4t+;Ej~o)%J#d6}9XXtC10QpHH*X!(vYjmZ zlmm6A=sN)+Lnfb)wzL90u6B=liNgkPm2tWfvU)a0y=N2gqg_uRzguCqXO<0 zp@5n^hzkW&E&~|ZnlPAz)<%Cdh;IgaTGMjVcP{dLFnX>K+DJ zd?m)lN&&u@soMY!B-jeeZNHfQIu7I&9N?AgMkXKxIC+JQibV=}9;p)91_6sP0x=oO zd9T#KhN9M8uO4rCDa ze;J+@sfk?@C6ke`KmkokKLLvbpNHGP^1^^YoBV^rxnXe8nl%NfKS}ea`^9weO&eZ` zo3Nb?%LfcmGM4c%PpK;~v#XWF+!|RaTd$6126a6)WGQPmv0E@fm9;I@#QpU0rcGEJ zNS_DL26^sx!>ccJF}F){`A0VIvLan^$?MI%g|@ebIFlrG&W$4|8=~H%Xsb{gawm(u zEgD&|uQgc{a;4k6J|qjRZzat^hbRSXZwu7(c-+?ku6G1X0c*0%*CyUsXxlKf=%wfS z7A!7+`^?MrPvs?yo31D=ZCu!3UU`+dR^S>@R%-y+!b$RlnflhseNn10MV5M=0KfZ+ zl9DEH0jK5}{VOgmzKClJ7?+=AED&7I=*K$;ONIUM3nyT|P}|NXn@Qhn<7H$I*mKw1 axPAxe%7rDusX+w*00006jj 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⁣ zwiG+x#%j}{0gU~J8;<|!B1@-XaB@{KORFwrYg_8rOv({b0EO#DbeQRm;B6_9=mXGf z-x|VL{zd`)#@yN}HkCSJbjbNlE|zL3Wm9Q8HY`sV)}3%pgN>cL^67{Z;PPL(*wT8N zUjXU{@|*hvm}({wsAC=x0^ok0%UAz0;sogW{B!nDqk|JJ5x~4NfTDgP49^zeu`csl?5mY@JdQdISc zFs!E{^grmkLnUk9 zny~m)1vws@5BFI<-0Tuo2JWX(0v`W|t(wg;s--L47WTvTMz-8l#TL^=OJNRS2?_Qj z3AKT+gvbyBi#H*-tJ%tWD|>EV3wy|8qxfzS!5RW;Jpl5*zo&^UBU=fG#2}UvRyNkK zA06Dy9;K1ca@r2T>yThYgI!ont$(G{6q#2QT+00r_x0(b)gsE`lBB?2gr55gq^D3Fi&p%E(p9>U%bv zkg1Jco(RbyTX7FDHOnl7-O@ zI$AaIl?9NJKPm(WiBP`1-#CB1QzU>&hKm)fpa5DKE{2$X0hGz-0uZ?cyTk(YC!Y&| zL=1VrNERSA5NA2jq7FACfX4JfPyj5XXl1yv0>~s;eF7L2$>&oMqeTFT2m$y7FlkON z_yurD1yIOvA;5C6016pyxBznGUt0kJ&k5r#;&>Jow`r)sp9R~PmK~lz$3xH%LT*1U zJdOyABZ3!FvNoR*vN$5ykHS8f`jA4zV+|L}i1C4`B2c{R0;UdYxaU|H)2avz@ z=mEYc|2S<+(B2Tj+FkX+2D+yFI!k9lWMA61DJ{)e;lum$(;O87?vGJJe!KtK04+N_ zI*P~t@dUb>9Xh{dbyl{-ZQ(UMgz7$|QfL5XSPkskt^NgctYC#;4WcZB1@%@wy@2t3 z2z0DI7&%b$*Aw~abe?GxE`ez@+6hOh-6*8fHRV{1os$EL@}uUZeG4h1&Be`98q*7j z=3-v+lhIjfWVo12!<>%V^a6lTgW3+_#W6n|p*~==zOH7z$0{LSZk(Tpd7EaD04hnA zL;#fxS0aD{`5^&D`}>0Uq?byDD-l2=!wm_bLcUl4gc(% za1p|itVANvFF>hghAS07Im1;IK;|b*W)}VDyI;BIp2=K*yu2a)j?B|f<44NI$NbmJ z#dE0>jI$fMr&@>4kN8MLFb4&2O9fEKaQg%(QO$4_1rVQywG^CmBLh#}_7gKW3vd?| z2?1^&KWq8}8I^_S0|)MowU_pw$q@nl@Nkn$z>BQq_KA^9yaR`(R3u{{Ig;cwt z@AJ^{ODQCm^neroM9nKNUAXi9RCK`OsP_LuR0PUR(YZCCX5dNF6VzcoK&=b^r`W?ltt|*F zpkoae%ZT{C1h~EcFui~b7fF`vb<<~j_VquuUA$}QqIKYELPp#;{u?q8Dz}WAG-(3; zjrm$i%7UbyZMM(Y{>!uJ#vNB?R~B{6Htp=>e*<{fQQ5W7V(1coCWlOON!MzZxhum| ztZBQpGR z;~#ur^&PockKdV{Q6R>o`Pl{0x!DEbpZ7y9Y;*ZvE!*gU`V1W3znva{f=?WO5I&>B z&hw6}tjECtaghm5z|C#%M;Yf_*pI^};h}Vl=^r9EN=tVDj86D;C$jIJ?K7VP+00000NkvXXu0mjf D5i!M* literal 0 HcmV?d00001 diff --git a/packages/reactnative/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/packages/reactnative/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png new file mode 100644 index 0000000000000000000000000000000000000000..459ca609d3ae0d3943ab44cdc27feef9256dc6d7 GIT binary patch literal 7098 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 literal 0 HcmV?d00001 diff --git a/packages/reactnative/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/packages/reactnative/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..8ca12fe024be86e868d14e91120a6902f8e88ac6 GIT binary patch literal 6464 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 B0*L?s literal 0 HcmV?d00001 diff --git a/packages/reactnative/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/packages/reactnative/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png new file mode 100644 index 0000000000000000000000000000000000000000..8e19b410a1b15ff180f3dacac19395fe3046cdec GIT binary patch literal 10676 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 literal 0 HcmV?d00001 diff --git a/packages/reactnative/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/packages/reactnative/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png new file mode 100644 index 0000000000000000000000000000000000000000..4c19a13c239cb67b8a2134ddd5f325db1d2d5bee GIT binary patch literal 15523 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 BIP(Ai literal 0 HcmV?d00001 diff --git a/packages/reactnative/example/android/app/src/main/res/values/strings.xml b/packages/reactnative/example/android/app/src/main/res/values/strings.xml new file mode 100644 index 000000000..9a4c824b4 --- /dev/null +++ b/packages/reactnative/example/android/app/src/main/res/values/strings.xml @@ -0,0 +1,3 @@ + + ReactNativeSdkExample + diff --git a/packages/reactnative/example/android/app/src/main/res/values/styles.xml b/packages/reactnative/example/android/app/src/main/res/values/styles.xml new file mode 100644 index 000000000..7ba83a2ad --- /dev/null +++ b/packages/reactnative/example/android/app/src/main/res/values/styles.xml @@ -0,0 +1,9 @@ + + + + + + diff --git a/packages/reactnative/example/android/app/src/release/java/com/reactnativesdkexample/ReactNativeFlipper.java b/packages/reactnative/example/android/app/src/release/java/com/reactnativesdkexample/ReactNativeFlipper.java new file mode 100644 index 000000000..5491ad36b --- /dev/null +++ b/packages/reactnative/example/android/app/src/release/java/com/reactnativesdkexample/ReactNativeFlipper.java @@ -0,0 +1,20 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + *

This source code is licensed under the MIT license found in the LICENSE file in the root + * directory of this source tree. + */ +package com.reactnativesdkexample; + +import android.content.Context; +import com.facebook.react.ReactInstanceManager; + +/** + * Class responsible of loading Flipper inside your React Native application. This is the release + * flavor of it so it's empty as we don't want to load Flipper. + */ +public class ReactNativeFlipper { + public static void initializeFlipper(Context context, ReactInstanceManager reactInstanceManager) { + // Do nothing as we don't want to initialize Flipper on Release. + } +} diff --git a/packages/reactnative/example/android/build.gradle b/packages/reactnative/example/android/build.gradle new file mode 100644 index 000000000..67d887b03 --- /dev/null +++ b/packages/reactnative/example/android/build.gradle @@ -0,0 +1,21 @@ +// Top-level build file where you can add configuration options common to all sub-projects/modules. + +buildscript { + ext { + buildToolsVersion = "33.0.0" + minSdkVersion = 21 + compileSdkVersion = 33 + targetSdkVersion = 33 + + // We use NDK 23 which has both M1 support and is the side-by-side NDK version from AGP. + ndkVersion = "23.1.7779620" + } + repositories { + google() + mavenCentral() + } + dependencies { + classpath("com.android.tools.build:gradle:7.3.1") + classpath("com.facebook.react:react-native-gradle-plugin") + } +} diff --git a/packages/reactnative/example/android/gradle.properties b/packages/reactnative/example/android/gradle.properties new file mode 100644 index 000000000..e4af465e8 --- /dev/null +++ b/packages/reactnative/example/android/gradle.properties @@ -0,0 +1,44 @@ +# Project-wide Gradle settings. + +# IDE (e.g. Android Studio) users: +# Gradle settings configured through the IDE *will override* +# any settings specified in this file. + +# For more details on how to configure your build environment visit +# http://www.gradle.org/docs/current/userguide/build_environment.html + +# Specifies the JVM arguments used for the daemon process. +# The setting is particularly useful for tweaking memory settings. +# Default value: -Xmx512m -XX:MaxMetaspaceSize=256m +org.gradle.jvmargs=-Xmx2048m -XX:MaxMetaspaceSize=512m + +# When configured, Gradle will run in incubating parallel mode. +# This option should only be used with decoupled projects. More details, visit +# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects +# org.gradle.parallel=true + +# AndroidX package structure to make it clearer which packages are bundled with the +# Android operating system, and which are packaged with your app's APK +# https://developer.android.com/topic/libraries/support-library/androidx-rn +android.useAndroidX=true +# Automatically convert third-party libraries to use AndroidX +android.enableJetifier=true + +# Version of flipper SDK to use with React Native +FLIPPER_VERSION=0.125.0 + +# Use this property to specify which architecture you want to build. +# You can also override it from the CLI using +# ./gradlew -PreactNativeArchitectures=x86_64 +reactNativeArchitectures=armeabi-v7a,arm64-v8a,x86,x86_64 + +# Use this property to enable support to the new architecture. +# This will allow you to use TurboModules and the Fabric render in +# your application. You should enable this flag either if you want +# to write custom TurboModules/Fabric components OR use libraries that +# are providing them. +newArchEnabled=false + +# Use this property to enable or disable the Hermes JS engine. +# If set to false, you will be using JSC instead. +hermesEnabled=true diff --git a/packages/reactnative/example/android/gradle/wrapper/gradle-wrapper.jar b/packages/reactnative/example/android/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..41d9927a4d4fb3f96a785543079b8df6723c946b GIT binary patch literal 59821 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 literal 0 HcmV?d00001 diff --git a/packages/reactnative/example/android/gradle/wrapper/gradle-wrapper.properties b/packages/reactnative/example/android/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 000000000..8fad3f5a9 --- /dev/null +++ b/packages/reactnative/example/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-all.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/packages/reactnative/example/android/gradlew b/packages/reactnative/example/android/gradlew new file mode 100755 index 000000000..1b6c78733 --- /dev/null +++ b/packages/reactnative/example/android/gradlew @@ -0,0 +1,234 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit + +APP_NAME="Gradle" +APP_BASE_NAME=${0##*/} + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/packages/reactnative/example/android/gradlew.bat b/packages/reactnative/example/android/gradlew.bat new file mode 100644 index 000000000..107acd32c --- /dev/null +++ b/packages/reactnative/example/android/gradlew.bat @@ -0,0 +1,89 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/packages/reactnative/example/android/settings.gradle b/packages/reactnative/example/android/settings.gradle new file mode 100644 index 000000000..0dc839ff8 --- /dev/null +++ b/packages/reactnative/example/android/settings.gradle @@ -0,0 +1,4 @@ +rootProject.name = 'ReactNativeSdkExample' +apply from: file("../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesSettingsGradle(settings) +include ':app' +includeBuild('../node_modules/react-native-gradle-plugin') diff --git a/packages/reactnative/example/app.json b/packages/reactnative/example/app.json new file mode 100644 index 000000000..45952059e --- /dev/null +++ b/packages/reactnative/example/app.json @@ -0,0 +1,4 @@ +{ + "name": "ReactNativeSdkExample", + "displayName": "ReactNativeSdkExample" +} \ No newline at end of file diff --git a/packages/reactnative/example/babel.config.js b/packages/reactnative/example/babel.config.js new file mode 100644 index 000000000..d66f68421 --- /dev/null +++ b/packages/reactnative/example/babel.config.js @@ -0,0 +1,25 @@ +const path = require('path'); +const pak = require('../package.json'); + +module.exports = { + presets: ['module:metro-react-native-babel-preset'], + plugins: [ + [ + 'module-resolver', + { + extensions: ['.tsx', '.ts', '.js', '.json'], + alias: { + [pak.name]: path.join(__dirname, '..', pak.source), + }, + }, + ], + [ + 'module:react-native-dotenv', + { + envName: 'APP_ENV', + moduleName: '@env', + path: '.env', + }, + ], + ], +}; diff --git a/packages/reactnative/example/index.js b/packages/reactnative/example/index.js new file mode 100644 index 000000000..117ddcae4 --- /dev/null +++ b/packages/reactnative/example/index.js @@ -0,0 +1,5 @@ +import { AppRegistry } from 'react-native'; +import App from './src/App'; +import { name as appName } from './app.json'; + +AppRegistry.registerComponent(appName, () => App); diff --git a/packages/reactnative/example/ios/File.swift b/packages/reactnative/example/ios/File.swift new file mode 100644 index 000000000..88c4f5252 --- /dev/null +++ b/packages/reactnative/example/ios/File.swift @@ -0,0 +1,6 @@ +// +// File.swift +// ReactNativeSdkExample +// + +import Foundation diff --git a/packages/reactnative/example/ios/Podfile b/packages/reactnative/example/ios/Podfile new file mode 100644 index 000000000..ef5d238fe --- /dev/null +++ b/packages/reactnative/example/ios/Podfile @@ -0,0 +1,60 @@ +require_relative '../node_modules/react-native/scripts/react_native_pods' +require_relative '../node_modules/@react-native-community/cli-platform-ios/native_modules' + +platform :ios, min_ios_version_supported +prepare_react_native_project! + +# If you are using a `react-native-flipper` your iOS build will fail when `NO_FLIPPER=1` is set. +# because `react-native-flipper` depends on (FlipperKit,...) that will be excluded +# +# To fix this you can also exclude `react-native-flipper` using a `react-native.config.js` +# ```js +# module.exports = { +# dependencies: { +# ...(process.env.NO_FLIPPER ? { 'react-native-flipper': { platforms: { ios: null } } } : {}), +# ``` +flipper_config = ENV['NO_FLIPPER'] == "1" ? FlipperConfiguration.disabled : FlipperConfiguration.enabled + +linkage = ENV['USE_FRAMEWORKS'] +if linkage != nil + Pod::UI.puts "Configuring Pod with #{linkage}ally linked Frameworks".green + use_frameworks! :linkage => linkage.to_sym +end + +target 'ReactNativeSdkExample' do + config = use_native_modules! + + # Flags change depending on the env values. + flags = get_default_flags() + + use_react_native!( + :path => config[:reactNativePath], + # Hermes is now enabled by default. Disable by setting this flag to false. + # Upcoming versions of React Native may rely on get_default_flags(), but + # we make it explicit here to aid in the React Native upgrade process. + :hermes_enabled => flags[:hermes_enabled], + :fabric_enabled => flags[:fabric_enabled], + # Enables Flipper. + # + # Note that if you have use_frameworks! enabled, Flipper will not work and + # you should disable the next line. + :flipper_configuration => flipper_config, + # An absolute path to your application root. + :app_path => "#{Pod::Config.instance.installation_root}/.." + ) + + target 'ReactNativeSdkExampleTests' do + inherit! :complete + # Pods for testing + end + + post_install do |installer| + react_native_post_install( + installer, + # Set `mac_catalyst_enabled` to `true` in order to apply patches + # necessary for Mac Catalyst builds + :mac_catalyst_enabled => false + ) + __apply_Xcode_12_5_M1_post_install_workaround(installer) + end +end diff --git a/packages/reactnative/example/ios/Podfile.lock b/packages/reactnative/example/ios/Podfile.lock new file mode 100644 index 000000000..571da8c5e --- /dev/null +++ b/packages/reactnative/example/ios/Podfile.lock @@ -0,0 +1,641 @@ +PODS: + - boost (1.76.0) + - CocoaAsyncSocket (7.6.5) + - DoubleConversion (1.1.6) + - FBLazyVector (0.71.11) + - FBReactNativeSpec (0.71.11): + - RCT-Folly (= 2021.07.22.00) + - RCTRequired (= 0.71.11) + - RCTTypeSafety (= 0.71.11) + - React-Core (= 0.71.11) + - React-jsi (= 0.71.11) + - ReactCommon/turbomodule/core (= 0.71.11) + - Flipper (0.125.0): + - Flipper-Folly (~> 2.6) + - Flipper-RSocket (~> 1.4) + - Flipper-Boost-iOSX (1.76.0.1.11) + - Flipper-DoubleConversion (3.2.0.1) + - Flipper-Fmt (7.1.7) + - Flipper-Folly (2.6.10): + - Flipper-Boost-iOSX + - Flipper-DoubleConversion + - Flipper-Fmt (= 7.1.7) + - Flipper-Glog + - libevent (~> 2.1.12) + - OpenSSL-Universal (= 1.1.1100) + - Flipper-Glog (0.5.0.5) + - Flipper-PeerTalk (0.0.4) + - Flipper-RSocket (1.4.3): + - Flipper-Folly (~> 2.6) + - FlipperKit (0.125.0): + - FlipperKit/Core (= 0.125.0) + - FlipperKit/Core (0.125.0): + - Flipper (~> 0.125.0) + - FlipperKit/CppBridge + - FlipperKit/FBCxxFollyDynamicConvert + - FlipperKit/FBDefines + - FlipperKit/FKPortForwarding + - SocketRocket (~> 0.6.0) + - FlipperKit/CppBridge (0.125.0): + - Flipper (~> 0.125.0) + - FlipperKit/FBCxxFollyDynamicConvert (0.125.0): + - Flipper-Folly (~> 2.6) + - FlipperKit/FBDefines (0.125.0) + - FlipperKit/FKPortForwarding (0.125.0): + - CocoaAsyncSocket (~> 7.6) + - Flipper-PeerTalk (~> 0.0.4) + - FlipperKit/FlipperKitHighlightOverlay (0.125.0) + - FlipperKit/FlipperKitLayoutHelpers (0.125.0): + - FlipperKit/Core + - FlipperKit/FlipperKitHighlightOverlay + - FlipperKit/FlipperKitLayoutTextSearchable + - FlipperKit/FlipperKitLayoutIOSDescriptors (0.125.0): + - FlipperKit/Core + - FlipperKit/FlipperKitHighlightOverlay + - FlipperKit/FlipperKitLayoutHelpers + - YogaKit (~> 1.18) + - FlipperKit/FlipperKitLayoutPlugin (0.125.0): + - FlipperKit/Core + - FlipperKit/FlipperKitHighlightOverlay + - FlipperKit/FlipperKitLayoutHelpers + - FlipperKit/FlipperKitLayoutIOSDescriptors + - FlipperKit/FlipperKitLayoutTextSearchable + - YogaKit (~> 1.18) + - FlipperKit/FlipperKitLayoutTextSearchable (0.125.0) + - FlipperKit/FlipperKitNetworkPlugin (0.125.0): + - FlipperKit/Core + - FlipperKit/FlipperKitReactPlugin (0.125.0): + - FlipperKit/Core + - FlipperKit/FlipperKitUserDefaultsPlugin (0.125.0): + - FlipperKit/Core + - FlipperKit/SKIOSNetworkPlugin (0.125.0): + - FlipperKit/Core + - FlipperKit/FlipperKitNetworkPlugin + - fmt (6.2.1) + - glog (0.3.5) + - hermes-engine (0.71.11): + - hermes-engine/Pre-built (= 0.71.11) + - hermes-engine/Pre-built (0.71.11) + - libevent (2.1.12) + - OpenSSL-Universal (1.1.1100) + - push-react-native-sdk (0.1.0): + - React-Core + - RCT-Folly (2021.07.22.00): + - boost + - DoubleConversion + - fmt (~> 6.2.1) + - glog + - RCT-Folly/Default (= 2021.07.22.00) + - RCT-Folly/Default (2021.07.22.00): + - boost + - DoubleConversion + - fmt (~> 6.2.1) + - glog + - RCT-Folly/Futures (2021.07.22.00): + - boost + - DoubleConversion + - fmt (~> 6.2.1) + - glog + - libevent + - RCTRequired (0.71.11) + - RCTTypeSafety (0.71.11): + - FBLazyVector (= 0.71.11) + - RCTRequired (= 0.71.11) + - React-Core (= 0.71.11) + - React (0.71.11): + - React-Core (= 0.71.11) + - React-Core/DevSupport (= 0.71.11) + - React-Core/RCTWebSocket (= 0.71.11) + - React-RCTActionSheet (= 0.71.11) + - React-RCTAnimation (= 0.71.11) + - React-RCTBlob (= 0.71.11) + - React-RCTImage (= 0.71.11) + - React-RCTLinking (= 0.71.11) + - React-RCTNetwork (= 0.71.11) + - React-RCTSettings (= 0.71.11) + - React-RCTText (= 0.71.11) + - React-RCTVibration (= 0.71.11) + - React-callinvoker (0.71.11) + - React-Codegen (0.71.11): + - FBReactNativeSpec + - hermes-engine + - RCT-Folly + - RCTRequired + - RCTTypeSafety + - React-Core + - React-jsi + - React-jsiexecutor + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - React-Core (0.71.11): + - glog + - hermes-engine + - RCT-Folly (= 2021.07.22.00) + - React-Core/Default (= 0.71.11) + - React-cxxreact (= 0.71.11) + - React-hermes + - React-jsi (= 0.71.11) + - React-jsiexecutor (= 0.71.11) + - React-perflogger (= 0.71.11) + - Yoga + - React-Core/CoreModulesHeaders (0.71.11): + - glog + - hermes-engine + - RCT-Folly (= 2021.07.22.00) + - React-Core/Default + - React-cxxreact (= 0.71.11) + - React-hermes + - React-jsi (= 0.71.11) + - React-jsiexecutor (= 0.71.11) + - React-perflogger (= 0.71.11) + - Yoga + - React-Core/Default (0.71.11): + - glog + - hermes-engine + - RCT-Folly (= 2021.07.22.00) + - React-cxxreact (= 0.71.11) + - React-hermes + - React-jsi (= 0.71.11) + - React-jsiexecutor (= 0.71.11) + - React-perflogger (= 0.71.11) + - Yoga + - React-Core/DevSupport (0.71.11): + - glog + - hermes-engine + - RCT-Folly (= 2021.07.22.00) + - React-Core/Default (= 0.71.11) + - React-Core/RCTWebSocket (= 0.71.11) + - React-cxxreact (= 0.71.11) + - React-hermes + - React-jsi (= 0.71.11) + - React-jsiexecutor (= 0.71.11) + - React-jsinspector (= 0.71.11) + - React-perflogger (= 0.71.11) + - Yoga + - React-Core/RCTActionSheetHeaders (0.71.11): + - glog + - hermes-engine + - RCT-Folly (= 2021.07.22.00) + - React-Core/Default + - React-cxxreact (= 0.71.11) + - React-hermes + - React-jsi (= 0.71.11) + - React-jsiexecutor (= 0.71.11) + - React-perflogger (= 0.71.11) + - Yoga + - React-Core/RCTAnimationHeaders (0.71.11): + - glog + - hermes-engine + - RCT-Folly (= 2021.07.22.00) + - React-Core/Default + - React-cxxreact (= 0.71.11) + - React-hermes + - React-jsi (= 0.71.11) + - React-jsiexecutor (= 0.71.11) + - React-perflogger (= 0.71.11) + - Yoga + - React-Core/RCTBlobHeaders (0.71.11): + - glog + - hermes-engine + - RCT-Folly (= 2021.07.22.00) + - React-Core/Default + - React-cxxreact (= 0.71.11) + - React-hermes + - React-jsi (= 0.71.11) + - React-jsiexecutor (= 0.71.11) + - React-perflogger (= 0.71.11) + - Yoga + - React-Core/RCTImageHeaders (0.71.11): + - glog + - hermes-engine + - RCT-Folly (= 2021.07.22.00) + - React-Core/Default + - React-cxxreact (= 0.71.11) + - React-hermes + - React-jsi (= 0.71.11) + - React-jsiexecutor (= 0.71.11) + - React-perflogger (= 0.71.11) + - Yoga + - React-Core/RCTLinkingHeaders (0.71.11): + - glog + - hermes-engine + - RCT-Folly (= 2021.07.22.00) + - React-Core/Default + - React-cxxreact (= 0.71.11) + - React-hermes + - React-jsi (= 0.71.11) + - React-jsiexecutor (= 0.71.11) + - React-perflogger (= 0.71.11) + - Yoga + - React-Core/RCTNetworkHeaders (0.71.11): + - glog + - hermes-engine + - RCT-Folly (= 2021.07.22.00) + - React-Core/Default + - React-cxxreact (= 0.71.11) + - React-hermes + - React-jsi (= 0.71.11) + - React-jsiexecutor (= 0.71.11) + - React-perflogger (= 0.71.11) + - Yoga + - React-Core/RCTSettingsHeaders (0.71.11): + - glog + - hermes-engine + - RCT-Folly (= 2021.07.22.00) + - React-Core/Default + - React-cxxreact (= 0.71.11) + - React-hermes + - React-jsi (= 0.71.11) + - React-jsiexecutor (= 0.71.11) + - React-perflogger (= 0.71.11) + - Yoga + - React-Core/RCTTextHeaders (0.71.11): + - glog + - hermes-engine + - RCT-Folly (= 2021.07.22.00) + - React-Core/Default + - React-cxxreact (= 0.71.11) + - React-hermes + - React-jsi (= 0.71.11) + - React-jsiexecutor (= 0.71.11) + - React-perflogger (= 0.71.11) + - Yoga + - React-Core/RCTVibrationHeaders (0.71.11): + - glog + - hermes-engine + - RCT-Folly (= 2021.07.22.00) + - React-Core/Default + - React-cxxreact (= 0.71.11) + - React-hermes + - React-jsi (= 0.71.11) + - React-jsiexecutor (= 0.71.11) + - React-perflogger (= 0.71.11) + - Yoga + - React-Core/RCTWebSocket (0.71.11): + - glog + - hermes-engine + - RCT-Folly (= 2021.07.22.00) + - React-Core/Default (= 0.71.11) + - React-cxxreact (= 0.71.11) + - React-hermes + - React-jsi (= 0.71.11) + - React-jsiexecutor (= 0.71.11) + - React-perflogger (= 0.71.11) + - Yoga + - React-CoreModules (0.71.11): + - RCT-Folly (= 2021.07.22.00) + - RCTTypeSafety (= 0.71.11) + - React-Codegen (= 0.71.11) + - React-Core/CoreModulesHeaders (= 0.71.11) + - React-jsi (= 0.71.11) + - React-RCTBlob + - React-RCTImage (= 0.71.11) + - ReactCommon/turbomodule/core (= 0.71.11) + - React-cxxreact (0.71.11): + - boost (= 1.76.0) + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly (= 2021.07.22.00) + - React-callinvoker (= 0.71.11) + - React-jsi (= 0.71.11) + - React-jsinspector (= 0.71.11) + - React-logger (= 0.71.11) + - React-perflogger (= 0.71.11) + - React-runtimeexecutor (= 0.71.11) + - React-hermes (0.71.11): + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly (= 2021.07.22.00) + - RCT-Folly/Futures (= 2021.07.22.00) + - React-cxxreact (= 0.71.11) + - React-jsi + - React-jsiexecutor (= 0.71.11) + - React-jsinspector (= 0.71.11) + - React-perflogger (= 0.71.11) + - React-jsi (0.71.11): + - boost (= 1.76.0) + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly (= 2021.07.22.00) + - React-jsiexecutor (0.71.11): + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly (= 2021.07.22.00) + - React-cxxreact (= 0.71.11) + - React-jsi (= 0.71.11) + - React-perflogger (= 0.71.11) + - React-jsinspector (0.71.11) + - React-logger (0.71.11): + - glog + - react-native-fast-openpgp (2.6.0): + - React-Core + - react-native-webview (13.2.2): + - React-Core + - React-perflogger (0.71.11) + - React-RCTActionSheet (0.71.11): + - React-Core/RCTActionSheetHeaders (= 0.71.11) + - React-RCTAnimation (0.71.11): + - RCT-Folly (= 2021.07.22.00) + - RCTTypeSafety (= 0.71.11) + - React-Codegen (= 0.71.11) + - React-Core/RCTAnimationHeaders (= 0.71.11) + - React-jsi (= 0.71.11) + - ReactCommon/turbomodule/core (= 0.71.11) + - React-RCTAppDelegate (0.71.11): + - RCT-Folly + - RCTRequired + - RCTTypeSafety + - React-Core + - ReactCommon/turbomodule/core + - React-RCTBlob (0.71.11): + - hermes-engine + - RCT-Folly (= 2021.07.22.00) + - React-Codegen (= 0.71.11) + - React-Core/RCTBlobHeaders (= 0.71.11) + - React-Core/RCTWebSocket (= 0.71.11) + - React-jsi (= 0.71.11) + - React-RCTNetwork (= 0.71.11) + - ReactCommon/turbomodule/core (= 0.71.11) + - React-RCTImage (0.71.11): + - RCT-Folly (= 2021.07.22.00) + - RCTTypeSafety (= 0.71.11) + - React-Codegen (= 0.71.11) + - React-Core/RCTImageHeaders (= 0.71.11) + - React-jsi (= 0.71.11) + - React-RCTNetwork (= 0.71.11) + - ReactCommon/turbomodule/core (= 0.71.11) + - React-RCTLinking (0.71.11): + - React-Codegen (= 0.71.11) + - React-Core/RCTLinkingHeaders (= 0.71.11) + - React-jsi (= 0.71.11) + - ReactCommon/turbomodule/core (= 0.71.11) + - React-RCTNetwork (0.71.11): + - RCT-Folly (= 2021.07.22.00) + - RCTTypeSafety (= 0.71.11) + - React-Codegen (= 0.71.11) + - React-Core/RCTNetworkHeaders (= 0.71.11) + - React-jsi (= 0.71.11) + - ReactCommon/turbomodule/core (= 0.71.11) + - React-RCTSettings (0.71.11): + - RCT-Folly (= 2021.07.22.00) + - RCTTypeSafety (= 0.71.11) + - React-Codegen (= 0.71.11) + - React-Core/RCTSettingsHeaders (= 0.71.11) + - React-jsi (= 0.71.11) + - ReactCommon/turbomodule/core (= 0.71.11) + - React-RCTText (0.71.11): + - React-Core/RCTTextHeaders (= 0.71.11) + - React-RCTVibration (0.71.11): + - RCT-Folly (= 2021.07.22.00) + - React-Codegen (= 0.71.11) + - React-Core/RCTVibrationHeaders (= 0.71.11) + - React-jsi (= 0.71.11) + - ReactCommon/turbomodule/core (= 0.71.11) + - React-runtimeexecutor (0.71.11): + - React-jsi (= 0.71.11) + - ReactCommon/turbomodule/bridging (0.71.11): + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly (= 2021.07.22.00) + - React-callinvoker (= 0.71.11) + - React-Core (= 0.71.11) + - React-cxxreact (= 0.71.11) + - React-jsi (= 0.71.11) + - React-logger (= 0.71.11) + - React-perflogger (= 0.71.11) + - ReactCommon/turbomodule/core (0.71.11): + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly (= 2021.07.22.00) + - React-callinvoker (= 0.71.11) + - React-Core (= 0.71.11) + - React-cxxreact (= 0.71.11) + - React-jsi (= 0.71.11) + - React-logger (= 0.71.11) + - React-perflogger (= 0.71.11) + - SocketRocket (0.6.0) + - Yoga (1.14.0) + - YogaKit (1.18.1): + - Yoga (~> 1.14) + +DEPENDENCIES: + - boost (from `../node_modules/react-native/third-party-podspecs/boost.podspec`) + - DoubleConversion (from `../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec`) + - FBLazyVector (from `../node_modules/react-native/Libraries/FBLazyVector`) + - FBReactNativeSpec (from `../node_modules/react-native/React/FBReactNativeSpec`) + - Flipper (= 0.125.0) + - Flipper-Boost-iOSX (= 1.76.0.1.11) + - Flipper-DoubleConversion (= 3.2.0.1) + - Flipper-Fmt (= 7.1.7) + - Flipper-Folly (= 2.6.10) + - Flipper-Glog (= 0.5.0.5) + - Flipper-PeerTalk (= 0.0.4) + - Flipper-RSocket (= 1.4.3) + - FlipperKit (= 0.125.0) + - FlipperKit/Core (= 0.125.0) + - FlipperKit/CppBridge (= 0.125.0) + - FlipperKit/FBCxxFollyDynamicConvert (= 0.125.0) + - FlipperKit/FBDefines (= 0.125.0) + - FlipperKit/FKPortForwarding (= 0.125.0) + - FlipperKit/FlipperKitHighlightOverlay (= 0.125.0) + - FlipperKit/FlipperKitLayoutPlugin (= 0.125.0) + - FlipperKit/FlipperKitLayoutTextSearchable (= 0.125.0) + - FlipperKit/FlipperKitNetworkPlugin (= 0.125.0) + - FlipperKit/FlipperKitReactPlugin (= 0.125.0) + - FlipperKit/FlipperKitUserDefaultsPlugin (= 0.125.0) + - FlipperKit/SKIOSNetworkPlugin (= 0.125.0) + - glog (from `../node_modules/react-native/third-party-podspecs/glog.podspec`) + - hermes-engine (from `../node_modules/react-native/sdks/hermes-engine/hermes-engine.podspec`) + - libevent (~> 2.1.12) + - OpenSSL-Universal (= 1.1.1100) + - push-react-native-sdk (from `../..`) + - RCT-Folly (from `../node_modules/react-native/third-party-podspecs/RCT-Folly.podspec`) + - RCTRequired (from `../node_modules/react-native/Libraries/RCTRequired`) + - RCTTypeSafety (from `../node_modules/react-native/Libraries/TypeSafety`) + - React (from `../node_modules/react-native/`) + - React-callinvoker (from `../node_modules/react-native/ReactCommon/callinvoker`) + - React-Codegen (from `build/generated/ios`) + - React-Core (from `../node_modules/react-native/`) + - React-Core/DevSupport (from `../node_modules/react-native/`) + - React-Core/RCTWebSocket (from `../node_modules/react-native/`) + - React-CoreModules (from `../node_modules/react-native/React/CoreModules`) + - React-cxxreact (from `../node_modules/react-native/ReactCommon/cxxreact`) + - React-hermes (from `../node_modules/react-native/ReactCommon/hermes`) + - React-jsi (from `../node_modules/react-native/ReactCommon/jsi`) + - React-jsiexecutor (from `../node_modules/react-native/ReactCommon/jsiexecutor`) + - React-jsinspector (from `../node_modules/react-native/ReactCommon/jsinspector`) + - React-logger (from `../node_modules/react-native/ReactCommon/logger`) + - react-native-fast-openpgp (from `../node_modules/react-native-fast-openpgp`) + - react-native-webview (from `../node_modules/react-native-webview`) + - React-perflogger (from `../node_modules/react-native/ReactCommon/reactperflogger`) + - React-RCTActionSheet (from `../node_modules/react-native/Libraries/ActionSheetIOS`) + - React-RCTAnimation (from `../node_modules/react-native/Libraries/NativeAnimation`) + - React-RCTAppDelegate (from `../node_modules/react-native/Libraries/AppDelegate`) + - React-RCTBlob (from `../node_modules/react-native/Libraries/Blob`) + - React-RCTImage (from `../node_modules/react-native/Libraries/Image`) + - React-RCTLinking (from `../node_modules/react-native/Libraries/LinkingIOS`) + - React-RCTNetwork (from `../node_modules/react-native/Libraries/Network`) + - React-RCTSettings (from `../node_modules/react-native/Libraries/Settings`) + - React-RCTText (from `../node_modules/react-native/Libraries/Text`) + - React-RCTVibration (from `../node_modules/react-native/Libraries/Vibration`) + - React-runtimeexecutor (from `../node_modules/react-native/ReactCommon/runtimeexecutor`) + - ReactCommon/turbomodule/core (from `../node_modules/react-native/ReactCommon`) + - Yoga (from `../node_modules/react-native/ReactCommon/yoga`) + +SPEC REPOS: + trunk: + - CocoaAsyncSocket + - Flipper + - Flipper-Boost-iOSX + - Flipper-DoubleConversion + - Flipper-Fmt + - Flipper-Folly + - Flipper-Glog + - Flipper-PeerTalk + - Flipper-RSocket + - FlipperKit + - fmt + - libevent + - OpenSSL-Universal + - SocketRocket + - YogaKit + +EXTERNAL SOURCES: + boost: + :podspec: "../node_modules/react-native/third-party-podspecs/boost.podspec" + DoubleConversion: + :podspec: "../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec" + FBLazyVector: + :path: "../node_modules/react-native/Libraries/FBLazyVector" + FBReactNativeSpec: + :path: "../node_modules/react-native/React/FBReactNativeSpec" + glog: + :podspec: "../node_modules/react-native/third-party-podspecs/glog.podspec" + hermes-engine: + :podspec: "../node_modules/react-native/sdks/hermes-engine/hermes-engine.podspec" + push-react-native-sdk: + :path: "../.." + RCT-Folly: + :podspec: "../node_modules/react-native/third-party-podspecs/RCT-Folly.podspec" + RCTRequired: + :path: "../node_modules/react-native/Libraries/RCTRequired" + RCTTypeSafety: + :path: "../node_modules/react-native/Libraries/TypeSafety" + React: + :path: "../node_modules/react-native/" + React-callinvoker: + :path: "../node_modules/react-native/ReactCommon/callinvoker" + React-Codegen: + :path: build/generated/ios + React-Core: + :path: "../node_modules/react-native/" + React-CoreModules: + :path: "../node_modules/react-native/React/CoreModules" + React-cxxreact: + :path: "../node_modules/react-native/ReactCommon/cxxreact" + React-hermes: + :path: "../node_modules/react-native/ReactCommon/hermes" + React-jsi: + :path: "../node_modules/react-native/ReactCommon/jsi" + React-jsiexecutor: + :path: "../node_modules/react-native/ReactCommon/jsiexecutor" + React-jsinspector: + :path: "../node_modules/react-native/ReactCommon/jsinspector" + React-logger: + :path: "../node_modules/react-native/ReactCommon/logger" + react-native-fast-openpgp: + :path: "../node_modules/react-native-fast-openpgp" + react-native-webview: + :path: "../node_modules/react-native-webview" + React-perflogger: + :path: "../node_modules/react-native/ReactCommon/reactperflogger" + React-RCTActionSheet: + :path: "../node_modules/react-native/Libraries/ActionSheetIOS" + React-RCTAnimation: + :path: "../node_modules/react-native/Libraries/NativeAnimation" + React-RCTAppDelegate: + :path: "../node_modules/react-native/Libraries/AppDelegate" + React-RCTBlob: + :path: "../node_modules/react-native/Libraries/Blob" + React-RCTImage: + :path: "../node_modules/react-native/Libraries/Image" + React-RCTLinking: + :path: "../node_modules/react-native/Libraries/LinkingIOS" + React-RCTNetwork: + :path: "../node_modules/react-native/Libraries/Network" + React-RCTSettings: + :path: "../node_modules/react-native/Libraries/Settings" + React-RCTText: + :path: "../node_modules/react-native/Libraries/Text" + React-RCTVibration: + :path: "../node_modules/react-native/Libraries/Vibration" + React-runtimeexecutor: + :path: "../node_modules/react-native/ReactCommon/runtimeexecutor" + ReactCommon: + :path: "../node_modules/react-native/ReactCommon" + Yoga: + :path: "../node_modules/react-native/ReactCommon/yoga" + +SPEC CHECKSUMS: + boost: 57d2868c099736d80fcd648bf211b4431e51a558 + CocoaAsyncSocket: 065fd1e645c7abab64f7a6a2007a48038fdc6a99 + DoubleConversion: 5189b271737e1565bdce30deb4a08d647e3f5f54 + FBLazyVector: c511d4cd0210f416cb5c289bd5ae6b36d909b048 + FBReactNativeSpec: a911fb22def57aef1d74215e8b6b8761d25c1c54 + Flipper: 26fc4b7382499f1281eb8cb921e5c3ad6de91fe0 + Flipper-Boost-iOSX: fd1e2b8cbef7e662a122412d7ac5f5bea715403c + Flipper-DoubleConversion: 2dc99b02f658daf147069aad9dbd29d8feb06d30 + Flipper-Fmt: 60cbdd92fc254826e61d669a5d87ef7015396a9b + Flipper-Folly: 584845625005ff068a6ebf41f857f468decd26b3 + Flipper-Glog: 70c50ce58ddaf67dc35180db05f191692570f446 + Flipper-PeerTalk: 116d8f857dc6ef55c7a5a75ea3ceaafe878aadc9 + Flipper-RSocket: d9d9ade67cbecf6ac10730304bf5607266dd2541 + FlipperKit: cbdee19bdd4e7f05472a66ce290f1b729ba3cb86 + fmt: ff9d55029c625d3757ed641535fd4a75fedc7ce9 + glog: 04b94705f318337d7ead9e6d17c019bd9b1f6b1b + hermes-engine: 34c863b446d0135b85a6536fa5fd89f48196f848 + libevent: 4049cae6c81cdb3654a443be001fb9bdceff7913 + OpenSSL-Universal: ebc357f1e6bc71fa463ccb2fe676756aff50e88c + push-react-native-sdk: d9d498989a0efa80523cfc7517ae24259d4a10f5 + RCT-Folly: 424b8c9a7a0b9ab2886ffe9c3b041ef628fd4fb1 + RCTRequired: f6187ec763637e6a57f5728dd9a3bdabc6d6b4e0 + RCTTypeSafety: a01aca2dd3b27fa422d5239252ad38e54e958750 + React: 741b4f5187e7a2137b69c88e65f940ba40600b4b + React-callinvoker: 72ba74b2d5d690c497631191ae6eeca0c043d9cf + React-Codegen: 8a7cda1633e4940de8a710f6bf5cae5dd673546e + React-Core: 72bb19702c465b6451a40501a2879532bec9acee + React-CoreModules: ffd19b082fc36b9b463fedf30955138b5426c053 + React-cxxreact: 8b3dd87e3b8ea96dd4ad5c7bac8f31f1cc3da97f + React-hermes: be95942c3f47fc032da1387360413f00dae0ea68 + React-jsi: 9978e2a64c2a4371b40e109f4ef30a33deaa9bcb + React-jsiexecutor: 18b5b33c5f2687a784a61bc8176611b73524ae77 + React-jsinspector: b6ed4cb3ffa27a041cd440300503dc512b761450 + React-logger: 186dd536128ae5924bc38ed70932c00aa740cd5b + react-native-fast-openpgp: 25df11a0fc3a801ef8fa6bd4335cb48c66dc5bbe + react-native-webview: b8ec89966713985111a14d6e4bf98d8b54bced0d + React-perflogger: e706562ab7eb8eb590aa83a224d26fa13963d7f2 + React-RCTActionSheet: 57d4bd98122f557479a3359ad5dad8e109e20c5a + React-RCTAnimation: ccf3ef00101ea74bda73a045d79a658b36728a60 + React-RCTAppDelegate: d0c28a35c65e9a0aef287ac0dafe1b71b1ac180c + React-RCTBlob: 1700b92ece4357af0a49719c9638185ad2902e95 + React-RCTImage: f2e4904566ccccaa4b704170fcc5ae144ca347bf + React-RCTLinking: 52a3740e3651e30aa11dff5a6debed7395dd8169 + React-RCTNetwork: ea0976f2b3ffc7877cd7784e351dc460adf87b12 + React-RCTSettings: ed5ac992b23e25c65c3cc31f11b5c940ae5e3e60 + React-RCTText: c9dfc6722621d56332b4f3a19ac38105e7504145 + React-RCTVibration: f09f08de63e4122deb32506e20ca4cae6e4e14c1 + React-runtimeexecutor: 4817d63dbc9d658f8dc0ec56bd9b83ce531129f0 + ReactCommon: 08723d2ed328c5cbcb0de168f231bc7bae7f8aa1 + SocketRocket: fccef3f9c5cedea1353a9ef6ada904fde10d6608 + Yoga: f7decafdc5e8c125e6fa0da38a687e35238420fa + YogaKit: f782866e155069a2cca2517aafea43200b01fd5a + +PODFILE CHECKSUM: c63b686a08336fbad705bcda149d6478884e7332 + +COCOAPODS: 1.12.1 diff --git a/packages/reactnative/example/ios/ReactNativeSdkExample-Bridging-Header.h b/packages/reactnative/example/ios/ReactNativeSdkExample-Bridging-Header.h new file mode 100644 index 000000000..e11d920b1 --- /dev/null +++ b/packages/reactnative/example/ios/ReactNativeSdkExample-Bridging-Header.h @@ -0,0 +1,3 @@ +// +// Use this file to import your target's public headers that you would like to expose to Swift. +// diff --git a/packages/reactnative/example/ios/ReactNativeSdkExample.xcodeproj/project.pbxproj b/packages/reactnative/example/ios/ReactNativeSdkExample.xcodeproj/project.pbxproj new file mode 100644 index 000000000..c3c77ab21 --- /dev/null +++ b/packages/reactnative/example/ios/ReactNativeSdkExample.xcodeproj/project.pbxproj @@ -0,0 +1,704 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 54; + objects = { + +/* Begin PBXBuildFile section */ + 00E356F31AD99517003FC87E /* ReactNativeSdkExampleTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 00E356F21AD99517003FC87E /* ReactNativeSdkExampleTests.m */; }; + 0C80B921A6F3F58F76C31292 /* libPods-ReactNativeSdkExample.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5DCACB8F33CDC322A6C60F78 /* libPods-ReactNativeSdkExample.a */; }; + 13B07FBC1A68108700A75B9A /* AppDelegate.mm in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB01A68108700A75B9A /* AppDelegate.mm */; }; + 13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; }; + 13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; }; + 7699B88040F8A987B510C191 /* libPods-ReactNativeSdkExample-ReactNativeSdkExampleTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 19F6CBCC0A4E27FBF8BF4A61 /* libPods-ReactNativeSdkExample-ReactNativeSdkExampleTests.a */; }; + 81AB9BB82411601600AC10FF /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 00E356F41AD99517003FC87E /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 83CBB9F71A601CBA00E9B192 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 13B07F861A680F5B00A75B9A; + remoteInfo = ReactNativeSdkExample; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXFileReference section */ + 00E356EE1AD99517003FC87E /* ReactNativeSdkExampleTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ReactNativeSdkExampleTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 00E356F11AD99517003FC87E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 00E356F21AD99517003FC87E /* ReactNativeSdkExampleTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ReactNativeSdkExampleTests.m; sourceTree = ""; }; + 13B07F961A680F5B00A75B9A /* ReactNativeSdkExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ReactNativeSdkExample.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 13B07FAF1A68108700A75B9A /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = ReactNativeSdkExample/AppDelegate.h; sourceTree = ""; }; + 13B07FB01A68108700A75B9A /* AppDelegate.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = AppDelegate.mm; path = ReactNativeSdkExample/AppDelegate.mm; sourceTree = ""; }; + 13B07FB51A68108700A75B9A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = ReactNativeSdkExample/Images.xcassets; sourceTree = ""; }; + 13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = ReactNativeSdkExample/Info.plist; sourceTree = ""; }; + 13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = ReactNativeSdkExample/main.m; sourceTree = ""; }; + 19F6CBCC0A4E27FBF8BF4A61 /* libPods-ReactNativeSdkExample-ReactNativeSdkExampleTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-ReactNativeSdkExample-ReactNativeSdkExampleTests.a"; sourceTree = BUILT_PRODUCTS_DIR; }; + 3B4392A12AC88292D35C810B /* Pods-ReactNativeSdkExample.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ReactNativeSdkExample.debug.xcconfig"; path = "Target Support Files/Pods-ReactNativeSdkExample/Pods-ReactNativeSdkExample.debug.xcconfig"; sourceTree = ""; }; + 5709B34CF0A7D63546082F79 /* Pods-ReactNativeSdkExample.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ReactNativeSdkExample.release.xcconfig"; path = "Target Support Files/Pods-ReactNativeSdkExample/Pods-ReactNativeSdkExample.release.xcconfig"; sourceTree = ""; }; + 5B7EB9410499542E8C5724F5 /* Pods-ReactNativeSdkExample-ReactNativeSdkExampleTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ReactNativeSdkExample-ReactNativeSdkExampleTests.debug.xcconfig"; path = "Target Support Files/Pods-ReactNativeSdkExample-ReactNativeSdkExampleTests/Pods-ReactNativeSdkExample-ReactNativeSdkExampleTests.debug.xcconfig"; sourceTree = ""; }; + 5DCACB8F33CDC322A6C60F78 /* libPods-ReactNativeSdkExample.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-ReactNativeSdkExample.a"; sourceTree = BUILT_PRODUCTS_DIR; }; + 81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = LaunchScreen.storyboard; path = ReactNativeSdkExample/LaunchScreen.storyboard; sourceTree = ""; }; + 89C6BE57DB24E9ADA2F236DE /* Pods-ReactNativeSdkExample-ReactNativeSdkExampleTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ReactNativeSdkExample-ReactNativeSdkExampleTests.release.xcconfig"; path = "Target Support Files/Pods-ReactNativeSdkExample-ReactNativeSdkExampleTests/Pods-ReactNativeSdkExample-ReactNativeSdkExampleTests.release.xcconfig"; sourceTree = ""; }; + ED297162215061F000B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 00E356EB1AD99517003FC87E /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 7699B88040F8A987B510C191 /* libPods-ReactNativeSdkExample-ReactNativeSdkExampleTests.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 13B07F8C1A680F5B00A75B9A /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 0C80B921A6F3F58F76C31292 /* libPods-ReactNativeSdkExample.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 00E356EF1AD99517003FC87E /* ReactNativeSdkExampleTests */ = { + isa = PBXGroup; + children = ( + 00E356F21AD99517003FC87E /* ReactNativeSdkExampleTests.m */, + 00E356F01AD99517003FC87E /* Supporting Files */, + ); + path = ReactNativeSdkExampleTests; + sourceTree = ""; + }; + 00E356F01AD99517003FC87E /* Supporting Files */ = { + isa = PBXGroup; + children = ( + 00E356F11AD99517003FC87E /* Info.plist */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; + 13B07FAE1A68108700A75B9A /* ReactNativeSdkExample */ = { + isa = PBXGroup; + children = ( + 13B07FAF1A68108700A75B9A /* AppDelegate.h */, + 13B07FB01A68108700A75B9A /* AppDelegate.mm */, + 13B07FB51A68108700A75B9A /* Images.xcassets */, + 13B07FB61A68108700A75B9A /* Info.plist */, + 81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */, + 13B07FB71A68108700A75B9A /* main.m */, + ); + name = ReactNativeSdkExample; + sourceTree = ""; + }; + 2D16E6871FA4F8E400B85C8A /* Frameworks */ = { + isa = PBXGroup; + children = ( + ED297162215061F000B7C4FE /* JavaScriptCore.framework */, + 5DCACB8F33CDC322A6C60F78 /* libPods-ReactNativeSdkExample.a */, + 19F6CBCC0A4E27FBF8BF4A61 /* libPods-ReactNativeSdkExample-ReactNativeSdkExampleTests.a */, + ); + name = Frameworks; + sourceTree = ""; + }; + 832341AE1AAA6A7D00B99B32 /* Libraries */ = { + isa = PBXGroup; + children = ( + ); + name = Libraries; + sourceTree = ""; + }; + 83CBB9F61A601CBA00E9B192 = { + isa = PBXGroup; + children = ( + 13B07FAE1A68108700A75B9A /* ReactNativeSdkExample */, + 832341AE1AAA6A7D00B99B32 /* Libraries */, + 00E356EF1AD99517003FC87E /* ReactNativeSdkExampleTests */, + 83CBBA001A601CBA00E9B192 /* Products */, + 2D16E6871FA4F8E400B85C8A /* Frameworks */, + BBD78D7AC51CEA395F1C20DB /* Pods */, + ); + indentWidth = 2; + sourceTree = ""; + tabWidth = 2; + usesTabs = 0; + }; + 83CBBA001A601CBA00E9B192 /* Products */ = { + isa = PBXGroup; + children = ( + 13B07F961A680F5B00A75B9A /* ReactNativeSdkExample.app */, + 00E356EE1AD99517003FC87E /* ReactNativeSdkExampleTests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + BBD78D7AC51CEA395F1C20DB /* Pods */ = { + isa = PBXGroup; + children = ( + 3B4392A12AC88292D35C810B /* Pods-ReactNativeSdkExample.debug.xcconfig */, + 5709B34CF0A7D63546082F79 /* Pods-ReactNativeSdkExample.release.xcconfig */, + 5B7EB9410499542E8C5724F5 /* Pods-ReactNativeSdkExample-ReactNativeSdkExampleTests.debug.xcconfig */, + 89C6BE57DB24E9ADA2F236DE /* Pods-ReactNativeSdkExample-ReactNativeSdkExampleTests.release.xcconfig */, + ); + path = Pods; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 00E356ED1AD99517003FC87E /* ReactNativeSdkExampleTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 00E357021AD99517003FC87E /* Build configuration list for PBXNativeTarget "ReactNativeSdkExampleTests" */; + buildPhases = ( + A55EABD7B0C7F3A422A6CC61 /* [CP] Check Pods Manifest.lock */, + 00E356EA1AD99517003FC87E /* Sources */, + 00E356EB1AD99517003FC87E /* Frameworks */, + 00E356EC1AD99517003FC87E /* Resources */, + C59DA0FBD6956966B86A3779 /* [CP] Embed Pods Frameworks */, + F6A41C54EA430FDDC6A6ED99 /* [CP] Copy Pods Resources */, + ); + buildRules = ( + ); + dependencies = ( + 00E356F51AD99517003FC87E /* PBXTargetDependency */, + ); + name = ReactNativeSdkExampleTests; + productName = ReactNativeSdkExampleTests; + productReference = 00E356EE1AD99517003FC87E /* ReactNativeSdkExampleTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + 13B07F861A680F5B00A75B9A /* ReactNativeSdkExample */ = { + isa = PBXNativeTarget; + buildConfigurationList = 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "ReactNativeSdkExample" */; + buildPhases = ( + C38B50BA6285516D6DCD4F65 /* [CP] Check Pods Manifest.lock */, + FD10A7F022414F080027D42C /* Start Packager */, + 13B07F871A680F5B00A75B9A /* Sources */, + 13B07F8C1A680F5B00A75B9A /* Frameworks */, + 13B07F8E1A680F5B00A75B9A /* Resources */, + 00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */, + 00EEFC60759A1932668264C0 /* [CP] Embed Pods Frameworks */, + E235C05ADACE081382539298 /* [CP] Copy Pods Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = ReactNativeSdkExample; + productName = ReactNativeSdkExample; + productReference = 13B07F961A680F5B00A75B9A /* ReactNativeSdkExample.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 83CBB9F71A601CBA00E9B192 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 1210; + TargetAttributes = { + 00E356ED1AD99517003FC87E = { + CreatedOnToolsVersion = 6.2; + TestTargetID = 13B07F861A680F5B00A75B9A; + }; + 13B07F861A680F5B00A75B9A = { + LastSwiftMigration = 1120; + }; + }; + }; + buildConfigurationList = 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "ReactNativeSdkExample" */; + compatibilityVersion = "Xcode 12.0"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 83CBB9F61A601CBA00E9B192; + productRefGroup = 83CBBA001A601CBA00E9B192 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 13B07F861A680F5B00A75B9A /* ReactNativeSdkExample */, + 00E356ED1AD99517003FC87E /* ReactNativeSdkExampleTests */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 00E356EC1AD99517003FC87E /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 13B07F8E1A680F5B00A75B9A /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 81AB9BB82411601600AC10FF /* LaunchScreen.storyboard in Resources */, + 13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "$(SRCROOT)/.xcode.env.local", + "$(SRCROOT)/.xcode.env", + ); + name = "Bundle React Native code and images"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + 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"; + }; + 00EEFC60759A1932668264C0 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-ReactNativeSdkExample/Pods-ReactNativeSdkExample-frameworks-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-ReactNativeSdkExample/Pods-ReactNativeSdkExample-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-ReactNativeSdkExample/Pods-ReactNativeSdkExample-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + A55EABD7B0C7F3A422A6CC61 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-ReactNativeSdkExample-ReactNativeSdkExampleTests-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + 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"; + showEnvVarsInLog = 0; + }; + C38B50BA6285516D6DCD4F65 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-ReactNativeSdkExample-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + 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"; + showEnvVarsInLog = 0; + }; + C59DA0FBD6956966B86A3779 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-ReactNativeSdkExample-ReactNativeSdkExampleTests/Pods-ReactNativeSdkExample-ReactNativeSdkExampleTests-frameworks-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-ReactNativeSdkExample-ReactNativeSdkExampleTests/Pods-ReactNativeSdkExample-ReactNativeSdkExampleTests-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-ReactNativeSdkExample-ReactNativeSdkExampleTests/Pods-ReactNativeSdkExample-ReactNativeSdkExampleTests-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + E235C05ADACE081382539298 /* [CP] Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-ReactNativeSdkExample/Pods-ReactNativeSdkExample-resources-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Copy Pods Resources"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-ReactNativeSdkExample/Pods-ReactNativeSdkExample-resources-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-ReactNativeSdkExample/Pods-ReactNativeSdkExample-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; + F6A41C54EA430FDDC6A6ED99 /* [CP] Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-ReactNativeSdkExample-ReactNativeSdkExampleTests/Pods-ReactNativeSdkExample-ReactNativeSdkExampleTests-resources-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Copy Pods Resources"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-ReactNativeSdkExample-ReactNativeSdkExampleTests/Pods-ReactNativeSdkExample-ReactNativeSdkExampleTests-resources-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-ReactNativeSdkExample-ReactNativeSdkExampleTests/Pods-ReactNativeSdkExample-ReactNativeSdkExampleTests-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; + FD10A7F022414F080027D42C /* Start Packager */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + name = "Start Packager"; + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + 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"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 00E356EA1AD99517003FC87E /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 00E356F31AD99517003FC87E /* ReactNativeSdkExampleTests.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 13B07F871A680F5B00A75B9A /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 13B07FBC1A68108700A75B9A /* AppDelegate.mm in Sources */, + 13B07FC11A68108700A75B9A /* main.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 00E356F51AD99517003FC87E /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 13B07F861A680F5B00A75B9A /* ReactNativeSdkExample */; + targetProxy = 00E356F41AD99517003FC87E /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin XCBuildConfiguration section */ + 00E356F61AD99517003FC87E /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 5B7EB9410499542E8C5724F5 /* Pods-ReactNativeSdkExample-ReactNativeSdkExampleTests.debug.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + INFOPLIST_FILE = ReactNativeSdkExampleTests/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 12.4; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + OTHER_LDFLAGS = ( + "-ObjC", + "-lc++", + "$(inherited)", + ); + PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)"; + PRODUCT_NAME = "$(TARGET_NAME)"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/ReactNativeSdkExample.app/ReactNativeSdkExample"; + }; + name = Debug; + }; + 00E356F71AD99517003FC87E /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 89C6BE57DB24E9ADA2F236DE /* Pods-ReactNativeSdkExample-ReactNativeSdkExampleTests.release.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + COPY_PHASE_STRIP = NO; + INFOPLIST_FILE = ReactNativeSdkExampleTests/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 12.4; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + OTHER_LDFLAGS = ( + "-ObjC", + "-lc++", + "$(inherited)", + ); + PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)"; + PRODUCT_NAME = "$(TARGET_NAME)"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/ReactNativeSdkExample.app/ReactNativeSdkExample"; + }; + name = Release; + }; + 13B07F941A680F5B00A75B9A /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 3B4392A12AC88292D35C810B /* Pods-ReactNativeSdkExample.debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = 1; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = ReactNativeSdkExample/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + OTHER_LDFLAGS = ( + "$(inherited)", + "-ObjC", + "-lc++", + ); + PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)"; + PRODUCT_NAME = ReactNativeSdkExample; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Debug; + }; + 13B07F951A680F5B00A75B9A /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 5709B34CF0A7D63546082F79 /* Pods-ReactNativeSdkExample.release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = 1; + INFOPLIST_FILE = ReactNativeSdkExample/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + OTHER_LDFLAGS = ( + "$(inherited)", + "-ObjC", + "-lc++", + ); + PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)"; + PRODUCT_NAME = ReactNativeSdkExample; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; + 83CBBA201A601CBA00E9B192 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_CXX_LANGUAGE_STANDARD = "c++17"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = i386; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 12.4; + LD_RUNPATH_SEARCH_PATHS = ( + /usr/lib/swift, + "$(inherited)", + ); + LIBRARY_SEARCH_PATHS = ( + "\"$(SDKROOT)/usr/lib/swift\"", + "\"$(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME)\"", + "\"$(inherited)\"", + ); + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + OTHER_CPLUSPLUSFLAGS = ( + "$(OTHER_CFLAGS)", + "-DFOLLY_NO_CONFIG", + "-DFOLLY_MOBILE=1", + "-DFOLLY_USE_LIBCPP=1", + ); + REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native"; + SDKROOT = iphoneos; + }; + name = Debug; + }; + 83CBBA211A601CBA00E9B192 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_CXX_LANGUAGE_STANDARD = "c++17"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = YES; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = i386; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 12.4; + LD_RUNPATH_SEARCH_PATHS = ( + /usr/lib/swift, + "$(inherited)", + ); + LIBRARY_SEARCH_PATHS = ( + "\"$(SDKROOT)/usr/lib/swift\"", + "\"$(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME)\"", + "\"$(inherited)\"", + ); + MTL_ENABLE_DEBUG_INFO = NO; + OTHER_CPLUSPLUSFLAGS = ( + "$(OTHER_CFLAGS)", + "-DFOLLY_NO_CONFIG", + "-DFOLLY_MOBILE=1", + "-DFOLLY_USE_LIBCPP=1", + ); + REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native"; + SDKROOT = iphoneos; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 00E357021AD99517003FC87E /* Build configuration list for PBXNativeTarget "ReactNativeSdkExampleTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 00E356F61AD99517003FC87E /* Debug */, + 00E356F71AD99517003FC87E /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "ReactNativeSdkExample" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 13B07F941A680F5B00A75B9A /* Debug */, + 13B07F951A680F5B00A75B9A /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "ReactNativeSdkExample" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 83CBBA201A601CBA00E9B192 /* Debug */, + 83CBBA211A601CBA00E9B192 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 83CBB9F71A601CBA00E9B192 /* Project object */; +} diff --git a/packages/reactnative/example/ios/ReactNativeSdkExample.xcodeproj/xcshareddata/xcschemes/ReactNativeSdkExample.xcscheme b/packages/reactnative/example/ios/ReactNativeSdkExample.xcodeproj/xcshareddata/xcschemes/ReactNativeSdkExample.xcscheme new file mode 100644 index 000000000..c3bb832ce --- /dev/null +++ b/packages/reactnative/example/ios/ReactNativeSdkExample.xcodeproj/xcshareddata/xcschemes/ReactNativeSdkExample.xcscheme @@ -0,0 +1,88 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/reactnative/example/ios/ReactNativeSdkExample.xcworkspace/contents.xcworkspacedata b/packages/reactnative/example/ios/ReactNativeSdkExample.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..9be26e856 --- /dev/null +++ b/packages/reactnative/example/ios/ReactNativeSdkExample.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/packages/reactnative/example/ios/ReactNativeSdkExample/AppDelegate.h b/packages/reactnative/example/ios/ReactNativeSdkExample/AppDelegate.h new file mode 100644 index 000000000..5d2808256 --- /dev/null +++ b/packages/reactnative/example/ios/ReactNativeSdkExample/AppDelegate.h @@ -0,0 +1,6 @@ +#import +#import + +@interface AppDelegate : RCTAppDelegate + +@end diff --git a/packages/reactnative/example/ios/ReactNativeSdkExample/AppDelegate.mm b/packages/reactnative/example/ios/ReactNativeSdkExample/AppDelegate.mm new file mode 100644 index 000000000..8df3ed060 --- /dev/null +++ b/packages/reactnative/example/ios/ReactNativeSdkExample/AppDelegate.mm @@ -0,0 +1,36 @@ +#import "AppDelegate.h" + +#import + +@implementation AppDelegate + +- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions +{ + self.moduleName = @"ReactNativeSdkExample"; + // You can add your custom initial props in the dictionary below. + // They will be passed down to the ViewController used by React Native. + self.initialProps = @{}; + + return [super application:application didFinishLaunchingWithOptions:launchOptions]; +} + +- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge +{ +#if DEBUG + return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index"]; +#else + return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"]; +#endif +} + +/// This method controls whether the `concurrentRoot`feature of React18 is turned on or off. +/// +/// @see: https://reactjs.org/blog/2022/03/29/react-v18.html +/// @note: This requires to be rendering on Fabric (i.e. on the New Architecture). +/// @return: `true` if the `concurrentRoot` feature is enabled. Otherwise, it returns `false`. +- (BOOL)concurrentRootEnabled +{ + return true; +} + +@end diff --git a/packages/reactnative/example/ios/ReactNativeSdkExample/Images.xcassets/AppIcon.appiconset/Contents.json b/packages/reactnative/example/ios/ReactNativeSdkExample/Images.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 000000000..81213230d --- /dev/null +++ b/packages/reactnative/example/ios/ReactNativeSdkExample/Images.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,53 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "20x20" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "20x20" + }, + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "29x29" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "29x29" + }, + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "40x40" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "40x40" + }, + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "60x60" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "60x60" + }, + { + "idiom" : "ios-marketing", + "scale" : "1x", + "size" : "1024x1024" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/packages/reactnative/example/ios/ReactNativeSdkExample/Images.xcassets/Contents.json b/packages/reactnative/example/ios/ReactNativeSdkExample/Images.xcassets/Contents.json new file mode 100644 index 000000000..2d92bd53f --- /dev/null +++ b/packages/reactnative/example/ios/ReactNativeSdkExample/Images.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/packages/reactnative/example/ios/ReactNativeSdkExample/Info.plist b/packages/reactnative/example/ios/ReactNativeSdkExample/Info.plist new file mode 100644 index 000000000..e7a375d46 --- /dev/null +++ b/packages/reactnative/example/ios/ReactNativeSdkExample/Info.plist @@ -0,0 +1,55 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleDisplayName + ReactNativeSdkExample + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + $(MARKETING_VERSION) + CFBundleSignature + ???? + CFBundleVersion + $(CURRENT_PROJECT_VERSION) + LSRequiresIPhoneOS + + NSAppTransportSecurity + + NSExceptionDomains + + localhost + + NSExceptionAllowsInsecureHTTPLoads + + + + + NSLocationWhenInUseUsageDescription + + UILaunchStoryboardName + LaunchScreen + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UIViewControllerBasedStatusBarAppearance + + + diff --git a/packages/reactnative/example/ios/ReactNativeSdkExample/LaunchScreen.storyboard b/packages/reactnative/example/ios/ReactNativeSdkExample/LaunchScreen.storyboard new file mode 100644 index 000000000..9e0f02713 --- /dev/null +++ b/packages/reactnative/example/ios/ReactNativeSdkExample/LaunchScreen.storyboard @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/reactnative/example/ios/ReactNativeSdkExample/main.m b/packages/reactnative/example/ios/ReactNativeSdkExample/main.m new file mode 100644 index 000000000..d645c7246 --- /dev/null +++ b/packages/reactnative/example/ios/ReactNativeSdkExample/main.m @@ -0,0 +1,10 @@ +#import + +#import "AppDelegate.h" + +int main(int argc, char *argv[]) +{ + @autoreleasepool { + return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); + } +} diff --git a/packages/reactnative/example/ios/ReactNativeSdkExampleTests/Info.plist b/packages/reactnative/example/ios/ReactNativeSdkExampleTests/Info.plist new file mode 100644 index 000000000..ba72822e8 --- /dev/null +++ b/packages/reactnative/example/ios/ReactNativeSdkExampleTests/Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + + diff --git a/packages/reactnative/example/ios/ReactNativeSdkExampleTests/ReactNativeSdkExampleTests.m b/packages/reactnative/example/ios/ReactNativeSdkExampleTests/ReactNativeSdkExampleTests.m new file mode 100644 index 000000000..b2523c458 --- /dev/null +++ b/packages/reactnative/example/ios/ReactNativeSdkExampleTests/ReactNativeSdkExampleTests.m @@ -0,0 +1,66 @@ +#import +#import + +#import +#import + +#define TIMEOUT_SECONDS 600 +#define TEXT_TO_LOOK_FOR @"Welcome to React" + +@interface ReactNativeSdkExampleTests : XCTestCase + +@end + +@implementation ReactNativeSdkExampleTests + +- (BOOL)findSubviewInView:(UIView *)view matching:(BOOL (^)(UIView *view))test +{ + if (test(view)) { + return YES; + } + for (UIView *subview in [view subviews]) { + if ([self findSubviewInView:subview matching:test]) { + return YES; + } + } + return NO; +} + +- (void)testRendersWelcomeScreen +{ + UIViewController *vc = [[[RCTSharedApplication() delegate] window] rootViewController]; + NSDate *date = [NSDate dateWithTimeIntervalSinceNow:TIMEOUT_SECONDS]; + BOOL foundElement = NO; + + __block NSString *redboxError = nil; +#ifdef DEBUG + RCTSetLogFunction( + ^(RCTLogLevel level, RCTLogSource source, NSString *fileName, NSNumber *lineNumber, NSString *message) { + if (level >= RCTLogLevelError) { + redboxError = message; + } + }); +#endif + + while ([date timeIntervalSinceNow] > 0 && !foundElement && !redboxError) { + [[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; + [[NSRunLoop mainRunLoop] runMode:NSRunLoopCommonModes beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; + + foundElement = [self findSubviewInView:vc.view + matching:^BOOL(UIView *view) { + if ([view.accessibilityLabel isEqualToString:TEXT_TO_LOOK_FOR]) { + return YES; + } + return NO; + }]; + } + +#ifdef DEBUG + RCTSetLogFunction(RCTDefaultLogFunction); +#endif + + XCTAssertNil(redboxError, @"RedBox error: %@", redboxError); + XCTAssertTrue(foundElement, @"Couldn't find element with text '%@' in %d seconds", TEXT_TO_LOOK_FOR, TIMEOUT_SECONDS); +} + +@end diff --git a/packages/reactnative/example/metro.config.js b/packages/reactnative/example/metro.config.js new file mode 100644 index 000000000..b5c0064bb --- /dev/null +++ b/packages/reactnative/example/metro.config.js @@ -0,0 +1,40 @@ +const path = require('path'); +const escape = require('escape-string-regexp'); +const exclusionList = require('metro-config/src/defaults/exclusionList'); +const pak = require('../package.json'); + +const root = path.resolve(__dirname, '..'); + +const modules = Object.keys({ + ...pak.peerDependencies, +}); + +module.exports = { + projectRoot: __dirname, + watchFolders: [root], + + // We need to make sure that only one version is loaded for peerDependencies + // So we block them at the root, and alias them to the versions in example's node_modules + resolver: { + blacklistRE: exclusionList( + modules.map( + (m) => + new RegExp(`^${escape(path.join(root, 'node_modules', m))}\\/.*$`) + ) + ), + + extraNodeModules: modules.reduce((acc, name) => { + acc[name] = path.join(__dirname, 'node_modules', name); + return acc; + }, {}), + }, + + transformer: { + getTransformOptions: async () => ({ + transform: { + experimentalImportSupport: false, + inlineRequires: true, + }, + }), + }, +}; diff --git a/packages/reactnative/example/package.json b/packages/reactnative/example/package.json new file mode 100644 index 000000000..281c48666 --- /dev/null +++ b/packages/reactnative/example/package.json @@ -0,0 +1,33 @@ +{ + "name": "ReactNativeSdkExample", + "version": "0.0.1", + "private": true, + "scripts": { + "android": "react-native run-android", + "ios": "react-native run-ios", + "start": "react-native start", + "pods": "pod-install --quiet" + }, + "dependencies": { + "ethers": "^5.7.1", + "react": "18.2.0", + "react-native": "0.71.11", + "react-native-dotenv": "^3.4.9", + "react-native-fast-openpgp": "^2.6.0", + "react-native-webview": "^13.2.2", + "react-native-webview-crypto": "^0.0.25" + }, + "devDependencies": { + "@babel/core": "^7.20.0", + "@babel/preset-env": "^7.20.0", + "@babel/runtime": "^7.20.0", + "@tsconfig/react-native": "^3.0.2", + "@types/jest": "^29.5.2", + "@types/react": "^18.2.13", + "@types/react-native-dotenv": "^0.2.0", + "@types/react-test-renderer": "^18.0.0", + "babel-plugin-module-resolver": "^4.1.0", + "metro-react-native-babel-preset": "0.73.10", + "typescript": "^5.1.3" + } +} diff --git a/packages/reactnative/example/react-native.config.js b/packages/reactnative/example/react-native.config.js new file mode 100644 index 000000000..a5166956f --- /dev/null +++ b/packages/reactnative/example/react-native.config.js @@ -0,0 +1,10 @@ +const path = require('path'); +const pak = require('../package.json'); + +module.exports = { + dependencies: { + [pak.name]: { + root: path.join(__dirname, '..'), + }, + }, +}; diff --git a/packages/reactnative/example/shim.js b/packages/reactnative/example/shim.js new file mode 100644 index 000000000..812d6b45c --- /dev/null +++ b/packages/reactnative/example/shim.js @@ -0,0 +1,26 @@ +if (typeof __dirname === 'undefined') global.__dirname = '/' +if (typeof __filename === 'undefined') global.__filename = '' +if (typeof process === 'undefined') { + global.process = require('process') +} else { + const bProcess = require('process') + for (var p in bProcess) { + if (!(p in process)) { + process[p] = bProcess[p] + } + } +} + +process.browser = false +if (typeof Buffer === 'undefined') global.Buffer = require('buffer').Buffer + +// global.location = global.location || { port: 80 } +const isDev = typeof __DEV__ === 'boolean' && __DEV__ +process.env['NODE_ENV'] = isDev ? 'development' : 'production' +if (typeof localStorage !== 'undefined') { + localStorage.debug = isDev ? '*' : '' +} + +// If using the crypto shim, uncomment the following line to ensure +// crypto is loaded first, so it can populate global.crypto +// require('crypto') diff --git a/packages/reactnative/example/src/App.tsx b/packages/reactnative/example/src/App.tsx new file mode 100644 index 000000000..1ac463941 --- /dev/null +++ b/packages/reactnative/example/src/App.tsx @@ -0,0 +1,442 @@ +import React from 'react'; +import { ethers } from 'ethers'; + +import WebViewCrypto from 'react-native-webview-crypto'; +import { ScrollView, StyleSheet, Text } from 'react-native'; +import OpenPGP from 'react-native-fast-openpgp'; +import { + NFT_CHAIN_ID_1, + NFT_CHAIN_ID_2, + NFT_CONTRACT_ADDRESS_1, + NFT_CONTRACT_ADDRESS_2, + NFT_HOLDER_WALLET_PRIVATE_KEY_1, + NFT_HOLDER_WALLET_PRIVATE_KEY_2, + NFT_TOKEN_ID_1, + NFT_TOKEN_ID_2, +} from '@env'; +import { + PGPHelper, + genRandomAddress, + createUser, + ENV, + conversationHash, + latest, + createGroup, + updateGroup, + chats, + PushApi, + get, + profileUpdate, + decryptPGPKey, + profileUpgrade, + send, + Constants, + approve, +} from '@push/react-native-sdk'; + +function generatePrivateKey() { + // Define the set of characters for private key generation + var characters = '0123456789abcdef'; + + // Set the length of the private key (64 characters for 256 bits) + var keyLength = 64; + + // Generate the private key + var privateKey = ''; + for (var i = 0; i < keyLength; i++) { + var randomIndex = Math.floor(Math.random() * characters.length); + privateKey += characters.charAt(randomIndex); + } + + // Return the private key + return privateKey; +} + +function generateRandomString() { + var characters = '0123456789abcdef'; + var keyLength = 40; + var randomString = ''; + for (var i = 0; i < keyLength; i++) { + var randomIndex = Math.floor(Math.random() * characters.length); + randomString += characters.charAt(randomIndex); + } + return randomString; +} + +export default function App() { + const handlePgp = async () => { + let res = await PGPHelper.generateKeyPair(); + console.log(res); + }; + + const handleEthers = async () => { + let res = await genRandomAddress(); + console.log(res); + }; + + const handleUserCreate = async () => { + const pk = generatePrivateKey(); + + const signer = new ethers.Wallet(pk); + const walletAddress = signer.address; + const account = `eip155:${walletAddress}`; + + const options: PushApi.user.CreateUserProps = { + account: account, + signer: signer, + env: Constants.ENV.DEV, + }; + + console.log('create user', account); + + const res = await createUser(options); + console.log('success', res.did); + }; + + const handleUserMsgs = async () => { + const signer = new ethers.Wallet( + '07da77f7471e5cf046ea3793421cbce90fd42a4cfcf520046a490ca1a9b636e0' + ); + const walletAddress = signer.address; + const account = `eip155:${walletAddress}`; + console.log(signer); + + const res = await PushApi.chat.conversationHash({ + account: account, + conversationId: + 'b353220b812bdb707bd93529aac6fac893438e5db791d7c9e6aab6773aaff90b', + env: ENV.STAGING, + }); + + const res2 = await latest({ + threadhash: res.threadHash, + toDecrypt: true, + account: account, + env: ENV.STAGING, + }); + + const user = await PushApi.user.get({ + account: account, + env: ENV.STAGING, + }); + + const pgpDecryptedPvtKey = await PushApi.chat.decryptPGPKey({ + encryptedPGPPrivateKey: user.encryptedPrivateKey, + signer: signer, + }); + + const chatList = await chats({ + account: account, + pgpPrivateKey: pgpDecryptedPvtKey, + toDecrypt: true, + env: ENV.STAGING, + }); + console.log(user, 'user'); + console.log(pgpDecryptedPvtKey, 'key'); + console.log(chatList, 'Chatlist'); + }; + + const handleCreateGroup = async () => { + const pk = generatePrivateKey(); + const signer = new ethers.Wallet(pk); + const walletAddress = signer.address; + const account = `eip155:${walletAddress}`; + console.log(signer); + + const groupName = generateRandomString(); + + const res = await createGroup({ + groupName: groupName, + groupDescription: 'satyamstesing', + groupImage: 'https://github.com', + account: account, + signer: signer, + members: [ + '0x83d4c16b15F7BBA501Ca1057364a1F502d1c34D5', + '0x6Ff7DF70cAACAd6B35d2d30eca6bbb4E86fEE62f', + ], + admins: [], + isPublic: true, + env: ENV.DEV, + }); + console.log(res, 'res'); + + return { + chatId: res.chatId, + groupName, + signer, + }; + }; + + const handleUpdateGroup = async () => { + const { signer, chatId, groupName } = await handleCreateGroup(); + const walletAddress = signer.address; + const account = `eip155:${walletAddress}`; + + const res = await updateGroup({ + groupName, + groupDescription: 'satyamstesing', + groupImage: 'https://github.com', + chatId, + account: account, + signer: signer, + admins: ['0x83d4c16b15F7BBA501Ca1057364a1F502d1c34D5'], + members: [ + '0x6Ff7DF70cAACAd6B35d2d30eca6bbb4E86fEE62f', + '0x6d118b28ebd82635A30b142D11B9eEEa2c0bea26', + '0x83d4c16b15F7BBA501Ca1057364a1F502d1c34D5', + ], + env: ENV.DEV, + }); + console.log(res, 'ress'); + }; + + const handleGetUser = async () => { + const options: PushApi.AccountEnvOptionsType = { + account: '0xACEe0D180d0118FD4F3027Ab801cc862520570d1', + env: Constants.ENV.DEV, + }; + + const res = await get(options); + console.log('successfully got user', res); + }; + + const handleProfileUpdate = async () => { + console.log('updating profile...'); + const pk = generatePrivateKey(); + + const signer = new ethers.Wallet(pk); + const walletAddress = signer.address; + const account = `eip155:${walletAddress}`; + + console.log('creating user...'); + const user = await createUser({ + account: account, + signer: signer, + env: Constants.ENV.DEV, + }); + + console.log('decrypting pgp key...'); + const pgpPK = await decryptPGPKey({ + account: user.did, + encryptedPGPPrivateKey: user.encryptedPrivateKey, + env: Constants.ENV.DEV, + signer: signer, + }); + + console.log('updating profile...'); + await profileUpdate({ + account: account, + env: Constants.ENV.DEV, + pgpPrivateKey: pgpPK, + profile: { + name: 'Updated Name', + desc: 'Updated Desc', + }, + }); + console.log('successfully updated profile'); + }; + + const handleProfileUpgrade = async () => { + console.log('upgrading profile...'); + const pk = generatePrivateKey(); + const signer = new ethers.Wallet(pk); + const walletAddress = signer.address; + const account = `eip155:${walletAddress}`; + + const user = await createUser({ + account: account, + signer: signer, + env: Constants.ENV.DEV, + }); + + const pgpPK = await decryptPGPKey({ + account: user.did, + encryptedPGPPrivateKey: user.encryptedPrivateKey, + env: Constants.ENV.DEV, + signer: signer, + }); + + const pgpPubKey = await OpenPGP.convertPrivateKeyToPublicKey(pgpPK); + + const upgradedProfile = await profileUpgrade({ + signer: signer, + pgpPrivateKey: pgpPK, + pgpPublicKey: pgpPubKey, + pgpEncryptionVersion: Constants.ENCRYPTION_TYPE.NFTPGP_V1, + account: account, + env: Constants.ENV.DEV, + additionalMeta: { + NFTPGP_V1: { + password: '0x@1jdw89Amcedk', //new nft profile password + }, + }, + }); + + console.log('successfully upgraded profile'); + return upgradedProfile; + }; + + const handleSend = async () => { + const _nftSigner1 = new ethers.Wallet( + `0x${NFT_HOLDER_WALLET_PRIVATE_KEY_1}` + ); + const _nftWalletAddress1 = _nftSigner1.address; + console.log('sending...'); + console.log({ + NFT_CHAIN_ID: NFT_CHAIN_ID_1, + NFT_CONTRACT_ADDRESS: NFT_CONTRACT_ADDRESS_1, + NFT_TOKEN_ID: NFT_TOKEN_ID_1, + }); + const _nftAccount1 = `nft:eip155:${NFT_CHAIN_ID_1}:${NFT_CONTRACT_ADDRESS_1}:${NFT_TOKEN_ID_1}`; + const _nftSigner2 = new ethers.Wallet( + `0x${NFT_HOLDER_WALLET_PRIVATE_KEY_2}` + ); + const _nftWalletAddress2 = _nftSigner2.address; + const _nftAccount2 = `nft:eip155:${NFT_CHAIN_ID_2}:${NFT_CONTRACT_ADDRESS_2}:${NFT_TOKEN_ID_2}`; + + const pk1 = generatePrivateKey(); + const WALLET1 = new ethers.Wallet(pk1); + const _signer1 = new ethers.Wallet(WALLET1.privateKey); + const walletAddress1 = _signer1.address; + const account1 = `eip155:${walletAddress1}`; + + const pk2 = generatePrivateKey(); + const WALLET2 = new ethers.Wallet(pk2); + const _signer2 = new ethers.Wallet(WALLET2.privateKey); + const walletAddress2 = _signer2.address; + const account2 = `eip155:${walletAddress2}`; + + const MESSAGE = 'Hey There!!!'; + const MESSAGE2 = 'Hey There Upgraded User!!!'; + const MESSAGE3 = 'Hey There from Upgraded User!!!'; + + const _env = Constants.ENV.DEV; + + await send({ + messageContent: MESSAGE, + receiverAddress: _nftAccount1, + account: account1, + signer: _signer1, + env: _env, + }); + + await send({ + messageContent: MESSAGE, + receiverAddress: account1, + account: _nftAccount1, + signer: _nftSigner1, + env: _env, + }); + + await send({ + messageContent: MESSAGE, + receiverAddress: _nftAccount2, + account: _nftAccount1, + signer: _nftSigner1, + env: _env, + }); + console.log('sent message!'); + }; + + const handleApproveRequest = async () => { + console.log('sending request...'); + + const pk1 = generatePrivateKey(); + const pk2 = generatePrivateKey(); + + const signer1 = new ethers.Wallet(pk1); + const signer2 = new ethers.Wallet(pk2); + + const account1 = `eip155:${signer1.address}`; + const account2 = `eip155:${signer2.address}`; + + const MESSAGE = 'Hey There!!!'; + + await createUser({ + account: account1, + signer: signer1, + env: Constants.ENV.DEV, + }); + + await createUser({ + account: account2, + signer: signer2, + env: Constants.ENV.DEV, + }); + + await send({ + messageContent: MESSAGE, + receiverAddress: signer2.address, + account: account1, + signer: signer1, + env: Constants.ENV.DEV, + }); + + console.log('approving request...'); + await approve({ + senderAddress: signer1.address, + status: 'Approved', + account: account2, + signer: signer2, + env: Constants.ENV.DEV, + }); + + console.log('successfully approved request!'); + }; + + return ( + + + + New User + + + Generate PGP Pair + + + Log Address + + + Create Group + + + update group + + + ConversationHash + + + Get user + + + Update Profile + + + Upgrade Profile + + + Send Message + + + Approve Request + + + ); +} + +const styles = StyleSheet.create({ + container: { + flex: 1, + }, + box: { + width: 60, + height: 60, + marginVertical: 20, + }, + button: { + padding: 10, + fontSize: 32, + margin: 10, + }, +}); diff --git a/packages/reactnative/example/tsconfig.json b/packages/reactnative/example/tsconfig.json new file mode 100644 index 000000000..b71c72cc6 --- /dev/null +++ b/packages/reactnative/example/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "@tsconfig/react-native/tsconfig.json", +} diff --git a/packages/reactnative/example/types/env.d.ts b/packages/reactnative/example/types/env.d.ts new file mode 100644 index 000000000..d01acb281 --- /dev/null +++ b/packages/reactnative/example/types/env.d.ts @@ -0,0 +1,12 @@ +declare module '@env' { + export const ENV: string; + export const WALLET_PRIVATE_KEY: string; + export const NFT_CONTRACT_ADDRESS_1: string; + export const NFT_CHAIN_ID_1: string; + export const NFT_TOKEN_ID_1: string; + export const NFT_HOLDER_WALLET_PRIVATE_KEY_1: string; + export const NFT_CONTRACT_ADDRESS_2: string; + export const NFT_CHAIN_ID_2: string; + export const NFT_TOKEN_ID_2: string; + export const NFT_HOLDER_WALLET_PRIVATE_KEY_2: string; +} diff --git a/packages/reactnative/ios/ReactNativeSdk.xcodeproj/project.pbxproj b/packages/reactnative/ios/ReactNativeSdk.xcodeproj/project.pbxproj new file mode 100644 index 000000000..14e8dfeed --- /dev/null +++ b/packages/reactnative/ios/ReactNativeSdk.xcodeproj/project.pbxproj @@ -0,0 +1,274 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 5E555C0D2413F4C50049A1A2 /* ReactNativeSdk.m in Sources */ = {isa = PBXBuildFile; fileRef = B3E7B5891CC2AC0600A0062D /* ReactNativeSdk.m */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 58B511D91A9E6C8500147676 /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = "include/$(PRODUCT_NAME)"; + dstSubfolderSpec = 16; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 134814201AA4EA6300B7C361 /* libReactNativeSdk.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libReactNativeSdk.a; sourceTree = BUILT_PRODUCTS_DIR; }; + B3E7B5881CC2AC0600A0062D /* ReactNativeSdk.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ReactNativeSdk.h; sourceTree = ""; }; + B3E7B5891CC2AC0600A0062D /* ReactNativeSdk.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ReactNativeSdk.m; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 58B511D81A9E6C8500147676 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 134814211AA4EA7D00B7C361 /* Products */ = { + isa = PBXGroup; + children = ( + 134814201AA4EA6300B7C361 /* libReactNativeSdk.a */, + ); + name = Products; + sourceTree = ""; + }; + 58B511D21A9E6C8500147676 = { + isa = PBXGroup; + children = ( + B3E7B5881CC2AC0600A0062D /* ReactNativeSdk.h */, + B3E7B5891CC2AC0600A0062D /* ReactNativeSdk.m */, + 134814211AA4EA7D00B7C361 /* Products */, + ); + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 58B511DA1A9E6C8500147676 /* ReactNativeSdk */ = { + isa = PBXNativeTarget; + buildConfigurationList = 58B511EF1A9E6C8500147676 /* Build configuration list for PBXNativeTarget "ReactNativeSdk" */; + buildPhases = ( + 58B511D71A9E6C8500147676 /* Sources */, + 58B511D81A9E6C8500147676 /* Frameworks */, + 58B511D91A9E6C8500147676 /* CopyFiles */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = ReactNativeSdk; + productName = RCTDataManager; + productReference = 134814201AA4EA6300B7C361 /* libReactNativeSdk.a */; + productType = "com.apple.product-type.library.static"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 58B511D31A9E6C8500147676 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0920; + ORGANIZATIONNAME = Facebook; + TargetAttributes = { + 58B511DA1A9E6C8500147676 = { + CreatedOnToolsVersion = 6.1.1; + }; + }; + }; + buildConfigurationList = 58B511D61A9E6C8500147676 /* Build configuration list for PBXProject "ReactNativeSdk" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + English, + en, + ); + mainGroup = 58B511D21A9E6C8500147676; + productRefGroup = 58B511D21A9E6C8500147676; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 58B511DA1A9E6C8500147676 /* ReactNativeSdk */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXSourcesBuildPhase section */ + 58B511D71A9E6C8500147676 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + B3E7B58A1CC2AC0600A0062D /* ReactNativeSdk.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 58B511ED1A9E6C8500147676 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + "EXCLUDED_ARCHS[sdk=*]" = arm64; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + }; + name = Debug; + }; + 58B511EE1A9E6C8500147676 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = YES; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + "EXCLUDED_ARCHS[sdk=*]" = arm64; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 58B511F01A9E6C8500147676 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + HEADER_SEARCH_PATHS = ( + "$(inherited)", + /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, + "$(SRCROOT)/../../../React/**", + "$(SRCROOT)/../../react-native/React/**", + ); + LIBRARY_SEARCH_PATHS = "$(inherited)"; + OTHER_LDFLAGS = "-ObjC"; + PRODUCT_NAME = ReactNativeSdk; + SKIP_INSTALL = YES; + }; + name = Debug; + }; + 58B511F11A9E6C8500147676 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + HEADER_SEARCH_PATHS = ( + "$(inherited)", + /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, + "$(SRCROOT)/../../../React/**", + "$(SRCROOT)/../../react-native/React/**", + ); + LIBRARY_SEARCH_PATHS = "$(inherited)"; + OTHER_LDFLAGS = "-ObjC"; + PRODUCT_NAME = ReactNativeSdk; + SKIP_INSTALL = YES; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 58B511D61A9E6C8500147676 /* Build configuration list for PBXProject "ReactNativeSdk" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 58B511ED1A9E6C8500147676 /* Debug */, + 58B511EE1A9E6C8500147676 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 58B511EF1A9E6C8500147676 /* Build configuration list for PBXNativeTarget "ReactNativeSdk" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 58B511F01A9E6C8500147676 /* Debug */, + 58B511F11A9E6C8500147676 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 58B511D31A9E6C8500147676 /* Project object */; +} diff --git a/packages/reactnative/ios/ReactNativeSdkViewManager.m b/packages/reactnative/ios/ReactNativeSdkViewManager.m new file mode 100644 index 000000000..661383f12 --- /dev/null +++ b/packages/reactnative/ios/ReactNativeSdkViewManager.m @@ -0,0 +1,34 @@ +#import + +@interface ReactNativeSdkViewManager : RCTViewManager +@end + +@implementation ReactNativeSdkViewManager + +RCT_EXPORT_MODULE(ReactNativeSdkView) + +- (UIView *)view +{ + return [[UIView alloc] init]; +} + +RCT_CUSTOM_VIEW_PROPERTY(color, NSString, UIView) +{ + [view setBackgroundColor:[self hexStringToColor:json]]; +} + +- hexStringToColor:(NSString *)stringToConvert +{ + NSString *noHashString = [stringToConvert stringByReplacingOccurrencesOfString:@"#" withString:@""]; + NSScanner *stringScanner = [NSScanner scannerWithString:noHashString]; + + unsigned hex; + if (![stringScanner scanHexInt:&hex]) return nil; + int r = (hex >> 16) & 0xFF; + int g = (hex >> 8) & 0xFF; + int b = (hex) & 0xFF; + + return [UIColor colorWithRed:r / 255.0f green:g / 255.0f blue:b / 255.0f alpha:1.0f]; +} + +@end diff --git a/packages/reactnative/package.json b/packages/reactnative/package.json index 8978987cc..e5f689dfc 100644 --- a/packages/reactnative/package.json +++ b/packages/reactnative/package.json @@ -1,25 +1,219 @@ { - "name": "@pushprotocol/reactnative", - "version": "0.2.0", + "name": "@push/react-native-sdk", + "version": "0.1.0", + "description": "test", + "main": "lib/commonjs/index", + "module": "lib/module/index", + "types": "lib/typescript/index.d.ts", + "react-native": { + "lib/commonjs/index": "src/index", + "crypto": "react-native-crypto", + "net": "react-native-tcp", + "http": "@tradle/react-native-http", + "https": "https-browserify", + "os": "react-native-os", + "fs": "react-native-level-fs", + "_stream_transform": "readable-stream/transform", + "_stream_readable": "readable-stream/readable", + "_stream_writable": "readable-stream/writable", + "_stream_duplex": "readable-stream/duplex", + "_stream_passthrough": "readable-stream/passthrough", + "stream": "stream-browserify" + }, + "source": "src/index", + "files": [ + "src", + "lib", + "android", + "ios", + "cpp", + "*.podspec", + "!lib/typescript/example", + "!ios/build", + "!android/build", + "!android/gradle", + "!android/gradlew", + "!android/gradlew.bat", + "!android/local.properties", + "!**/__tests__", + "!**/__fixtures__", + "!**/__mocks__", + "!**/.*" + ], + "scripts": { + "test": "jest", + "typecheck": "tsc --noEmit", + "lint": "eslint \"**/*.{js,ts,tsx}\"", + "prepack": "bob build", + "release": "release-it", + "example": "yarn --cwd example", + "bootstrap": "yarn example && yarn install && yarn example pods", + "clean": "del-cli android/build example/android/build example/android/app/build example/ios/build", + "postinstall": "node_modules/.bin/rn-nodeify --install crypto,assert,url,stream,events,http,https,os,url,net,fs --hack && patch-package" + }, + "keywords": [ + "react-native", + "ios", + "android" + ], + "repository": "https://github.com/ethereum-push-notification-service/push-sdk", + "author": "Push Protocol (https://www.push.org)", + "license": "MIT", + "bugs": { + "url": "https://github.com/ethereum-push-notification-service/push-sdk/issues" + }, + "homepage": "https://github.com/ethereum-push-notification-service/push-sdk#readme", "publishConfig": { "registry": "https://registry.npmjs.org/" }, + "dependencies": { + "@pushprotocol/restapi": "../../dist/packages/restapi", + "@tradle/react-native-http": "^2.0.1", + "assert": "^1.5.0", + "crypto": "^1.0.1", + "crypto-js": "3.1.9-1", + "ethers": "^5.7.1", + "events": "^3.3.0", + "https-browserify": "^0.0.1", + "process": "^0.11.10", + "react-native-crypto": "^2.2.0", + "react-native-fast-openpgp": "^2.6.0", + "react-native-get-random-values": "^1.9.0", + "react-native-level-fs": "^3.0.1", + "react-native-os": "^1.2.6", + "react-native-randombytes": "^3.6.1", + "react-native-tcp": "^3.3.2", + "react-native-webview": "^11.26.1", + "react-native-webview-crypto": "^0.0.25", + "readable-stream": "^1.0.33", + "stream": "^0.0.2", + "stream-browserify": "^1.0.0", + "text-encoding": "0.7.0", + "url": "^0.10.3" + }, + "devDependencies": { + "@commitlint/config-conventional": "^17.0.2", + "@evilmartians/lefthook": "^1.2.2", + "@react-native-community/eslint-config": "^3.0.2", + "@release-it/conventional-changelog": "^5.0.0", + "@types/jest": "^28.1.2", + "@types/react": "~17.0.21", + "@types/react-native": "0.70.0", + "commitlint": "^17.0.2", + "del-cli": "^5.0.0", + "eslint": "^8.4.1", + "eslint-config-prettier": "^8.5.0", + "eslint-plugin-prettier": "^4.0.0", + "jest": "^28.1.1", + "patch-package": "^7.0.0", + "pod-install": "^0.1.0", + "postinstall-postinstall": "^2.1.0", + "prettier": "^2.0.5", + "react": "18.2.0", + "react-native": "0.71.11", + "react-native-builder-bob": "^0.20.4", + "release-it": "^15.0.0", + "rn-nodeify": "^10.3.0", + "typescript": "^4.5.2" + }, + "resolutions": { + "@types/react": "17.0.21" + }, "peerDependencies": { - "@react-native-masked-view/masked-view": "^0.2.7", - "expo": "^45.0.0", - "expo-file-system": "^14.0.0", - "expo-linear-gradient": "^11.3.0", - "react": "^17.0.2 || ^18.0.0", - "react-native": "^0.68.2", - "react-native-svg": "^12.3.0", - "react-native-video": "^5.2.0", - "react-native-youtube": "^2.0.2" + "react": "*", + "react-native": "*", + "react-native-fast-openpgp": "^2.6.0" }, - "dependencies": { - "moment": "^2.29.4", - "react-native-device-detection": "^0.2.1", - "react-native-modal": "^13.0.1", - "react-native-parsed-text": "^0.0.22", - "react-native-progress-circle": "^2.1.0" + "engines": { + "node": ">= 16.0.0" + }, + "packageManager": "^yarn@1.22.15", + "jest": { + "preset": "react-native", + "modulePathIgnorePatterns": [ + "/example/node_modules", + "/lib/" + ] + }, + "commitlint": { + "extends": [ + "@commitlint/config-conventional" + ] + }, + "release-it": { + "git": { + "commitMessage": "chore: release ${version}", + "tagName": "v${version}" + }, + "npm": { + "publish": true + }, + "github": { + "release": true + }, + "plugins": { + "@release-it/conventional-changelog": { + "preset": "angular" + } + } + }, + "eslintConfig": { + "root": true, + "extends": [ + "@react-native-community", + "prettier" + ], + "rules": { + "prettier/prettier": [ + "error", + { + "quoteProps": "consistent", + "singleQuote": true, + "tabWidth": 2, + "trailingComma": "es5", + "useTabs": false + } + ] + } + }, + "eslintIgnore": [ + "node_modules/", + "lib/" + ], + "prettier": { + "quoteProps": "consistent", + "singleQuote": true, + "tabWidth": 2, + "trailingComma": "es5", + "useTabs": false + }, + "react-native-builder-bob": { + "source": "src", + "output": "lib", + "targets": [ + "commonjs", + "module", + [ + "typescript", + { + "project": "tsconfig.build.json" + } + ] + ] + }, + "browser": { + "lib/commonjs/index": "src/index", + "crypto": "react-native-crypto", + "net": "react-native-tcp", + "http": "@tradle/react-native-http", + "https": "https-browserify", + "os": "react-native-os", + "fs": "react-native-level-fs", + "_stream_transform": "readable-stream/transform", + "_stream_readable": "readable-stream/readable", + "_stream_writable": "readable-stream/writable", + "_stream_duplex": "readable-stream/duplex", + "_stream_passthrough": "readable-stream/passthrough", + "stream": "stream-browserify" } } diff --git a/packages/reactnative/patches/micro-ftch+0.3.1.patch b/packages/reactnative/patches/micro-ftch+0.3.1.patch new file mode 100644 index 000000000..0e91bb169 --- /dev/null +++ b/packages/reactnative/patches/micro-ftch+0.3.1.patch @@ -0,0 +1,17 @@ +diff --git a/node_modules/micro-ftch/index.js b/node_modules/micro-ftch/index.js +index 7f00c3d..da4a27f 100644 +--- a/node_modules/micro-ftch/index.js ++++ b/node_modules/micro-ftch/index.js +@@ -51,9 +51,9 @@ function detectType(b, type) { + let agents = {}; + function fetchNode(url, _options) { + let options = { ...DEFAULT_OPT, ..._options }; +- const http = require('http'); +- const https = require('https'); +- const zlib = require('zlib'); ++ const http = {}; ++ const https = {}; ++ const zlib = {}; + const { promisify } = require('util'); + const { resolve: urlResolve } = require('url'); + const isSecure = !!/^https/.test(url); diff --git a/packages/reactnative/patches/react-native-randombytes+3.6.1.patch b/packages/reactnative/patches/react-native-randombytes+3.6.1.patch new file mode 100644 index 000000000..fc9c6a000 --- /dev/null +++ b/packages/reactnative/patches/react-native-randombytes+3.6.1.patch @@ -0,0 +1,23 @@ +diff --git a/node_modules/react-native-randombytes/index.js b/node_modules/react-native-randombytes/index.js +index 7478cb3..bd2ecbd 100644 +--- a/node_modules/react-native-randombytes/index.js ++++ b/node_modules/react-native-randombytes/index.js +@@ -12,11 +12,13 @@ function toBuffer (nativeStr) { + } + + function init () { +- if (RNRandomBytes.seed) { +- let seedBuffer = toBuffer(RNRandomBytes.seed) +- addEntropy(seedBuffer) +- } else { +- seedSJCL() ++ if(RNRandomBytes){ ++ if (RNRandomBytes.seed) { ++ let seedBuffer = toBuffer(RNRandomBytes.seed) ++ addEntropy(seedBuffer) ++ } else { ++ seedSJCL() ++ } + } + } + diff --git a/packages/reactnative/push-react-native-sdk.podspec b/packages/reactnative/push-react-native-sdk.podspec new file mode 100644 index 000000000..adccca4bc --- /dev/null +++ b/packages/reactnative/push-react-native-sdk.podspec @@ -0,0 +1,36 @@ +require "json" + +package = JSON.parse(File.read(File.join(__dir__, "package.json"))) +folly_compiler_flags = '-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1 -Wno-comma -Wno-shorten-64-to-32' + +Pod::Spec.new do |s| + s.name = "push-react-native-sdk" + s.version = package["version"] + s.summary = package["description"] + s.homepage = package["homepage"] + s.license = package["license"] + s.authors = package["author"] + + s.platforms = { :ios => "11.0" } + s.source = { :git => "https://github.com/ethereum-push-notification-service/push-sdk.git", :tag => "#{s.version}" } + + s.source_files = "ios/**/*.{h,m,mm}" + + s.dependency "React-Core" + + # Don't install the dependencies when we run `pod install` in the old architecture. + if ENV['RCT_NEW_ARCH_ENABLED'] == '1' then + s.compiler_flags = folly_compiler_flags + " -DRCT_NEW_ARCH_ENABLED=1" + s.pod_target_xcconfig = { + "HEADER_SEARCH_PATHS" => "\"$(PODS_ROOT)/boost\"", + "OTHER_CPLUSPLUSFLAGS" => "-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1", + "CLANG_CXX_LANGUAGE_STANDARD" => "c++17" + } + s.dependency "React-RCTFabric" + s.dependency "React-Codegen" + s.dependency "RCT-Folly" + s.dependency "RCTRequired" + s.dependency "RCTTypeSafety" + s.dependency "ReactCommon/turbomodule/core" + end +end diff --git a/packages/reactnative/rollup.config.cjs b/packages/reactnative/rollup.config.cjs deleted file mode 100644 index 1bfee03c8..000000000 --- a/packages/reactnative/rollup.config.cjs +++ /dev/null @@ -1,26 +0,0 @@ -const nrwlConfig = require('@nrwl/react/plugins/bundle-rollup'); -const replace = require('@rollup/plugin-replace'); - -module.exports = (config) => { - const nxConfig = nrwlConfig(config); - - return { - ...nxConfig, - plugins: [ - ...nxConfig.plugins, - - /** - * IMAGE path hack for packaged library to be able to read images on - * the BUNDLE path instead of the SOURCE path - */ - replace({ - values: { - '../../assets/frownface.png': './lib/assets/frownface.png', - '../../assets/epnsbot.png': './lib/assets/epnsbot.png' - }, - delimiters: ['', ''], - }) - - ] - }; -} \ No newline at end of file diff --git a/packages/reactnative/scripts/bootstrap.js b/packages/reactnative/scripts/bootstrap.js new file mode 100644 index 000000000..172918947 --- /dev/null +++ b/packages/reactnative/scripts/bootstrap.js @@ -0,0 +1,29 @@ +const os = require('os'); +const path = require('path'); +const child_process = require('child_process'); + +const root = path.resolve(__dirname, '..'); +const args = process.argv.slice(2); +const options = { + cwd: process.cwd(), + env: process.env, + stdio: 'inherit', + encoding: 'utf-8', +}; + +if (os.type() === 'Windows_NT') { + options.shell = true; +} + +let result; + +if (process.cwd() !== root || args.length) { + // We're not in the root of the project, or additional arguments were passed + // In this case, forward the command to `yarn` + result = child_process.spawnSync('yarn', args, options); +} else { + // If `yarn` is run without arguments, perform bootstrap + result = child_process.spawnSync('yarn', ['bootstrap'], options); +} + +process.exitCode = result.status; diff --git a/packages/reactnative/shim.js b/packages/reactnative/shim.js new file mode 100644 index 000000000..812d6b45c --- /dev/null +++ b/packages/reactnative/shim.js @@ -0,0 +1,26 @@ +if (typeof __dirname === 'undefined') global.__dirname = '/' +if (typeof __filename === 'undefined') global.__filename = '' +if (typeof process === 'undefined') { + global.process = require('process') +} else { + const bProcess = require('process') + for (var p in bProcess) { + if (!(p in process)) { + process[p] = bProcess[p] + } + } +} + +process.browser = false +if (typeof Buffer === 'undefined') global.Buffer = require('buffer').Buffer + +// global.location = global.location || { port: 80 } +const isDev = typeof __DEV__ === 'boolean' && __DEV__ +process.env['NODE_ENV'] = isDev ? 'development' : 'production' +if (typeof localStorage !== 'undefined') { + localStorage.debug = isDev ? '*' : '' +} + +// If using the crypto shim, uncomment the following line to ensure +// crypto is loaded first, so it can populate global.crypto +// require('crypto') diff --git a/packages/reactnative/src/__tests__/index.test.tsx b/packages/reactnative/src/__tests__/index.test.tsx new file mode 100644 index 000000000..92643deb6 --- /dev/null +++ b/packages/reactnative/src/__tests__/index.test.tsx @@ -0,0 +1,4 @@ +import { PushApi } from '../index'; +it('write a test', async () => { + console.log(PushApi); +}); diff --git a/packages/reactnative/src/index.ts b/packages/reactnative/src/index.ts deleted file mode 100644 index 47945b57c..000000000 --- a/packages/reactnative/src/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './lib'; \ No newline at end of file diff --git a/packages/reactnative/src/index.tsx b/packages/reactnative/src/index.tsx new file mode 100644 index 000000000..60cf5f630 --- /dev/null +++ b/packages/reactnative/src/index.tsx @@ -0,0 +1,140 @@ +import '../shim.js'; +import 'text-encoding'; +import 'react-native-crypto'; +import 'react-native-get-random-values'; + +import OpenPGP from 'react-native-fast-openpgp'; +import { ethers } from 'ethers'; + +import * as PushApi from '@pushprotocol/restapi'; +import { IPGPHelper } from '@pushprotocol/restapi/src/lib/chat/helpers/pgp.js'; +import { ENV } from '@pushprotocol/restapi/src/lib/constants.js'; +import { LatestMessagesOptionsType } from '@pushprotocol/restapi/src/lib/chat/latestMessage.js'; +import { HistoricalMessagesOptionsType } from '@pushprotocol/restapi/src/lib/chat/historicalMessages.js'; +import { ChatCreateGroupType } from '@pushprotocol/restapi/src/lib/chat/createGroup.js'; +import { ChatUpdateGroupType } from '@pushprotocol/restapi/src/lib/chat/updateGroup.js'; +import { ChatsOptionsType } from '@pushprotocol/restapi/src/lib/chat/chats.js'; +import Constants from '@pushprotocol/restapi/src/lib/constants.js'; +import { decryptPGPKey } from '@pushprotocol/restapi/src/lib/helpers/crypto.js'; + +// TODO:fix this +//@ts-ignore +crypto.getRandomValues = (input) => { + return input; +}; + +// const randomBytes = new Uint8Array(8); +// console.log('inital', randomBytes); +// //@ts-ignore +// let res = crypto.getRandomValues(randomBytes); +// console.log('got res', res); + +const PGPHelper: IPGPHelper = { + async generateKeyPair() { + let keys = await OpenPGP.generate({ keyOptions: { rsaBits: 2048 } }); + return { + privateKeyArmored: keys.privateKey, + publicKeyArmored: keys.publicKey, + }; + }, + + async sign({ message, signingKey }) { + const publicKey = await OpenPGP.convertPrivateKeyToPublicKey(signingKey); + const signature = await OpenPGP.sign(message, publicKey, signingKey, ''); + return signature.replace('\nVersion: openpgp-mobile', ''); + }, + + async pgpEncrypt({ keys, plainText }) { + const encryptedSecret = await OpenPGP.encrypt(plainText, keys.join('\n')); + return encryptedSecret; + }, +}; + +const createUser = async (options: PushApi.user.CreateUserProps) => { + return await PushApi.user.createUserCore(options, PGPHelper); +}; + +const get = async (options: PushApi.AccountEnvOptionsType) => { + return await PushApi.user.get(options); +}; + +const profileUpdate = async (options: PushApi.user.ProfileUpdateProps) => { + return await PushApi.user.profile.updateCore(options, PGPHelper); +}; + +const send = async (options: PushApi.ChatSendOptionsType) => { + return await PushApi.chat.sendCore(options, PGPHelper); +}; + +const approve = async (options: PushApi.chat.ApproveRequestOptionsType) => { + return await PushApi.chat.approveCore(options, PGPHelper); +}; + +const conversationHash = async ( + options: PushApi.ConversationHashOptionsType +) => { + let hash = await PushApi.chat.conversationHash(options); + return hash; +}; + +const chats = async (options: ChatsOptionsType) => { + let chatsList = await PushApi.chat.chatsCore(options, PGPHelper); + return chatsList; +}; + +const latest = async (options: LatestMessagesOptionsType) => { + let latestMsg = await PushApi.chat.latestCore(options, PGPHelper); + return latestMsg; +}; + +const history = async (options: HistoricalMessagesOptionsType) => { + let msg = await PushApi.chat.historyCore(options, PGPHelper); + return msg; +}; + +const createGroup = async (options: ChatCreateGroupType) => { + let group = await PushApi.chat.createGroupCore(options, PGPHelper); + return group; +}; + +const updateGroup = async (options: ChatUpdateGroupType) => { + let updatedGroup = await PushApi.chat.updateGroupCore(options, PGPHelper); + return updatedGroup; +}; + +// checking if ethers works +const genRandomAddress = async () => { + const privateKey = + '25520e97c3f31af3824ff62e350126299997322ff7d340ffd81faa7f84609ef9'; + + // Create an instance of Wallet using the private key + const wallet = new ethers.Wallet(privateKey); + + // Get the address from the wallet + const address = wallet.address; + + return address; +}; + +const profileUpgrade = PushApi.user.auth.update; + +export { + PGPHelper, + genRandomAddress, + createUser, + get, + profileUpdate, + PushApi, + ENV, + conversationHash, + latest, + history, + createGroup, + updateGroup, + chats, + decryptPGPKey, + profileUpgrade, + send, + approve, + Constants, +}; diff --git a/packages/reactnative/src/lib/assets/epnsbot.png b/packages/reactnative/src/lib/assets/epnsbot.png deleted file mode 100644 index 530859af93f7a26569d2e6d285da7ccb92164acc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2281 zcmX|@dpHy98^#iX2aNQB%3*{(1<37ISylO3lqYnAH`BsC`JdzmP1D& z#|kORp)~K9A|2$=oE1ObU%&UcuIF$+_kDf7*Z2PCdCs{UChU^hBPAv#w#&gD=eD^U zZ%s+y=6Y<~N}8A$z==xoWO)*u(E(93BmclCN{~@3jlP)|6T?`?()|O%gIHinPzW^= z3z=zXhJdMoSjaImqA`(f8x%^lk7EQKjXO*Vhzk!u1wyQ?q%g7QO#m&3ly|D|5L&W$3kqj1i_v}7qD#Xt7>+i!KqKJbKLcVV1;#J}gVAm{yFX%^5f&24V$snsSWHZeQH+UE6e9!% zN1;$KV+0I=fNoYmne0fGe=IbTxo->cKL##{8Ni^@S=6XV@D|gb5_O7&g+O3iBCtOy zoAzM;`r8ct?NCtUW?LAW{-L(G$6{g(EJblyQi+Js9(?DrrhKsbDUSj&S-O%NdWvu}YCz*5y*xJU=LQQll=6x@skE zj=|QN$b-_8&ev8?nEqYA)Q4ZQqQ2Ek>t5PRhSIb2Cgqh#n(&(SuJB$L@!9s@x75yC zsd)<33wyBrKLk5AU>^ap-cP6WPmUcT_pV1E(oU`G*@o~emvj<-iEKIn+cS^y|+dm*8;NT?XDnQ8FFAR9&>p0Q}; zqnk%9vJQ+R^QYtP9VUG}7f$%BaHhNIafZMMD|gY1z3?DBPhX>0t*&~*Z{=zhII#to z;BuMU$#!;;1dwBd+g!g@)i|t9)eF+%f|nA0eRe;Br!K+(QWN~$&ZFZ4=2wppYafsj zDOD8d`>QALGfjQD@6t(K6>js~MkJKi{MFjiYRxv?S2jY$-C2@zr9*-jg;Dv4KI@p- zf+}B+t5QdHE#j}Js+IYg=%kv|e^gau1x5?8yPNqVbWk>f$nFC&xOX%7c)SZSATvZurD8 zv%)f-08o6dHhkud_I;+k%hWlk8$)&j3nNPDT9pl@6hXkm+_yd>Mo&%*H)EZhp4L3r zn@bq|^y-uD%8?lbk1Gg+C+Zox-4=tT?zeUhe$p|G_I7<3Yv_)4W8=cI3z9)Eu8O0M#*+{(Fo7kUD10G7(4r~FY>pAUpG zSpQm&MRm33h09?UD)js!=5KCS+xt=WaYT$4>mEEsM|!ABs?=?AAl$~q!V5nvs#u== zHKqROI00}{BS1IdggQ>Kin`hx|8w#bD*M+vjVd{g$2rSAI;Srb`n{zG)U1u5>F>)O_GZ`ga?}de;6!CckKydpt; zz;Ch$q^i!x)Cc{jD#{C6J)I4zzALhq1@-Y?5jH+!~<&==MPR}E>` zKfH>MAC^eqX@HGF21f6W*_C!`q8#+z>z- zN-a+ai-2K3KlY;^0NjiUIHPU=w4PWOJ2_ZXBFvBQY6v%*#n1;?{rl3VQbFeT9!rt$ zKE8MKGSR2S3($UJzwVLSY?CPlVnSv=%2pYKIPi?^ghdS8)p`ir{p?aJ$dLJKZ58tE3LXa9b!OgB_9{p+`H!=VO)9tm+4>6@Y~m2$^)!Ya$`q9( z>Qt-D7zTSFW4jkx>512Jo_jUH+Z>CNAJJA0>XGKTXrD=x60}Xz(`mG;|1O70s>X2W`e*u&oBDMek diff --git a/packages/reactnative/src/lib/assets/epnsbot@2x.png b/packages/reactnative/src/lib/assets/epnsbot@2x.png deleted file mode 100644 index 4e5addec45dd93ff732270bcf657943b24c18fa8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5130 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 a^)2TUZkycEg7^Qv@KhBw70TpZ2LBIGSkb8f diff --git a/packages/reactnative/src/lib/assets/epnsbot@3x.png b/packages/reactnative/src/lib/assets/epnsbot@3x.png deleted file mode 100644 index b46ff18bd51ea6ce6ad7d737ec21925bb2ebf2d5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8524 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�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 diff --git a/packages/reactnative/src/lib/components/DownloadHelper.ts b/packages/reactnative/src/lib/components/DownloadHelper.ts deleted file mode 100644 index 29b32aac7..000000000 --- a/packages/reactnative/src/lib/components/DownloadHelper.ts +++ /dev/null @@ -1,93 +0,0 @@ -/* eslint-disable no-useless-escape */ -// @ts-nocheck -import * as FileSystem from 'expo-file-system'; - -// Download Helper Function -const DownloadHelper = { - // To get Temp Save Location - getTempSaveLocation: function (fileURL: string) { - return ( - FileSystem.documentDirectory + - DownloadHelper.getSaveFileName(fileURL, true) - ); - }, - // To get Actual Save Location - getActualSaveLocation: function (fileURL: string) { - return ( - FileSystem.documentDirectory + - DownloadHelper.getSaveFileName(fileURL, false) - ); - }, - // To get Save File Name - getSaveFileName: function (fileURL: string, useTempLocation: boolean) { - // Remove all http, https protocols first - fileURL = fileURL.replace(/(^\w+:|^)\/\//, ''); - - // /[`~!@#$%^&*()_|+\-=?;:'",.<>\{\}\[\]\\\/]/gi - // Remove all special characters - fileURL = fileURL.replace(/[`~!@#$%^&*()_|+\-=?;:'",<>\{\}\[\]\\\/]/gi, ''); - - // Remove all but 250 characters - if (fileURL.length > 250) { - fileURL = fileURL.substr(-250); - } - - if (useTempLocation) { - return fileURL + '.temp'; - } else { - return fileURL; - } - }, - // Determine if media is supported video - isMediaSupportedVideo: function (fileURL: string) { - // check if media external embed first - if (DownloadHelper.isMediaExternalEmbed(fileURL)) { - return true; - } else { - // check if mp4 extension - if (fileURL.split('.').pop() === 'mp4') { - return true; - } - } - - // if all else fail - return false; - }, - // check if media is external embed, like youtube, soundcloud, etc - isMediaExternalEmbed: function (fileURL: string) { - return DownloadHelper.isMediaYoutube(fileURL); - }, - // Determine if youtube - isMediaYoutube: function (fileURL: string) { - if (fileURL !== undefined || fileURL !== '') { - const regExp = - /^.*(youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=|\&v=|\?v=)([^#\&\?]*).*/; - const match = fileURL.match(regExp); - if (match && match[2] && match[2].length === 11) { - // embed url - // const embedURL = - // 'https://www.youtube.com/embed/' + - // match[2] + - // '?autoplay=1&enablejsapi=1'; - return true; - } - } - - return false; - }, - // Get youtube id - getYoutubeID: function (fileURL: string) { - if (fileURL !== undefined || fileURL !== '') { - const regExp = - /^.*(youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=|\&v=|\?v=)([^#\&\?]*).*/; - const match = fileURL.match(regExp); - if (match && match[2] && match[2].length === 11) { - return match[2]; - } - } - - return false; - }, -}; - -export default DownloadHelper; diff --git a/packages/reactnative/src/lib/components/chainDetails/arbitrumSVG.tsx b/packages/reactnative/src/lib/components/chainDetails/arbitrumSVG.tsx deleted file mode 100644 index 7106c3552..000000000 --- a/packages/reactnative/src/lib/components/chainDetails/arbitrumSVG.tsx +++ /dev/null @@ -1,29 +0,0 @@ -import * as React from 'react'; -import { SVGProps } from 'react'; - -const ArbitrumSvgComponent = (props: SVGProps) => ( - - - - - - - -); - -export default ArbitrumSvgComponent; diff --git a/packages/reactnative/src/lib/components/chainDetails/bscSVG.tsx b/packages/reactnative/src/lib/components/chainDetails/bscSVG.tsx deleted file mode 100644 index 69b002455..000000000 --- a/packages/reactnative/src/lib/components/chainDetails/bscSVG.tsx +++ /dev/null @@ -1,22 +0,0 @@ -// @ts-nocheck -import * as React from 'react'; -import Svg, {Circle, Path } from 'react-native-svg'; - -const BscSvgComponent = (props: any) => ( - - - - -); - -export default BscSvgComponent; diff --git a/packages/reactnative/src/lib/components/chainDetails/ethereumSVG.tsx b/packages/reactnative/src/lib/components/chainDetails/ethereumSVG.tsx deleted file mode 100644 index 6a1b709a2..000000000 --- a/packages/reactnative/src/lib/components/chainDetails/ethereumSVG.tsx +++ /dev/null @@ -1,34 +0,0 @@ -// @ts-nocheck -import * as React from "react" -import Svg, { G, Path } from "react-native-svg" - -const EthereumSvgComponent = (props : any) => ( - - - - - - - - - - -) - -export default EthereumSvgComponent diff --git a/packages/reactnative/src/lib/components/chainDetails/index.tsx b/packages/reactnative/src/lib/components/chainDetails/index.tsx deleted file mode 100644 index dbd6c8e19..000000000 --- a/packages/reactnative/src/lib/components/chainDetails/index.tsx +++ /dev/null @@ -1,30 +0,0 @@ -import EthereumSvg from "./ethereumSVG"; -import PolygonSvg from "./polygonSVG"; -import GraphSvg from "./thegraphSVG"; -import BscSvg from "./bscSVG"; -import OptimismSvg from "./optimismSVG" -import PolygonZKEVMSvg from "./polygonZkEVMSVG"; -import ArbitrumSvgComponent from "./arbitrumSVG"; - -type Network = { - label: string; - Icon: any; -}; - -const networks: Record = { - ETH_TEST_GOERLI: { label: "ETHEREUM GOERLI", Icon: EthereumSvg }, - ETH_MAINNET: { label: "ETHEREUM MAINNET", Icon: EthereumSvg }, - POLYGON_TEST_MUMBAI: { label: "POLYGON MUMBAI", Icon: PolygonSvg }, - POLYGON_MAINNET: { label: "POLYGON MAINNET", Icon: PolygonSvg }, - BSC_TESTNET: { label: "BSC TESTNET", Icon: BscSvg }, - BSC_MAINNET: { label: "BSC MAINNET", Icon: BscSvg }, - OPTIMISM_TESTNET: { label: "OPTIMISM TESTNET", Icon: OptimismSvg }, - OPTIMISM_MAINNET: { label: "OPTIMISM MAINNET", Icon: OptimismSvg }, - POLYGON_ZK_EVM_TESTNET: {label:"POLYGON_ZK_EVM_TESTNET",Icon: PolygonZKEVMSvg}, - POLYGON_ZK_EVM_MAINNET: {label:"POLYGON_ZK_EVM_MAINNET",Icon: PolygonZKEVMSvg}, - ARBITRUM_TESTNET: {label:"ARBITRUM_TESTNET",Icon: ArbitrumSvgComponent}, - ARBITRUMONE_MAINNET: {label: "ARBITRUMONE_MAINNET", Icon: ArbitrumSvgComponent}, - THE_GRAPH: { label: "THE GRAPH", Icon: GraphSvg }, -}; - -export default networks \ No newline at end of file diff --git a/packages/reactnative/src/lib/components/chainDetails/optimismSVG.tsx b/packages/reactnative/src/lib/components/chainDetails/optimismSVG.tsx deleted file mode 100644 index 900b92514..000000000 --- a/packages/reactnative/src/lib/components/chainDetails/optimismSVG.tsx +++ /dev/null @@ -1,27 +0,0 @@ -// @ts-nocheck -import * as React from 'react'; -import Svg, { Defs, G, Path, Rect } from 'react-native-svg'; - -const OptimismSvgComponent = (props: any) => ( - - - - - - - - - - - - - -); - -export default OptimismSvgComponent; diff --git a/packages/reactnative/src/lib/components/chainDetails/polygonSVG.tsx b/packages/reactnative/src/lib/components/chainDetails/polygonSVG.tsx deleted file mode 100644 index 71e6469a1..000000000 --- a/packages/reactnative/src/lib/components/chainDetails/polygonSVG.tsx +++ /dev/null @@ -1,24 +0,0 @@ -// @ts-nocheck -import * as React from "react" -import Svg, { Path } from "react-native-svg" - -const PolygonSvgComponent = (props : any) => ( - - - -) - -export default PolygonSvgComponent diff --git a/packages/reactnative/src/lib/components/chainDetails/polygonZkEVMSVG.tsx b/packages/reactnative/src/lib/components/chainDetails/polygonZkEVMSVG.tsx deleted file mode 100644 index 5fa77721d..000000000 --- a/packages/reactnative/src/lib/components/chainDetails/polygonZkEVMSVG.tsx +++ /dev/null @@ -1,44 +0,0 @@ -import * as React from 'react'; -const PolygonZKEVMSvgComponent = (props: any) => ( - - - - - - - - - - - - - - - -); -export default PolygonZKEVMSvgComponent; diff --git a/packages/reactnative/src/lib/components/chainDetails/thegraphSVG.tsx b/packages/reactnative/src/lib/components/chainDetails/thegraphSVG.tsx deleted file mode 100644 index 479348d37..000000000 --- a/packages/reactnative/src/lib/components/chainDetails/thegraphSVG.tsx +++ /dev/null @@ -1,35 +0,0 @@ -// @ts-nocheck -import * as React from "react" -import Svg, { Circle, Path } from "react-native-svg" - -const GraphSvgComponent = (props) => ( - - - - -) - -export default GraphSvgComponent diff --git a/packages/reactnative/src/lib/components/index.tsx b/packages/reactnative/src/lib/components/index.tsx deleted file mode 100644 index 99db76cbc..000000000 --- a/packages/reactnative/src/lib/components/index.tsx +++ /dev/null @@ -1 +0,0 @@ -export * from './notifications'; \ No newline at end of file diff --git a/packages/reactnative/src/lib/components/loaders/EPNSActivity.tsx b/packages/reactnative/src/lib/components/loaders/EPNSActivity.tsx deleted file mode 100644 index d2f383f0e..000000000 --- a/packages/reactnative/src/lib/components/loaders/EPNSActivity.tsx +++ /dev/null @@ -1,102 +0,0 @@ -// @ts-nocheck -import * as React from 'react'; -import {View, ActivityIndicator, Platform, StyleSheet} from 'react-native'; - -import MaskedView from '@react-native-masked-view/masked-view'; -import {LinearGradient} from 'expo-linear-gradient'; - -import GLOBALS from '../../globals'; - - -export type EPNSActivityProps = { - style?: any; - size?: number | 'small' | 'large' | undefined; - color?: string; -}; - -export const EPNSActivity = (props: EPNSActivityProps) => { - const {style, size, color} = props; - - return ( - - {Platform.OS === 'android' || color ? ( - - ) : ( - - - - }> - - - - )} - - ); -}; - -// Styling -const styles = StyleSheet.create({ - container: { - alignSelf: 'center', - alignItems: 'center', - justifyContent: 'flex-end', - }, - small: { - width: 40, - height: 20, - }, - big: { - height: 36, - width: 36, - }, - maskedView: { - flex: 1, - flexDirection: 'row', - height: '100%', - }, - maskedElementView: { - backgroundColor: 'transparent', - flex: 1, - alignItems: 'center', - }, - maskedTitle: { - color: 'black', - fontWeight: 'bold', - }, - fullgradient: { - alignItems: 'flex-end', - width: '100%', - }, -}); diff --git a/packages/reactnative/src/lib/components/loaders/ImageDownloadWithIndicator.tsx b/packages/reactnative/src/lib/components/loaders/ImageDownloadWithIndicator.tsx deleted file mode 100644 index f8aeb0154..000000000 --- a/packages/reactnative/src/lib/components/loaders/ImageDownloadWithIndicator.tsx +++ /dev/null @@ -1,299 +0,0 @@ -import React, {useState, useRef, useEffect} from 'react'; -import { - StyleSheet, - View, - Image, - TouchableWithoutFeedback, - ImageResizeMode, - ImageSourcePropType, -} from 'react-native'; - -import * as FileSystem from 'expo-file-system'; - -import ProgressCircle from 'react-native-progress-circle'; -import { EPNSActivity } from './EPNSActivity'; -import DownloadHelper from '../DownloadHelper'; -import GLOBALS from '../../globals'; - -const MAX_ATTEMPTS = 3; - -const badImgPath = '../../assets/frownface.png'; - -const usePrevious = (value: T): T | undefined => { - const ref = useRef(); - useEffect(() => { - ref.current = value; - }); - - return ref.current; -}; - -type ImageDownloadWithIndicatorProps = { - style: any; - fileURL?: string; - imgsrc?: ImageSourcePropType; - miniProgressLoader?: boolean; - margin?: number; - resizeMode: ImageResizeMode | string; - onPress?: (arg0: string) => void; -}; - - -export const ImageDownloadWithIndicator = (props: ImageDownloadWithIndicatorProps) => { - const [indicator, setIndicator] = useState(false); - const [downloading, setDownloading] = useState(true); - const [downloadProgress, setDownloadProgress] = useState(0); - const [fileURI, setFileURI] = useState(''); - const [attemptNumber, setAttemptNumber] = useState(0); - const [defaulted, setDefaulted] = useState(false); - - const _isMounted = useRef(false); - - const previousFileUrl = usePrevious(props.fileURL); - - // derived values - const contentContainerStyle: any = {}; - - if (props.margin) { - contentContainerStyle.margin = props.margin; - } - - let modifiedResizeMode = props.resizeMode; - if (defaulted) { - modifiedResizeMode = 'center'; - } - - // To Start Download - const startDownload = async (_fileURL?: string) => { - const localFileTempURI = DownloadHelper.getTempSaveLocation(_fileURL || ''); - - // Create File Download - const downloadResumable = FileSystem.createDownloadResumable( - _fileURL || '', - localFileTempURI, - {}, - dwProg => { - const progress = - dwProg.totalBytesWritten / dwProg.totalBytesExpectedToWrite; - const progressPerc = Number((progress * 100).toFixed(2)); - // console.log('Progress for ' + _fileURL + ': ' + progressPerc); - - if (_isMounted.current) { - setDownloadProgress(progressPerc); - } - }, - ); - - // Initiate - try { - const downloadResult = await downloadResumable.downloadAsync(); - - // console.log(DownloadHelper.getActualSaveLocation(fileURL)); - - // Download completed, move file to actual location - try { - await FileSystem.moveAsync({ - from: downloadResult?.uri || '', - to: DownloadHelper.getActualSaveLocation(_fileURL || ''), - }); - } catch (e) { - console.warn(e); - } - - // Go Back to check and initiate operation - await checkAndInitiateOperation(_fileURL || ''); - } catch (e) { - console.warn(e); - } - }; - - // Check - const checkAndInitiateOperation = async (_fileURL?: string) => { - // Do Nothing, this is already loaded image - if (props.imgsrc) { - setIndicator(false); - setDownloading(false); - setDownloadProgress(100); - // setFileURI(props.imgsrc); - return; - } - - const localFileURI = DownloadHelper.getActualSaveLocation(_fileURL || ''); - const localFileInfo = await FileSystem.getInfoAsync(localFileURI); - - if (localFileInfo.exists) { - if (_isMounted.current) { - setIndicator(false); - setDownloading(false); - setDownloadProgress(100); - setFileURI(localFileURI); - } else { - if (attemptNumber <= MAX_ATTEMPTS) { - if (_isMounted.current) { - setIndicator(false); - setDownloading(true); - setDownloadProgress(0); - setAttemptNumber(attemptNumber + 1); - } - - await startDownload(_fileURL); - } else { - // Image can't be retrieved, Display bad image - // console.log('---> image cannot be retrieved, Display bad image'); - setIndicator(false); - setDownloading(false); - setDownloadProgress(100); - // setFileURI(''); - setDefaulted(true); - } - } - } - }; - - const renderDownloadingView = () => { - return ( - - {props.miniProgressLoader === true ? ( - - ) : ( - - )} - - ); - }; - - const renderBadImageView = () => { - return ( - - ); - }; - - const renderImageSourceView = (imgSrcPath: ImageSourcePropType) => { - return ( - - ); - }; - - const renderImageView = () => { - // console.log('\n\n\n Debug info: '); - // console.log({ indicator, downloading, defaulted, imgsrc: props.imgsrc, fileURIExists: !!fileURI }); - - if (props.imgsrc) { - return renderImageSourceView(props.imgsrc); - } - - if (indicator) { - return ; - } - - if (downloading) { - return renderDownloadingView(); - } - - if (defaulted || !fileURI) { - return renderBadImageView(); - } - - return ( - - ); - } - - // mount - useEffect(() => { - _isMounted.current = true; - checkAndInitiateOperation(props.fileURL); - - return () => { - _isMounted.current = false; - }; - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); - - // fileURL change - useEffect(() => { - // Check for prop change - if (previousFileUrl !== props.fileURL) { - setIndicator(true); - setDownloading(true); - setDownloadProgress(0); - setFileURI(''); - - checkAndInitiateOperation(props.fileURL); - } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [props.fileURL]); - - - return ( - { - if (props.onPress) { - props.onPress(fileURI); - } - }} - disabled={!props.onPress ? true : false}> - - - {renderImageView()} - - - - ); -}; - -const styles = StyleSheet.create({ - container: { - flex: 1, - overflow: 'hidden', - }, - innerContainer: { - flex: 1, - justifyContent: 'center', - alignItems: 'center', - overflow: 'hidden', - }, - contentContainer: { - justifyContent: 'center', - alignItems: 'center', - aspectRatio: 1, - width: '100%', - overflow: 'hidden', - }, - downloading: { - flex: 1, - justifyContent: 'center', - alignItems: 'center', - width: '100%', - padding: 40, - }, - image: { - flex: 1, - resizeMode: 'cover', - width: '100%', - height: '100%', - overflow: 'hidden', - }, - // this is not present actually in the legacy code - activity: {}, -}); diff --git a/packages/reactnative/src/lib/components/loaders/VideoDownloadWithIndicator.tsx b/packages/reactnative/src/lib/components/loaders/VideoDownloadWithIndicator.tsx deleted file mode 100644 index a1cd6873a..000000000 --- a/packages/reactnative/src/lib/components/loaders/VideoDownloadWithIndicator.tsx +++ /dev/null @@ -1,340 +0,0 @@ -// @ts-nocheck -import React, { Component } from "react"; -import { - StyleSheet, - View, - Image, - TouchableWithoutFeedback, -} from "react-native"; -import * as FileSystem from "expo-file-system"; - -import Video from "react-native-video"; -import YouTube from "react-native-youtube"; - -import ProgressCircle from "react-native-progress-circle"; -import { EPNSActivity } from "./EPNSActivity"; - -import DownloadHelper from "../DownloadHelper"; - -import GLOBALS from "../../globals"; - -const MAX_ATTEMPTS = 3; - - -export type VideoDownloadWithIndicatorProps = { - style: any; - fileURL: string; - resizeMode?: string; - youTubeAPIKey: string; -}; - -type VideoDownloadWithIndicatorState = { - indicator: boolean; - downloading: boolean; - downloadProgress: number; - fileURI: string; - attemptNumber: number; - defaulted: boolean; -}; - - -class VideoDownloadWithIndicator extends Component { - // CONSTRUCTOR - constructor(props: VideoDownloadWithIndicatorProps) { - super(props); - - this.state = { - indicator: false, - downloading: true, - downloadProgress: 0, - fileURI: "", - - attemptNumber: 0, - defaulted: false, - }; - - // Set Mounted - this._isMounted = false; - } - - // COMPONENT MOUNTED - componentDidMount() { - // Start Operation - this._isMounted = true; - this.checkAndInitiateOperation(this.props.fileURL); - } - - // COMPONENT UPDATED - componentDidUpdate(prevProps) { - // Check for prop change - if (this.props.fileURL !== prevProps.fileURL) { - this.setState({ - indicator: true, - downloading: true, - downloadProgress: 0, - fileURI: "", - }); - - this.checkAndInitiateOperation(this.props.fileURL); - } - } - - // COMPONENT UNMOUNTED - componentWillUnmount() { - this._isMounted = false; - } - - // FUNCTIONS - // Check - checkAndInitiateOperation = async (fileURL) => { - if (DownloadHelper.isMediaExternalEmbed(fileURL)) { - // Do Nothing, this is already loaded media - this.setState({ - indicator: false, - downloading: false, - downloadProgress: "100%", - fileURI: fileURL, - }); - - return; - } - - const localFileURI = DownloadHelper.getActualSaveLocation(fileURL); - const localFileInfo = await FileSystem.getInfoAsync(localFileURI); - - if (localFileInfo.exists) { - if (this._isMounted) { - this.setState({ - indicator: false, - downloading: false, - downloadProgress: 100, - fileURI: localFileURI, - }); - } - - // console.log("File Exists on: |" + localFileURI + "|"); - } else { - if (this.state.attemptNumber <= MAX_ATTEMPTS) { - if (this._isMounted) { - this.setState({ - indicator: false, - downloading: true, - downloadProgress: 0, - attemptNumber: this.state.attemptNumber + 1, - }); - } - - await this.startDownload(fileURL); - } else { - // Image can't be retrieved, Display bad image - this.setState({ - indicator: false, - downloading: false, - downloadProgress: "100%", - fileURI: require('../../assets/frownface.png'), - defaulted: true, - }); - } - } - }; - - // To Start Download - startDownload = async (fileURL) => { - const localFileTempURI = DownloadHelper.getTempSaveLocation(fileURL); - - // Create File Download - const downloadResumable = FileSystem.createDownloadResumable( - fileURL, - localFileTempURI, - {}, - (dwProg) => { - const progress = - dwProg.totalBytesWritten / dwProg.totalBytesExpectedToWrite; - const progressPerc = Number((progress * 100).toFixed(2)); - //console.log("Progress for " + fileURL + ": " + progressPerc); - - if (this._isMounted) { - this.setState({ - downloadProgress: progressPerc, - }); - } - } - ); - - // Initiate - try { - const { uri } = await downloadResumable.downloadAsync(); - // console.log("MOVING"); - // console.log(uri); - // console.log(DownloadHelper.getActualSaveLocation(fileURL)); - - // Download completed, move file to actual location - try { - await FileSystem.moveAsync({ - from: uri, - to: DownloadHelper.getActualSaveLocation(fileURL), - }); - } catch (e) { - console.warn(e); - } - - // Go Back to check and initiate operation - await this.checkAndInitiateOperation(fileURL); - } catch (e) { - console.warn(e); - } - }; - - // on video bufferring - onBuffer = (response) => { - // console.log('onBuffer: ', response); - }; - - // When Errored - videoError = (error) => { - // console.log("Error on playback" + error); - - this.setState({ - indicator: false, - downloading: false, - downloadProgress: "100%", - fileURI: require('../../assets/frownface.png'), - defaulted: true, - }); - }; - - // handle on press - onPress = () => { - // console.log("here"); - this.player.presentFullscreenPlayer(); - - if (this.props.onPress) { - this.props.onPress(); - } - }; - - // RENDER - render() { - const { - style, - miniProgressLoader, - margin, - resizeMode, - } = this.props; - - const contentContainerStyle = {}; - if (margin) { - contentContainerStyle.margin = margin; - } - - let modifiedResizeMode = resizeMode; - if (this.state.defaulted) { - modifiedResizeMode = "center"; - } - - return ( - { - this.onPress(this.state.fileURI); - }} - disabled={true} - > - - - {this.state.indicator ? ( - - ) : this.state.downloading ? ( - - {miniProgressLoader === true ? ( - - ) : ( - - )} - - ) : this.state.defaulted === true ? ( - - ) : DownloadHelper.isMediaExternalEmbed(this.state.fileURI) === - false ? ( - - - - ); - } -} - -const styles = StyleSheet.create({ - container: { - flex: 1, - overflow: "hidden", - }, - innerContainer: { - flex: 1, - height: "100%", - overflow: "hidden", - }, - contentContainer: { - justifyContent: "center", - alignItems: "center", - aspectRatio: 1, - width: "100%", - overflow: "hidden", - }, - downloading: { - flex: 1, - justifyContent: "center", - alignItems: "center", - width: "100%", - padding: 40, - }, - backgroundVideo: { - position: "absolute", - top: 0, - left: 0, - bottom: 0, - right: 0, - }, -}); - -export { - VideoDownloadWithIndicator -} \ No newline at end of file diff --git a/packages/reactnative/src/lib/components/loaders/index.tsx b/packages/reactnative/src/lib/components/loaders/index.tsx deleted file mode 100644 index 113de8946..000000000 --- a/packages/reactnative/src/lib/components/loaders/index.tsx +++ /dev/null @@ -1,3 +0,0 @@ -export * from './EPNSActivity'; -export * from './ImageDownloadWithIndicator'; -export * from './VideoDownloadWithIndicator'; diff --git a/packages/reactnative/src/lib/components/notifications/index.tsx b/packages/reactnative/src/lib/components/notifications/index.tsx deleted file mode 100644 index 3f0d15b4e..000000000 --- a/packages/reactnative/src/lib/components/notifications/index.tsx +++ /dev/null @@ -1 +0,0 @@ -export * from './notification'; \ No newline at end of file diff --git a/packages/reactnative/src/lib/components/notifications/notification.tsx b/packages/reactnative/src/lib/components/notifications/notification.tsx deleted file mode 100644 index bbc064056..000000000 --- a/packages/reactnative/src/lib/components/notifications/notification.tsx +++ /dev/null @@ -1,427 +0,0 @@ -import React from 'react'; -import { - View, Text, TouchableOpacity, StyleSheet, - Linking, Image, TouchableWithoutFeedback -} from 'react-native'; - -import Modal from 'react-native-modal'; -import device from 'react-native-device-detection'; -import moment from 'moment'; - -import { ParseText } from '../parsetext'; -import GLOBALS from '../../globals'; -import { extractTimeStamp } from './utils'; -import DownloadHelper from '../DownloadHelper'; -import chainDetails from '../chainDetails'; - -import { ImageDownloadWithIndicator, VideoDownloadWithIndicator } from '../loaders'; - - -// ================= Define types -export type chainNameType = "ETH_TEST_GOERLI" | "POLYGON_TEST_MUMBAI" | "ETH_MAINNET" | "POLYGON_MAINNET" | "BSC_MAINNET" | "BSC_TESTNET" | "OPTIMISM_MAINNET" | "OPTIMISM_TESTNET" | "POLYGON_ZK_EVM_TESTNET" | "POLYGON_ZK_EVM_MAINNET" | "ARBITRUMONE_MAINNET" | "ARBITRUM_TESTNET" | "THE_GRAPH" | undefined; - -const botImageLocalPath = '../../assets/epnsbot.png'; - -export type NotificationProps = { - notificationTitle: string; - notificationBody: string; - app: string; - icon: string; - appbot?: string; - image: string; - cta?: string; - url?: string; - chainName: chainNameType; - onImagePreview?: (arg0: string) => void; - youTubeAPIKey: string; -}; - - -export const Notification : React.FC = ({ - notificationTitle = '', - notificationBody = '', - cta = '', - app = '', - icon = '', - appbot = '', - image = '', - url = '', - chainName, - youTubeAPIKey, - onImagePreview -}) => { - const ctaEnabled = Boolean(cta); - - const { - originalBody: parsedBody, - timeStamp -} = extractTimeStamp(notificationBody || ''); - - // store the image to be displayed in this state variable - const [ isVisible, setIsVisible ] = React.useState(false); - - const internalBot = appbot === '1'; - - const ChainIcon = chainName && chainDetails[chainName] ? chainDetails[chainName].Icon : null; - - // Finally mark if the device is a tablet or a phone - let contentInnerStyle = {}; - let contentImgStyle = {}; - let contentMsgImgStyle = {}; - - let contentVidStyle = {}; - let contentMsgVidStyle = {}; - - // let bgVidStyle = {}; - // let contentYoutubeStyle = { - // marginBottom: 12 - // } - let contentBodyStyle = {}; - let containMode = 'contain'; - - if (device.isTablet) { - // Change the style to better suit tablet - contentInnerStyle = { - flexDirection: 'row', - alignItems: 'center', - }; - - contentImgStyle = { - width: '25%', - aspectRatio: 1, - borderRadius: 10, - paddingRight: 20, - }; - - contentMsgImgStyle = { - margin: 20, - marginRight: 5, - borderRadius: 10, - borderWidth: 0, - }; - - // contentYoutubeStyle = { - // width: '25%', - // aspectRatio: 1, - // borderRadius: 10, - // paddingRight: 20, - // margin: 20, - // marginRight: 10 - // } - - contentVidStyle = { - width: '25%', - aspectRatio: 1, - margin: 20, - marginRight: 10 - } - - contentBodyStyle = { - flex: 1, - }; - - contentMsgVidStyle = { - width: '100%', - } - - // bgVidStyle = { - // borderRadius: 10, - // } - - containMode = 'cover'; - } - - const ctaStyles = { - borderColor: GLOBALS.COLORS.SLIGHT_GRAY, - backgroundColor: GLOBALS.COLORS.GRADIENT_SECONDARY, - borderWidth: 1, - borderRadius: GLOBALS.ADJUSTMENTS.FEED_ITEM_RADIUS - }; - - if(ctaEnabled){ - ctaStyles['borderColor'] = GLOBALS.COLORS.GRADIENT_SECONDARY; - ctaStyles['borderWidth'] = 1; // this is 1 in web - ctaStyles['borderRadius'] = GLOBALS.ADJUSTMENTS.FEED_ITEM_RADIUS; - } - - // to check valid url - const validURL = (str: string) => { - const pattern = new RegExp( - "^(https?:\\/\\/)?" + // protocol - "((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|" + // domain name - "((\\d{1,3}\\.){3}\\d{1,3}))" + // OR ip (v4) address - "(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*" + // port and path - "(\\?[;&a-z\\d%_.~+=-]*)?" + // query string - "(\\#[-a-z\\d_]*)?$", - "i" - ); // fragment locator - return !!pattern.test(str); - }; - - const onPress = (url:string) => { - // TODO: fixTS - // eslint-disable-next-line no-constant-condition - if (validURL(url) || 1) { - // console.log("OPENING URL ", url); - // Bypassing the check so that custom app domains can be opened - Linking.canOpenURL(url).then(supported => { - if (supported) { - Linking.openURL(url); - } - }); - } - }; - - return ( - onPress(cta)} - disabled={!ctaEnabled}> - - - - onPress(url)} - > - - - - {app} - - - - - - {ChainIcon ? ( - - - - ) : null} - - - - - {!image ? null : DownloadHelper.isMediaSupportedVideo(image) ? ( - - - - ) : ( - - { - if (onImagePreview) { - // means List view gallery method is present. - onImagePreview(fileURI); - } else { - // use Item's own view method - setIsVisible(true); - } - }} - /> - - )} - - - {!notificationTitle ? null : ( - {notificationTitle} - )} - - {/* The entire content of the main component */} - - {/* The entire content of the main component */} - - - {!timeStamp ? null : ( - - - {moment - .utc(parseInt(timeStamp) * 1000) - .local() - .format('DD MMM YYYY | hh:mm A')} - - - )} - - - - - {/* when an image is clicked on make it fulll screen */} - - setIsVisible(false)}> - - - - {/* when an image is clicked on make it fulll screen */} - - - ); -}; - -// ================= Define styled components -// / Styling -const styles = StyleSheet.create({ - backgroundVideo: { - position: 'relative', - width: '100%', - aspectRatio: 1, - top: 0, - bottom: 0, - right: 0, - }, - container: { - marginVertical: 15, - marginHorizontal: 20 - }, - inner: { - margin: 1, - overflow: 'hidden', - borderRadius: GLOBALS.ADJUSTMENTS.FEED_ITEM_RADIUS, - }, - header: { - width: '100%', - paddingVertical: 8, - paddingHorizontal: 10, - backgroundColor: GLOBALS.COLORS.SLIGHTER_GRAY, - flexDirection: 'row', - justifyContent: 'space-between', - alignItems: 'center', - borderBottomWidth: 1, - borderColor: GLOBALS.COLORS.SLIGHT_GRAY, - }, - appInfo: { - flex: 1, - alignItems: 'flex-start', - }, - appLink: { - flexDirection: 'row', - justifyContent: 'flex-start', - alignItems: 'center', - }, - appicon: { - flex: 0, - justifyContent: 'center', - alignItems: 'center', - borderRadius: 5, - height: 24, - width: 24, - aspectRatio: 1, - marginRight: 5, - overflow: 'hidden', - backgroundColor: GLOBALS.COLORS.SLIGHT_GRAY, - }, - apptext: { - marginRight: 10, - marginLeft: 5, - fontSize: 14, - color: GLOBALS.COLORS.BLACK, - fontWeight: '400', - }, - networkIcon: { - fontSize: 9, - color: 'blue', - fontWeight: '300', - height: 18, - width: 18 - }, - appsecret: { - width: 16, - height: 16, - borderRadius: 16, - }, - content: { - backgroundColor: GLOBALS.COLORS.WHITE, - padding: 12, // as per Web - paddingBottom: 0 - }, - contentLoader: { - margin: 20, - }, - contentVid: { - width: '100%', - marginBottom: 12 - }, - msgVid: { - borderColor: GLOBALS.COLORS.SLIGHT_GRAY, - backgroundColor: GLOBALS.COLORS.SLIGHTER_GRAY, - borderBottomWidth: 1, - }, - contentImg: { - width: '100%', - aspectRatio: 2, - marginBottom: 12 - }, - msgImg: { - borderColor: GLOBALS.COLORS.SLIGHT_GRAY, - backgroundColor: GLOBALS.COLORS.SLIGHTER_GRAY, - borderBottomWidth: 1, - resizeMode: 'contain', - }, - contentBody: { - paddingHorizontal: 0, - }, - msgSub: { - fontSize: 18, - fontWeight: '400', - color: GLOBALS.COLORS.BLACK, - paddingVertical: 0, - }, - msg: { - paddingTop: 5, - paddingBottom: 15, - }, - timestampOuter: { - display: 'flex', - justifyContent: 'center', - alignSelf: 'flex-end', - paddingBottom: 8, - paddingHorizontal: 15, - marginRight: -20, - overflow: 'hidden', - }, - timestamp: { - fontWeight: 'bold', - fontSize: 10, - color: '#808080', - }, - image: { - flex: 1, - resizeMode: 'cover', - width: '100%', - height: '100%', - overflow: 'hidden', - marginBottom: 12 // same as web - }, - overlayImage: { - flex: 1, - resizeMode: 'contain', - borderRadius: 20, - overflow: 'hidden', - } -}); diff --git a/packages/reactnative/src/lib/components/notifications/utils.ts b/packages/reactnative/src/lib/components/notifications/utils.ts deleted file mode 100644 index 78c1f3936..000000000 --- a/packages/reactnative/src/lib/components/notifications/utils.ts +++ /dev/null @@ -1,43 +0,0 @@ -/** - * @description Parse the contents of the markdown version of the notification body - * @param message the notification body we wish to parse - * @returns - */ - export const FormatBody = (message: string) => { - // firstly replace all new line content of the text with
- // in order to parse it as HTML i.e "\n\n" => "

" - const parsedNewLine = message.replace(/\n/g, "
"); - // remove leading slashes from text i.e \alex => alex - const removedLeadingSlash = parsedNewLine.replace(/^\\/g, ""); - - return removedLeadingSlash; - } - - -/** - * @description parse and extract the timestamp from the body of the notification and remove the text from the body - * @param notificationBody the text which would represent the body of the notification - * @returns - */ - export function extractTimeStamp(notificationBody: string): { - notificationBody: string; - timeStamp: string; - originalBody: string; - } { - const parsedBody = { - notificationBody: FormatBody(notificationBody), - timeStamp: "", - originalBody: notificationBody, - }; - const matches = notificationBody.match(/\[timestamp:(.*?)\]/); - if (matches) { - parsedBody.timeStamp = matches[1] || ''; - const textWithoutTimeStamp = notificationBody.replace( - / *\[timestamp:[^)]*\] */g, - "" - ); - parsedBody.notificationBody = FormatBody(textWithoutTimeStamp); - parsedBody.originalBody = textWithoutTimeStamp; - } - return parsedBody; - } \ No newline at end of file diff --git a/packages/reactnative/src/lib/components/parsetext/index.tsx b/packages/reactnative/src/lib/components/parsetext/index.tsx deleted file mode 100644 index 76ef60f5c..000000000 --- a/packages/reactnative/src/lib/components/parsetext/index.tsx +++ /dev/null @@ -1 +0,0 @@ -export * from './parsetext'; \ No newline at end of file diff --git a/packages/reactnative/src/lib/components/parsetext/parsetext.tsx b/packages/reactnative/src/lib/components/parsetext/parsetext.tsx deleted file mode 100644 index a97bc8978..000000000 --- a/packages/reactnative/src/lib/components/parsetext/parsetext.tsx +++ /dev/null @@ -1,227 +0,0 @@ -// @ts-nocheck -// TODO: fixTS -import * as React from 'react'; -import { StyleSheet, View, Linking, Platform } from 'react-native'; -import ParsedText from 'react-native-parsed-text'; - -import GLOBALS from '../../globals'; - - -export function ParseText(props: any) { - const { - style, - title, - fontSize, - textStyle, - } = props; - - const handleUrlPress = (matchingString: string, matchIndex:number/*: number*/) => { - const pattern = /\[([^:]+):([^\]]+)\]/i; - const match = matchingString.match(pattern) || []; - - const midComponent = `${match[2]}`; - const url = midComponent.substr(midComponent.indexOf('||') + 2); - - Linking.openURL(url); - }; - - const handleAppSettings = () => { - if (Platform.OS === 'ios') { - Linking.openURL('app-settings:'); - } - }; - - const renderStyles = (matchingString: string, matches: string[]) => { - // matches => ["[@michel:5455345]", "@michel", "5455345"] - const pattern = /\[([^:]+):([^\]]+)\]/i; - const match = matchingString.match(pattern) || []; - - return `${match[2]}`; - }; - - const renderThreeStyles = (matchingString: string, matches: string[]) => { - // matches => ["[@michel:5455345]", "@michel", "5455345"] - const pattern = /\[([^:]+):([^\]]+)\]/i; - const match = matchingString.match(pattern) || []; - - const midComponent = `${match[2]}`; - const midText = midComponent.substr(0, midComponent.indexOf('||')); - return midText; - }; - - const TextUpdatedStyle = { - fontSize: fontSize - } - - const parseSettings = [ - { - pattern: /\[(u):([^\]]+)\]/i, // url - style: [styles.primary, styles.bold, styles.italics, styles.underline], - onPress: handleUrlPress, - renderText: renderThreeStyles - }, - { - pattern: /\[(ub):([^\]]+)\]/i, // url - style: [styles.secondary, styles.bold, styles.italics, styles.underline], - onPress: handleUrlPress, - renderText: renderThreeStyles - }, - { - pattern: /\[(ut):([^\]]+)\]/i, // url - style: [styles.third, styles.bold, styles.italics, styles.underline], - onPress: handleUrlPress, - renderText: renderThreeStyles - }, - { - pattern: /\[(up):([^\]]+)\]/i, // url - style: [styles.primary, styles.italics, styles.underline], - onPress: handleUrlPress, - renderText: renderThreeStyles - }, - { - pattern: /\[(d):([^\]]+)\]/i, // default or primary gradient color - style: [styles.primary, styles.bold], - renderText: renderStyles - }, - { - pattern: /\[(s):([^\]]+)\]/i, // secondary gradient color - style: [styles.secondary, styles.bold], - renderText: renderStyles - }, - { - pattern: /\[(t):([^\]]+)\]/i, // third gradient color - style: [styles.third, styles.bold], - renderText: renderStyles - }, - { - pattern: /\[(e):([^\]]+)\]/i, // error - style: [styles.error, styles.bold], - renderText: renderStyles - }, - { - pattern: /\[(b):([^\]]+)\]/i, // bold - style: styles.bold, - renderText: renderStyles - }, - { - pattern: /\[(i):([^\]]+)\]/i, // italics - style: styles.italics, - renderText: renderStyles - }, - { - pattern: /\[(bi):([^\]]+)\]/i, // bolditalics - style: [styles.bold, styles.italics], - renderText: renderStyles - }, - { - pattern: /\[(w):([^\]]+)\]/i, // white - style: [styles.white], - renderText: renderStyles - }, - { - pattern: /\[(wb):([^\]]+)\]/i, // whitebold - style: [styles.white, styles.bold], - renderText: renderStyles - }, - { - pattern: /\[(mg):([^\]]+)\]/i, // midgray - style: [styles.midgray], - renderText: renderStyles - }, - { - pattern: /\[(dg):([^\]]+)\]/i, // darkgray - style: [styles.darkgray], - renderText: renderStyles - }, - { - pattern: /\[(ddg):([^\]]+)\]/i, // darker gray - style: [styles.darkergray], - renderText: renderStyles - }, - ]; - - if (Platform.OS === 'ios') { - parseSettings.push( - { - pattern: /\[(appsettings):([^\]]+)\]/i, - style: [styles.link, styles.bold, styles.italics, styles.underline], - onPress: handleAppSettings, - renderText: renderStyles - } - ); - } - else if (Platform.OS === 'android') { - parseSettings.push( - { - pattern: /\[(appsettings):([^\]]+)\]/i, - style: [styles.bold], - renderText: renderStyles - } - ); - } - - return ( - - - {title} - - - ); - -} - - -// Styling -const styles = StyleSheet.create({ - container: { - }, - name: { - color: GLOBALS.COLORS.SUBLIME_RED - }, - username: { - color: GLOBALS.COLORS.GRADIENT_SECONDARY - }, - text: { - color: GLOBALS.COLORS.BLACK - }, - primary: { - color: GLOBALS.COLORS.GRADIENT_PRIMARY, - }, - secondary: { - color: GLOBALS.COLORS.GRADIENT_SECONDARY, - }, - third: { - color: GLOBALS.COLORS.GRADIENT_THIRD, - }, - error: { - color: GLOBALS.COLORS.SUBLIME_RED, - }, - white: { - color: GLOBALS.COLORS.WHITE, - }, - midgray: { - color: GLOBALS.COLORS.MID_GRAY, - }, - darkgray: { - color: GLOBALS.COLORS.DARK_GRAY, - }, - darkergray: { - color: GLOBALS.COLORS.DARKER_GRAY, - }, - link: { - color: GLOBALS.COLORS.GRADIENT_PRIMARY, - }, - underline: { - textDecorationLine: 'underline', - }, - bold: { - fontWeight: 'bold' - }, - italics: { - fontStyle: 'italic' - } -}); \ No newline at end of file diff --git a/packages/reactnative/src/lib/globals.ts b/packages/reactnative/src/lib/globals.ts deleted file mode 100644 index 07389689a..000000000 --- a/packages/reactnative/src/lib/globals.ts +++ /dev/null @@ -1,137 +0,0 @@ -export default { - LINKS: { - APPBOT_NAME: 'App Bot', - APP_WEBSITE: 'https://epns.io', - DEV_EPNS_SERVER: 'https://backend-kovan.epns.io/apis', - PROD_EPNS_SERVER: 'https://backend-kovan.epns.io/apis', - METAMASK_LINK_STAGING: 'https://metamask.app.link/dapp/staging-app.epns.io', - METAMASK_LINK_PROD: 'https://metamask.app.link/dapp/staging-app.epns.io', - DEEPLINK_URL: 'https://metamask.app.link/dapp/staging-app.epns.io', - CNS_ENDPOINT: - 'https://unstoppabledomains.com/api/v1/resellers/udtesting/domains', - - ENDPOINT_AUTHTOKEN: '/pushtokens/authtoken', - ENDPOINT_REGISTER_NO_AUTH: '/pushtokens/register_no_auth', - ENDPOINT_REGISTER: '/pushtokens/register', - ENDPOINT_GET_FEEDS: '/feeds/get_feeds', - ENDPOINT_GET_SPAM_FEEDS: '/feeds/get_spam_feeds', - ENDPOINT_FETCH_CHANNELS: '/channels/fetch_channels', - ENDPOINT_FETCH_SUBSCRIPTION: '/channels/is_user_subscribed', - ENDPOINT_SUBSCRIBE_OFFCHAIN: '/channels/subscribe_offchain', - ENDPOINT_UNSUBSCRIBE_OFFCHAIN: '/channels/unsubscribe_offchain', - }, - - // For Async Storage --> Represents Key and some Constants - STORAGE: { - IS_SIGNED_IN: 'IsUserSignedIn', - SIGNED_IN_TYPE: 'SignedInType', - FIRST_SIGN_IN: 'FirstSignInByUser', - USER_LOCKED: 'UserLocked', - PASSCODE_ATTEMPTS: 'MaxPasscodeAttempts', - - STORED_WALLET_OBJ: 'StoredWalletObject', - ENCRYPTED_PKEY: 'EncryptedPrivateKey', - - HASHED_PASSCODE: 'HashedPasscode', - - PUSH_TOKEN: 'PushToken', - PUSH_TOKEN_TO_REMOVE: 'PushTokenToRemove', - PUSH_TOKEN_SERVER_SYNCED: 'PushTokenServerSynced', - PUSH_BADGE_COUNT: 'PushBadgeCount', - PUSH_BADGE_COUNT_PREVIOUS: 'PreviousPushBadgeCount', - }, - - CONSTANTS: { - CRED_TYPE_WALLET: 'TypeWallet', - CRED_TYPE_PRIVATE_KEY: 'TypePrivateKey', - - NULL_EXCEPTION: 'NULL', - - MAX_PASSCODE_ATTEMPTS: 5, - - PUSH_TYPE_NORMAL_MSG: 1, - PUSH_TYPE_ENCRYPTED_MSG: 2, - - FEED_ITEMS_TO_PULL: 20, - - STATUS_BAR_HEIGHT: 60, - }, - - ADJUSTMENTS: { - SCREEN_GAP_HORIZONTAL: 10, - SCREEN_GAP_VERTICAL: 10, - - DEFAULT_BIG_RADIUS: 10, - DEFAULT_MID_RADIUS: 8, - FEED_ITEM_RADIUS: 8, - }, - - COLORS: { - PRIMARY: 'rgba(27.0, 150.0, 227.0, 1.0)', - - LINKS: 'rgba(20.0, 126.0, 251.0, 1.0)', - - GRADIENT_PRIMARY: 'rgba(226.0, 8.0, 128.0, 1.0)', - GRADIENT_SECONDARY: 'rgba(53.0, 197.0, 243.0, 1.0)', - GRADIENT_THIRD: 'rgba(103.0, 76.0, 159.0, 1.0)', - - TRANSPARENT: 'transparent', - - WHITE: 'rgba(255.0, 255.0, 255.0, 1.0)', - DARK_WHITE: 'rgba(255.0, 255.0, 255.0, 0.75)', - MID_WHITE: 'rgba(255.0, 255.0, 255.0, 0.5)', - LIGHT_WHITE: 'rgba(255.0, 255.0, 255.0, 0.25)', - - SLIGHTER_GRAY: 'rgba(250.0, 250.0, 250.0, 1)', - SLIGHT_GRAY: 'rgba(231.0, 231.0, 231.0, 1)', - LIGHT_GRAY: 'rgba(225.0, 225.0, 225.0, 1)', - MID_GRAY: 'rgba(200.0, 200.0, 200.0, 1)', - DARK_GRAY: 'rgba(160.0, 160.0, 160.0, 1)', - DARKER_GRAY: 'rgba(100.0, 100.0, 100.0, 1)', - - LIGHT_BLACK_TRANS: 'rgba(0.0, 0.0, 0.0, 0.1)', - SEMI_MID_BLACK_TRANS: 'rgba(0.0, 0.0, 0.0, 0.25)', - MID_BLACK_TRANS: 'rgba(0.0, 0.0, 0.0, 0.5)', - DARK_BLACK_TRANS: 'rgba(0.0, 0.0, 0.0, 0.75)', - BLACK: 'rgba(0.0, 0.0, 0.0, 1.0)', - - CONFIRM_GREEN: 'rgba(50.0, 205.0, 50.0, 1.0)', - - CONFIRM: 'rgba(34.0, 139.0, 34.0, 1.0)', - WARNING: 'rgba(255.0, 153.0, 0.0, 1.0)', - - SUBLIME_RED: 'rgba(237.0, 59.0, 72.0, 1.0)', - BADGE_RED: 'rgba(208.0, 44.0, 30.0, 1.0)', - LIGHT_MAROON: 'rgba(159.0, 0.0, 0.0, 1.0)', - LIGHTER_MAROON: 'rgba(129.0, 0.0, 0.0, 1.0)', - }, - SCREENS: { - WELCOME: 'Welcome', - SIGNIN: 'SignIn', - SIGNINADVANCE: 'SignInAdvance', - BIOMETRIC: 'Biometric', - PUSHNOTIFY: 'PushNotify', - SETUPCOMPLETE: 'SetupComplete', - TABS: 'Tabs', - SETTINGS: 'Settings', - SPLASH: 'Splash', - FEED: 'Feed', - CHANNELS: 'Channels', - SPAM: 'Spam', - SAMPLEFEED: 'SampleFeed', - NEWWALLETSIGNIN: 'NewWalletSignIn', - }, - APP_AUTH_STATES: { - INITIALIZING: 1, - ONBOARDING: 2, - ONBOARDED: 3, - AUTHENTICATED: 4, - }, - AUTH_STATE: { - INITIALIZING: 'INITIALIZING', - ONBOARDING: 'ONBOARDING', - ONBOARDED: 'ONBOARDED', - AUTHENTICATED: 'AUTHENTICATED', - }, - }; - \ No newline at end of file diff --git a/packages/reactnative/src/lib/index.tsx b/packages/reactnative/src/lib/index.tsx deleted file mode 100644 index 099b463e3..000000000 --- a/packages/reactnative/src/lib/index.tsx +++ /dev/null @@ -1 +0,0 @@ -export * from './components'; \ No newline at end of file diff --git a/packages/reactnative/test-setup.ts b/packages/reactnative/test-setup.ts deleted file mode 100644 index 9f28ad211..000000000 --- a/packages/reactnative/test-setup.ts +++ /dev/null @@ -1 +0,0 @@ -import '@testing-library/jest-native/extend-expect'; diff --git a/packages/reactnative/tsconfig.build.json b/packages/reactnative/tsconfig.build.json new file mode 100644 index 000000000..999d3f3c8 --- /dev/null +++ b/packages/reactnative/tsconfig.build.json @@ -0,0 +1,5 @@ + +{ + "extends": "./tsconfig", + "exclude": ["example"] +} diff --git a/packages/reactnative/tsconfig.json b/packages/reactnative/tsconfig.json index 6d076c06d..392fa464b 100644 --- a/packages/reactnative/tsconfig.json +++ b/packages/reactnative/tsconfig.json @@ -1,20 +1,27 @@ { - "extends": "../../tsconfig.base.json", "compilerOptions": { - "jsx": "react-jsx", - "allowJs": true, + "baseUrl": "./", + "paths": { + "@push/react-native-sdk": ["./src/index"] + }, + "allowUnreachableCode": false, + "allowUnusedLabels": false, "esModuleInterop": true, - "allowSyntheticDefaultImports": true, "forceConsistentCasingInFileNames": true, - "strict": true, + "jsx": "react", + "lib": ["esnext"], + "module": "esnext", + "moduleResolution": "node", + "noFallthroughCasesInSwitch": true, "noImplicitReturns": true, - "noFallthroughCasesInSwitch": true - }, - "files": [], - "include": [], - "references": [ - { - "path": "./tsconfig.lib.json" - } - ] + "noImplicitUseStrict": false, + "noStrictGenericChecks": false, + "noUncheckedIndexedAccess": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "resolveJsonModule": true, + "skipLibCheck": true, + "strict": true, + "target": "esnext" + } } diff --git a/packages/reactnative/tsconfig.lib.json b/packages/reactnative/tsconfig.lib.json deleted file mode 100644 index b1ada63f2..000000000 --- a/packages/reactnative/tsconfig.lib.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "extends": "./tsconfig.json", - "compilerOptions": { - "outDir": "../../dist/out-tsc", - "types": ["node"], - "jsx": "react-native" - }, - "exclude": ["**/*.spec.ts", "**/*.spec.tsx", "test-setup.ts"], - "include": ["**/*.js", "**/*.jsx", "**/*.ts", "**/*.tsx"] -} diff --git a/packages/restapi/src/lib/chat/approveRequest.ts b/packages/restapi/src/lib/chat/approveRequest.ts index 44f0c8c02..7084bb32b 100644 --- a/packages/restapi/src/lib/chat/approveRequest.ts +++ b/packages/restapi/src/lib/chat/approveRequest.ts @@ -4,16 +4,17 @@ import Constants from '../constants'; import { EnvOptionsType, SignerType } from '../types'; import { approveRequestPayload, - sign, - getConnectedUserV2, IApproveRequestPayload, getAccountAddress, getWallet, getUserDID, + getConnectedUserV2Core, + PGPHelper, + IPGPHelper, } from './helpers'; import * as CryptoJS from 'crypto-js'; -interface ApproveRequestOptionsType extends EnvOptionsType { +export interface ApproveRequestOptionsType extends EnvOptionsType { /** * Chat request sender address */ @@ -34,6 +35,13 @@ interface ApproveRequestOptionsType extends EnvOptionsType { */ export const approve = async ( options: ApproveRequestOptionsType +): Promise => { + return await approveCore(options, PGPHelper); +}; + +export const approveCore = async ( + options: ApproveRequestOptionsType, + pgpHelper: IPGPHelper ): Promise => { const { status = 'Approved', @@ -60,7 +68,12 @@ export const approve = async ( isGroup = false; } - const connectedUser = await getConnectedUserV2(wallet, pgpPrivateKey, env); + const connectedUser = await getConnectedUserV2Core( + wallet, + pgpPrivateKey, + env, + pgpHelper + ); let fromDID = await getUserDID(senderAddress, env); let toDID = await getUserDID(address, env); @@ -76,7 +89,7 @@ export const approve = async ( }; const hash = CryptoJS.SHA256(JSON.stringify(bodyToBeHashed)).toString(); - const signature: string = await sign({ + const signature: string = await pgpHelper.sign({ message: hash, signingKey: connectedUser.privateKey!, }); diff --git a/packages/restapi/src/lib/chat/chats.ts b/packages/restapi/src/lib/chat/chats.ts index 20cc2624b..349a7d627 100644 --- a/packages/restapi/src/lib/chat/chats.ts +++ b/packages/restapi/src/lib/chat/chats.ts @@ -2,7 +2,7 @@ import axios from 'axios'; import { getAPIBaseUrls, isValidETHAddress } from '../helpers'; import Constants, { ENV } from '../constants'; import { IFeeds } from '../types'; -import { getInboxLists, getUserDID, addDeprecatedInfo } from './helpers'; +import { getInboxLists, getUserDID, addDeprecatedInfo, IPGPHelper, PGPHelper } from './helpers'; export type ChatsOptionsType = { account: string; @@ -28,7 +28,12 @@ export type ChatsOptionsType = { /** * Return the latest message from all wallet addresses you have talked to. This can be used when building the inbox page. */ + export const chats = async (options: ChatsOptionsType): Promise => { + return await chatsCore(options,PGPHelper) +} + +export const chatsCore = async (options: ChatsOptionsType, pgpHelper: IPGPHelper): Promise => { const { account, pgpPrivateKey, diff --git a/packages/restapi/src/lib/chat/conversationHash.ts b/packages/restapi/src/lib/chat/conversationHash.ts index 85a1aef50..9541fcb82 100644 --- a/packages/restapi/src/lib/chat/conversationHash.ts +++ b/packages/restapi/src/lib/chat/conversationHash.ts @@ -7,9 +7,8 @@ import { getConversationHashService, getUserDID } from './helpers'; * All chat messages are stored on IPFS. This function will return the latest message's CID (Content Identifier on IPFS). * Whenever a new message is sent or received, this CID will change. */ -export const conversationHash = async ( - options: ConversationHashOptionsType -) => { + +export const conversationHash = async(options: ConversationHashOptionsType) => { const { conversationId, account, env = Constants.ENV.PROD } = options || {}; try { if (!isValidETHAddress(account)) { diff --git a/packages/restapi/src/lib/chat/createGroup.ts b/packages/restapi/src/lib/chat/createGroup.ts index 4d451d3fe..3632603e5 100644 --- a/packages/restapi/src/lib/chat/createGroup.ts +++ b/packages/restapi/src/lib/chat/createGroup.ts @@ -5,12 +5,13 @@ import { EnvOptionsType, GroupDTO, SignerType, Rules } from '../types'; import { ICreateGroupRequestPayload, createGroupPayload, - sign, createGroupRequestValidator, getWallet, getUserDID, - getConnectedUserV2, + IPGPHelper, + PGPHelper, validateScheduleDates, + getConnectedUserV2Core, } from './helpers'; import * as CryptoJS from 'crypto-js'; @@ -35,8 +36,13 @@ export interface ChatCreateGroupType extends EnvOptionsType { rules?: Rules | null; } -export const createGroup = async ( - options: ChatCreateGroupType +export const createGroup = async (options: ChatCreateGroupType) => { + return await createGroupCore(options, PGPHelper); +}; + +export const createGroupCore = async ( + options: ChatCreateGroupType, + pgpHelper: IPGPHelper ): Promise => { const { account = null, @@ -89,7 +95,12 @@ export const createGroup = async ( const convertedMembers = await Promise.all(convertedMembersPromise); const convertedAdmins = await Promise.all(convertedAdminsPromise); - const connectedUser = await getConnectedUserV2(wallet, pgpPrivateKey, env); + const connectedUser = await getConnectedUserV2Core( + wallet, + pgpPrivateKey, + env, + pgpHelper + ); const bodyToBeHashed = { groupName: groupName, @@ -108,7 +119,7 @@ export const createGroup = async ( }; const hash = CryptoJS.SHA256(JSON.stringify(bodyToBeHashed)).toString(); - const signature: string = await sign({ + const signature: string = await pgpHelper.sign({ message: hash, signingKey: connectedUser.privateKey!, }); diff --git a/packages/restapi/src/lib/chat/helpers/crypto.ts b/packages/restapi/src/lib/chat/helpers/crypto.ts index 43021a45d..3637855b0 100644 --- a/packages/restapi/src/lib/chat/helpers/crypto.ts +++ b/packages/restapi/src/lib/chat/helpers/crypto.ts @@ -59,13 +59,41 @@ export const encryptAndSign = async ({ signature: string; sigType: string; encType: string; +}> => { + return await encryptAndSignCore({ + plainText, + keys, + privateKeyArmored, + secretKey, + pgpHelper: PGP.PGPHelper, + }); +}; + +export const encryptAndSignCore = async ({ + plainText, + keys, + privateKeyArmored, + secretKey, + pgpHelper, +}: { + plainText: string; + keys: Array; + privateKeyArmored: string; + secretKey: string; + pgpHelper: PGP.IPGPHelper; +}): Promise<{ + cipherText: string; + encryptedSecret: string; + signature: string; + sigType: string; + encType: string; }> => { const cipherText: string = AES.aesEncrypt({ plainText, secretKey }); - const encryptedSecret = await PGP.pgpEncrypt({ + const encryptedSecret = await pgpHelper.pgpEncrypt({ plainText: secretKey, keys: keys, }); - const signature: string = await PGP.sign({ + const signature: string = await pgpHelper.sign({ message: cipherText, signingKey: privateKeyArmored, }); @@ -88,7 +116,26 @@ export const signMessageWithPGP = async ({ signature: string; sigType: string; }> => { - const signature: string = await PGP.sign({ + return await signMessageWithPGPCore ({ + message, + privateKeyArmored, + pgpHelper: PGP.PGPHelper, + }); +}; + +export const signMessageWithPGPCore = async ({ + message, + privateKeyArmored, + pgpHelper +}: { + message: string; + privateKeyArmored: string; + pgpHelper: PGP.IPGPHelper; +}): Promise<{ + signature: string; + sigType: string; +}> => { + const signature: string = await pgpHelper.sign({ message: message, signingKey: privateKeyArmored, }); @@ -180,6 +227,28 @@ export const getEncryptedRequest = async ( env: ENV, group: GroupDTO | null, secretKey: string +): Promise => { + return await getEncryptedRequestCore( + receiverAddress, + senderCreatedUser, + message, + isGroup, + env, + group, + secretKey, + PGP.PGPHelper + ); +}; + +export const getEncryptedRequestCore = async ( + receiverAddress: string, + senderCreatedUser: IConnectedUser, + message: string, + isGroup: boolean, + env: ENV, + group: GroupDTO | null, + secretKey: string, + pgpHelper: PGP.IPGPHelper ): Promise => { if (!isGroup) { const receiverCreatedUser: IUser = await get({ @@ -198,9 +267,10 @@ export const getEncryptedRequest = async ( }); // If the user is being created here, that means that user don't have a PGP keys. So this intent will be in plaintext - const { signature } = await signMessageWithPGP({ + const { signature } = await signMessageWithPGPCore({ message: message, privateKeyArmored: senderCreatedUser.privateKey!, + pgpHelper: pgpHelper, }); return { @@ -217,9 +287,10 @@ export const getEncryptedRequest = async ( '-----BEGIN PGP PUBLIC KEY BLOCK-----' ) ) { - const { signature } = await signMessageWithPGP({ + const { signature } = await signMessageWithPGPCore({ message: message, privateKeyArmored: senderCreatedUser.privateKey!, + pgpHelper: pgpHelper, }); return { @@ -229,12 +300,13 @@ export const getEncryptedRequest = async ( signature: signature, }; } else { - const { cipherText, encryptedSecret, signature } = await encryptAndSign( + const { cipherText, encryptedSecret, signature } = await encryptAndSignCore( { plainText: message, keys: [receiverCreatedUser.publicKey, senderCreatedUser.publicKey], privateKeyArmored: senderCreatedUser.privateKey!, secretKey, + pgpHelper: pgpHelper, } ); return { @@ -247,9 +319,10 @@ export const getEncryptedRequest = async ( } } else if (group) { if (group.isPublic) { - const { signature } = await signMessageWithPGP({ + const { signature } = await signMessageWithPGPCore({ message: message, privateKeyArmored: senderCreatedUser.privateKey!, + pgpHelper: pgpHelper, }); return { message: message, @@ -261,11 +334,12 @@ export const getEncryptedRequest = async ( const publicKeys: string[] = group.members.map( (member) => member.publicKey ); - const { cipherText, encryptedSecret, signature } = await encryptAndSign({ + const { cipherText, encryptedSecret, signature } = await encryptAndSignCore({ plainText: message, keys: publicKeys, privateKeyArmored: senderCreatedUser.privateKey!, secretKey, + pgpHelper: pgpHelper, }); return { message: cipherText, diff --git a/packages/restapi/src/lib/chat/helpers/payloadHelper.ts b/packages/restapi/src/lib/chat/helpers/payloadHelper.ts index 16d8eaaf4..b322a8e00 100644 --- a/packages/restapi/src/lib/chat/helpers/payloadHelper.ts +++ b/packages/restapi/src/lib/chat/helpers/payloadHelper.ts @@ -1,4 +1,5 @@ import { isValidETHAddress, walletToPCAIP10 } from '../../helpers'; +import { getEncryptedRequestCore } from './crypto'; import { IConnectedUser, GroupDTO, @@ -11,9 +12,12 @@ import { } from '../../types'; import { getEncryptedRequest } from './crypto'; import { ENV } from '../../constants'; +import { IPGPHelper, PGPHelper } from './pgp'; import * as AES from './aes'; -import { MessageObj } from '../../types/messageTypes'; import { sign } from './pgp'; +import { MessageObj } from '../../types/messageTypes'; + + import * as CryptoJS from 'crypto-js'; export interface ISendMessagePayload { fromDID: string; @@ -88,33 +92,58 @@ export const sendMessagePayload = async ( messageType: string, group: GroupDTO | null, env: ENV +): Promise => { + return await sendMessagePayloadCore( + receiverAddress, + senderCreatedUser, + messageObj, + messageContent, + messageType, + group, + env, + PGPHelper, + ); +}; + + +export const sendMessagePayloadCore = async ( + receiverAddress: string, + senderCreatedUser: IConnectedUser, + messageObj: MessageObj | string, + messageContent: string, + messageType: string, + group: GroupDTO | null, + env: ENV, + pgpHelper: IPGPHelper, ): Promise => { const isGroup = !isValidETHAddress(receiverAddress); const secretKey: string = AES.generateRandomSecret(15); const { message: encryptedMessageContent, signature: deprecatedSignature } = - await getEncryptedRequest( + await getEncryptedRequestCore( receiverAddress, senderCreatedUser, messageContent, isGroup, env, group, - secretKey + secretKey, + pgpHelper ); const { message: encryptedMessageObj, encryptionType, aesEncryptedSecret, - } = await getEncryptedRequest( + } = await getEncryptedRequestCore( receiverAddress, senderCreatedUser, JSON.stringify(messageObj), isGroup, env, group, - secretKey + secretKey, + pgpHelper ); const body: ISendMessagePayload = { @@ -144,7 +173,7 @@ export const sendMessagePayload = async ( encryptedSecret: body.encryptedSecret, }; const hash = CryptoJS.SHA256(JSON.stringify(bodyToBeHashed)).toString(); - const signature: string = await sign({ + const signature: string = await pgpHelper.sign({ message: hash, signingKey: senderCreatedUser.privateKey!, }); diff --git a/packages/restapi/src/lib/chat/helpers/pgp.ts b/packages/restapi/src/lib/chat/helpers/pgp.ts index 024c5cd79..7d23e6591 100644 --- a/packages/restapi/src/lib/chat/helpers/pgp.ts +++ b/packages/restapi/src/lib/chat/helpers/pgp.ts @@ -1,5 +1,47 @@ import * as openpgp from 'openpgp'; +interface IPGPHelper{ + generateKeyPair(): Promise<{ privateKeyArmored: string; publicKeyArmored: string }>; + sign ({ message, signingKey }: { message: string; signingKey: string }): Promise; + pgpEncrypt ({ plainText, keys }: { plainText: string; keys: Array }): Promise; +} + +const PGPHelper:IPGPHelper = { + async generateKeyPair(){ + const keys = await openpgp.generateKey({ + type: 'rsa', + rsaBits: 2048, + userIDs: [{ name: '', email: '' }] + }) + return { + privateKeyArmored: keys.privateKey, + publicKeyArmored: keys.publicKey + } + }, + + async sign ({ message, signingKey }): Promise { + const messageObject: openpgp.Message = await openpgp.createMessage({ text: message }) + const privateKey: openpgp.PrivateKey = await openpgp.readPrivateKey({ armoredKey: signingKey }) + return await openpgp.sign({ message: messageObject, signingKeys: privateKey, detached: true }) + }, + + async pgpEncrypt ({ plainText, keys }): Promise { + const pgpKeys: openpgp.Key[] = []; + + for(let i = 0; i < keys.length; i++) { + pgpKeys.push(await openpgp.readKey({ armoredKey: keys[i] })); + } + const message: openpgp.Message = await openpgp.createMessage({ text: plainText }); + const encrypted: string = await openpgp.encrypt({ + message: message, + encryptionKeys: pgpKeys, + }); + return encrypted; + }, +} + +export {IPGPHelper, PGPHelper} + export const generateKeyPair = async (): Promise<{ privateKeyArmored: string; publicKeyArmored: string }> => { const keys = await openpgp.generateKey({ type: 'rsa', diff --git a/packages/restapi/src/lib/chat/helpers/user.ts b/packages/restapi/src/lib/chat/helpers/user.ts index 1c8cf2ff5..06a9a9d4b 100644 --- a/packages/restapi/src/lib/chat/helpers/user.ts +++ b/packages/restapi/src/lib/chat/helpers/user.ts @@ -1,8 +1,8 @@ import Constants, { ENV } from '../../constants'; -import { get, create } from '../../user'; +import { get, create, createUserCore } from '../../user'; import { IConnectedUser, IUser, SignerType, walletType } from '../../types'; import { getAccountAddress } from './wallet'; -import { getDecryptedPrivateKey } from '.'; +import { IPGPHelper, PGPHelper, getDecryptedPrivateKey } from '.'; import { isValidCAIP10NFTAddress, isValidETHAddress, @@ -78,6 +78,15 @@ export const getConnectedUserV2 = async ( wallet: walletType, privateKey: string | null, env: ENV +): Promise => { + return await getConnectedUserV2Core(wallet, privateKey, env, PGPHelper); +}; + +export const getConnectedUserV2Core = async ( + wallet: walletType, + privateKey: string | null, + env: ENV, + pgpHelper: IPGPHelper, ): Promise => { const address = await getAccountAddress(wallet); const user = await get({ account: address, env: env || Constants.ENV.PROD }); @@ -111,7 +120,7 @@ export const getConnectedUserV2 = async ( createUserProps.signer = wallet.signer; } createUserProps.env = env; - const newUser = await create(createUserProps); + const newUser = await createUserCore(createUserProps, pgpHelper); const decryptedPrivateKey = await getDecryptedPrivateKey( wallet, newUser, diff --git a/packages/restapi/src/lib/chat/historicalMessages.ts b/packages/restapi/src/lib/chat/historicalMessages.ts index 18b42ace2..ae7f4377c 100644 --- a/packages/restapi/src/lib/chat/historicalMessages.ts +++ b/packages/restapi/src/lib/chat/historicalMessages.ts @@ -3,6 +3,8 @@ import { pCAIP10ToWallet } from '../helpers'; import { AccountEnvOptionsType, IMessageIPFS } from '../types'; import { get } from '../user'; import { + IPGPHelper, + PGPHelper, addDeprecatedInfoToMessages, decryptConversation, getMessagesService, @@ -27,8 +29,14 @@ export interface HistoricalMessagesOptionsType extends AccountEnvOptionsType { /** * Get all the messages exchanged between users after the threadhash. */ -export const history = async ( - options: HistoricalMessagesOptionsType + +export const history = async(options: HistoricalMessagesOptionsType) => { + return await historyCore(options, PGPHelper); +} + +export const historyCore = async ( + options: HistoricalMessagesOptionsType, + pgpHelper: IPGPHelper ): Promise => { const { threadhash, diff --git a/packages/restapi/src/lib/chat/latestMessage.ts b/packages/restapi/src/lib/chat/latestMessage.ts index 910427c49..0be7df08f 100644 --- a/packages/restapi/src/lib/chat/latestMessage.ts +++ b/packages/restapi/src/lib/chat/latestMessage.ts @@ -1,5 +1,6 @@ import Constants from '../constants'; import { AccountEnvOptionsType } from '../types'; +import { IPGPHelper, PGPHelper } from './helpers'; import { history } from './historicalMessages'; export interface LatestMessagesOptionsType extends AccountEnvOptionsType { @@ -11,7 +12,11 @@ export interface LatestMessagesOptionsType extends AccountEnvOptionsType { /** * Get the latest chat message */ + export const latest = async (options: LatestMessagesOptionsType) => { + return await latestCore(options, PGPHelper) +} +export const latestCore = async (options: LatestMessagesOptionsType, pgpHelper: IPGPHelper) => { const { threadhash, pgpPrivateKey = '', diff --git a/packages/restapi/src/lib/chat/send.ts b/packages/restapi/src/lib/chat/send.ts index 095f0fa73..674c85b52 100644 --- a/packages/restapi/src/lib/chat/send.ts +++ b/packages/restapi/src/lib/chat/send.ts @@ -3,13 +3,15 @@ import { getAPIBaseUrls, isValidETHAddress } from '../helpers'; import Constants, { MessageType, ENV } from '../constants'; import { ChatSendOptionsType, MessageWithCID, SignerType } from '../types'; import { + IPGPHelper, + PGPHelper, getAccountAddress, - getConnectedUserV2, + getConnectedUserV2Core, getUserDID, getWallet, } from './helpers'; import { conversationHash } from './conversationHash'; -import { ISendMessagePayload, sendMessagePayload } from './helpers'; +import { ISendMessagePayload, sendMessagePayloadCore } from './helpers'; import { getGroup } from './getGroup'; import { MessageObj } from '../types/messageTypes'; import { validateMessageObj } from '../validations/messageObject'; @@ -19,6 +21,13 @@ import { validateMessageObj } from '../validations/messageObject'; */ export const send = async ( options: ChatSendOptionsType +): Promise => { + return await sendCore(options, PGPHelper); +}; + +export const sendCore = async ( + options: ChatSendOptionsType, + pgpHelper: IPGPHelper ): Promise => { try { /** @@ -35,7 +44,7 @@ export const send = async ( await validateOptions(computedOptions); const wallet = getWallet({ account, signer }); - const sender = await getConnectedUserV2(wallet, pgpPrivateKey, env); + const sender = await getConnectedUserV2Core(wallet, pgpPrivateKey, env, pgpHelper); const receiver = await getUserDID(to, env); const API_BASE_URL = getAPIBaseUrls(env); const isGroup = isValidETHAddress(to) ? false : true; @@ -71,14 +80,15 @@ export const send = async ( apiEndpoint = `${API_BASE_URL}/v1/chat/message`; } - const body: ISendMessagePayload = await sendMessagePayload( + const body: ISendMessagePayload = await sendMessagePayloadCore( receiver, sender, messageObj, messageContent, messageType, group, - env + env, + pgpHelper ); return (await axios.post(apiEndpoint, body)).data; } catch (err) { diff --git a/packages/restapi/src/lib/chat/updateGroup.ts b/packages/restapi/src/lib/chat/updateGroup.ts index af5633be3..b8967095d 100644 --- a/packages/restapi/src/lib/chat/updateGroup.ts +++ b/packages/restapi/src/lib/chat/updateGroup.ts @@ -11,8 +11,11 @@ import { import { IUpdateGroupRequestPayload, updateGroupPayload, - sign, getWallet, + IPGPHelper, + PGPHelper, + getConnectedUserV2Core, + sign, getAccountAddress, getUserDID, getConnectedUserV2, @@ -43,8 +46,16 @@ export interface ChatUpdateGroupType extends EnvOptionsType { /** * Update Group information */ + export const updateGroup = async ( options: ChatUpdateGroupType +) => { + return await updateGroupCore(options, PGPHelper); +} + +export const updateGroupCore = async ( + options: ChatUpdateGroupType, + pgpHelper: IPGPHelper ): Promise => { const { chatId, @@ -78,8 +89,7 @@ export const updateGroup = async ( address, groupDescription ); - - const connectedUser = await getConnectedUserV2(wallet, pgpPrivateKey, env); + const connectedUser = await getConnectedUserV2Core(wallet, pgpPrivateKey, env, pgpHelper); const convertedMembersPromise = members.map(async (each) => { return getUserDID(each, env); }); @@ -97,7 +107,7 @@ export const updateGroup = async ( chatId: chatId, }; const hash = CryptoJS.SHA256(JSON.stringify(bodyToBeHashed)).toString(); - const signature: string = await sign({ + const signature: string = await pgpHelper.sign({ message: hash, signingKey: connectedUser.privateKey!, }); diff --git a/packages/restapi/src/lib/user/createUser.ts b/packages/restapi/src/lib/user/createUser.ts index 2d812de3f..9e04da1e0 100644 --- a/packages/restapi/src/lib/user/createUser.ts +++ b/packages/restapi/src/lib/user/createUser.ts @@ -1,6 +1,7 @@ import { + IPGPHelper, + PGPHelper, createUserService, - generateKeyPair, generateRandomSecret, getAccountAddress, getWallet, @@ -41,9 +42,14 @@ export type CreateUserProps = { interface ICreateUser extends IUser { decryptedPrivateKey?: string; } -export const create = async ( - options: CreateUserProps -): Promise => { + + +export const create = async (options:CreateUserProps):Promise=>{ + return await createUserCore(options, PGPHelper) +} + +export const createUserCore = async ( options: CreateUserProps, + pgpHelper: IPGPHelper): Promise => { const passPrefix = '$0Pc'; //password prefix to ensure password validation const { env = Constants.ENV.PROD, @@ -87,7 +93,7 @@ export const create = async ( // Report Progress progressHook?.(PROGRESSHOOK['PUSH-CREATE-01'] as ProgressHookType); - const keyPairs = await generateKeyPair(); + const keyPairs = await pgpHelper.generateKeyPair(); // Report Progress progressHook?.(PROGRESSHOOK['PUSH-CREATE-02'] as ProgressHookType); diff --git a/packages/restapi/src/lib/user/index.ts b/packages/restapi/src/lib/user/index.ts index d5c2b9084..3d5fff4f8 100644 --- a/packages/restapi/src/lib/user/index.ts +++ b/packages/restapi/src/lib/user/index.ts @@ -1,5 +1,6 @@ import { authUpdate } from './auth.updateUser'; -import { profileUpdate } from './profile.updateUser'; +import { profileUpdate, profileUpdateCore } from './profile.updateUser'; +export { ProfileUpdateProps } from './profile.updateUser'; export * from './createUser'; export * from './getFeeds'; export * from './getSubscriptions'; @@ -16,4 +17,5 @@ export const auth = { }; export const profile = { update: profileUpdate, + updateCore: profileUpdateCore, }; diff --git a/packages/restapi/src/lib/user/profile.updateUser.ts b/packages/restapi/src/lib/user/profile.updateUser.ts index 85b102f07..d62980d0e 100644 --- a/packages/restapi/src/lib/user/profile.updateUser.ts +++ b/packages/restapi/src/lib/user/profile.updateUser.ts @@ -1,6 +1,6 @@ import axios from 'axios'; import * as CryptoJS from 'crypto-js'; -import { getUserDID, sign } from '../chat/helpers'; +import { IPGPHelper, PGPHelper, getUserDID } from '../chat/helpers'; import Constants, { ENV } from '../constants'; import { getAPIBaseUrls, @@ -12,7 +12,7 @@ import { get } from './getUser'; import { populateDeprecatedUser } from '../utils/populateIUser'; import PROGRESSHOOK from '../progressHook'; -type ProfileUpdateProps = { +export type ProfileUpdateProps = { /** * PGP Private Key */ @@ -39,6 +39,13 @@ type ProfileUpdateProps = { */ export const profileUpdate = async ( options: ProfileUpdateProps +): Promise => { + return profileUpdateCore(options, PGPHelper); +}; + +export const profileUpdateCore = async ( + options: ProfileUpdateProps, + pgpHelper: IPGPHelper ): Promise => { const { pgpPrivateKey, @@ -85,7 +92,7 @@ export const profileUpdate = async ( blockedUsersList: profile.blockedUsersList ? blockedUsersList : [], }; const hash = CryptoJS.SHA256(JSON.stringify(updatedProfile)).toString(); - const signature = await sign({ + const signature = await pgpHelper.sign({ message: hash, signingKey: pgpPrivateKey, }); diff --git a/workspace.json b/workspace.json index 163b6ba91..8f790ddab 100644 --- a/workspace.json +++ b/workspace.json @@ -5,7 +5,6 @@ "demonative": "apps/demonative", "examples-sdk-frontend-react": "packages/examples/sdk-frontend-react", "ledgerlive": "packages/ledgerlive", - "reactnative": "packages/reactnative", "restapi": "packages/restapi", "socket": "packages/socket", "uiembed": "packages/uiembed",