diff --git a/.bundle/config b/.bundle/config new file mode 100644 index 0000000000..848943bb52 --- /dev/null +++ b/.bundle/config @@ -0,0 +1,2 @@ +BUNDLE_PATH: "vendor/bundle" +BUNDLE_FORCE_RUBY_PLATFORM: 1 diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000000..481f5d7a1b --- /dev/null +++ b/.eslintignore @@ -0,0 +1,10 @@ +example/ +dist/ +images/ +ios/ +android/ +assets/ +.vscode/ +.github/ +/.eslintrc.js +/metro.config.js diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 0000000000..97110ef76c --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,61 @@ +module.exports = { + root: true, + extends: '@react-native', + plugins: ['import'], + rules: { + // disabled rules + 'prettier/prettier': 'off', + 'react-native/no-inline-styles': 'off', + 'no-fallthrough': 'off', + curly: 'off', + // error rules + semi: 'error', + 'key-spacing': [2, { beforeColon: false, afterColon: true }], + 'require-await': 'error', + indent: [ + 'error', + 2, + { + ignoredNodes: ['TemplateLiteral'], // https://github.com/babel/babel-eslint/issues/681#issuecomment-451336031 + SwitchCase: 1, + }, + ], + 'no-console': 'error', + 'no-debugger': 'error', + 'prefer-const': 'error', + 'no-multiple-empty-lines': 'error', + 'no-unused-vars': 'error', + 'no-trailing-spaces': 'error', + 'brace-style': ['error', '1tbs', { allowSingleLine: true }], + 'react/jsx-boolean-value': 'error', + 'react/jsx-closing-bracket-location': 'error', + 'react/jsx-max-props-per-line': ['error', { maximum: 1, when: 'multiline' }], + 'max-len': [ + 'error', + { + code: 120, + ignoreTemplateLiterals: true, + // FIXME: doesn't work :/ + ignorePattern: '^log\\(', // ignore "log('...')" + ignoreUrls: true, // ignore long urls + }, + ], + 'import/no-unresolved': ['error', { commonjs: true, amd: true }], + 'import/named': 'error', + 'import/namespace': 'error', + 'import/default': 'error', + 'import/export': 'error', + }, + settings: { + 'import/ignore': ['node_modules/react-native/index\\.js$'], // https://github.com/facebook/react-native/issues/28549 + 'import/resolver': { + node: { + extensions: ['.js', '.ts', '.tsx', '.android.js', '.ios.js', '.android.tsx', '.ios.tsx'], + }, + }, + }, + globals: { + WebSocket: true, + URLSearchParams: true, + }, +}; diff --git a/.flowconfig b/.flowconfig deleted file mode 100644 index 66b57e0969..0000000000 --- a/.flowconfig +++ /dev/null @@ -1,89 +0,0 @@ -[ignore] - -# We fork some components by platform. -.*/*.web.js -.*/*.android.js - -# Some modules have their own node_modules with overlap -.*/node_modules/node-haste/.* - -# Ugh -.*/node_modules/babel.* -.*/node_modules/babylon.* -.*/node_modules/invariant.* - -# Ignore react and fbjs where there are overlaps, but don't ignore -# anything that react-native relies on -.*/node_modules/fbjs/lib/Map.js -.*/node_modules/fbjs/lib/fetch.js -.*/node_modules/fbjs/lib/ExecutionEnvironment.js -.*/node_modules/fbjs/lib/ErrorUtils.js - -# Flow has a built-in definition for the 'react' module which we prefer to use -# over the currently-untyped source -.*/node_modules/react/react.js -.*/node_modules/react/lib/React.js -.*/node_modules/react/lib/ReactDOM.js - -.*/__mocks__/.* -.*/__tests__/.* - -.*/commoner/test/source/widget/share.js - -# Ignore commoner tests -.*/node_modules/commoner/test/.* - -# See https://github.com/facebook/flow/issues/442 -.*/react-tools/node_modules/commoner/lib/reader.js - -# Ignore jest -.*/node_modules/jest-cli/.* - -# Ignore Website -.*/website/.* - -.*/node_modules/is-my-json-valid/test/.*\.json -.*/node_modules/iconv-lite/encodings/tables/.*\.json -.*/node_modules/y18n/test/.*\.json -.*/node_modules/spdx-license-ids/spdx-license-ids.json -.*/node_modules/spdx-exceptions/index.json -.*/node_modules/resolve/test/subdirs/node_modules/a/b/c/x.json -.*/node_modules/resolve/lib/core.json -.*/node_modules/jsonparse/samplejson/.*\.json -.*/node_modules/json5/test/.*\.json -.*/node_modules/ua-parser-js/test/.*\.json -.*/node_modules/builtin-modules/builtin-modules.json -.*/node_modules/binary-extensions/binary-extensions.json -.*/node_modules/url-regex/tlds.json -.*/node_modules/joi/.*\.json -.*/node_modules/isemail/.*\.json -.*/node_modules/tr46/.*\.json - -[include] - -[libs] -node_modules/react-native/Libraries/react-native/react-native-interface.js -node_modules/react-native/flow -flow/ - -[options] -module.system=haste - -esproposal.class_static_fields=enable -esproposal.class_instance_fields=enable - -munge_underscores=true - -module.name_mapper='^image![a-zA-Z0-9$_-]+$' -> 'GlobalImageStub' -module.name_mapper='^[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\)$' -> 'RelativeImageStub' - -suppress_type=$FlowIssue -suppress_type=$FlowFixMe -suppress_type=$FixMe - -suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(>=0\\.\\(2[0-2]\\|1[0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\) -suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(>=0\\.\\(2[0-2]\\|1[0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)?:? #[0-9]+ -suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy - -[version] -0.22.0 diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000000..60bf4dd094 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,37 @@ +--- +name: Bug report +about: Create a report to help us improve +title: '' +labels: '' +assignees: '' + +--- + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behavior: +1. Add prop `someProp="someValue"` +2. call `cameraRef.current.capture()` +3. See error in console + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If the issue is a visual glitch or UI issue please provide screen shots. + +**Desktop (please complete the following information):** + - OS: [e.g. iOS] + - Browser [e.g. chrome, safari] + - Version [e.g. 22] + +**Smartphone (please complete the following information):** + - Device: [e.g. iPhone6] + - OS: [e.g. iOS8.1] + - Browser [e.g. stock browser, safari] + - Version [e.g. 22] + +**Additional context** +Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 0000000000..bbcbbe7d61 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,20 @@ +--- +name: Feature request +about: Suggest an idea for this project +title: '' +labels: '' +assignees: '' + +--- + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here. diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 0000000000..7a37d25945 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,15 @@ +## Summary + + + +## How did you test this change? + + diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000000..782ca28975 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,41 @@ +name: Build +run-name: βš™οΈ Build examples on ${{ github.event_name == 'pull_request' && 'PR' || '🌱' }} ${{ github.event_name == 'pull_request' && github.event.number || github.ref_name }} + +on: + push: + branches: + - main + pull_request: + types: [opened, synchronize, reopened] + +jobs: + build-example-ios: + name: build-example-ios + runs-on: macos-latest + steps: + - name: Set up Ruby + uses: ruby/setup-ruby@v1 + with: + ruby-version: '2.7.4' + - name: Checkout + uses: actions/checkout@v3 + - name: Install modules + run: yarn + - name: Install example + run: yarn bootstrap + - name: Build + run: cd example/ios && xcodebuild -workspace CameraKitExample.xcworkspace -configuration Debug -scheme CameraKitExample -sdk iphoneos build CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO + build-example-android: + name: build-example-android + runs-on: ubuntu-latest # using linux runner for speed + steps: + - name: Checkout + uses: actions/checkout@v3 + - name: Validate Gradle Wrapper + uses: gradle/wrapper-validation-action@v1 + - name: Install modules + run: yarn + - name: Install example + run: yarn bootstrap-linux + - name: Build + run: cd example/android && ./gradlew assembleDebug diff --git a/.github/workflows/linter.yml b/.github/workflows/linter.yml new file mode 100644 index 0000000000..5fd53a991c --- /dev/null +++ b/.github/workflows/linter.yml @@ -0,0 +1,49 @@ +name: Linter +run-name: 🩺 Code checks on ${{ github.event_name == 'pull_request' && 'PR' || '🌱' }} ${{ github.event_name == 'pull_request' && github.event.number || github.ref_name }} + +on: + push: + branches: + - main + pull_request: + types: [opened, synchronize, reopened] + +jobs: + eslint: + name: ESLint + runs-on: ubuntu-latest # using linux runner for speed + steps: + - name: Checkout + uses: actions/checkout@v3 + - name: Install modules + run: yarn + - name: Install example + run: yarn bootstrap-linux + - name: Lint + run: yarn lint + + ios: + name: Lint iOS + runs-on: macos-latest + + steps: + - name: Checkout + uses: actions/checkout@v3 + with: + fetch-depth: 0 + - name: Install dependencies + run: brew bundle + - name: Run swiftlint + run: | + if [[ "${{ github.event_name }}" == "pull_request" ]]; then + updatedFiles=$(git --no-pager diff --name-only --diff-filter=ACMRT ${{ github.event.pull_request.base.sha }} ${{ github.event.pull_request.head.sha }} -- '*.swift') + + if [[ -z "$updatedFiles" ]]; then + echo "No Swift files changed, skipping linting" + exit 0 + fi + + swiftlint --reporter github-actions-logging -- $updatedFiles + else + swiftlint + fi diff --git a/.gitignore b/.gitignore index 81af72ff62..89ef71aa9d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,176 +1,3 @@ - -############ -# Node -############ -# Logs -logs -*.log -npm-debug.log* -package-lock.json - -# Runtime data -pids -*.pid -*.seed - -# Directory for instrumented libs generated by jscoverage/JSCover -lib-cov - -# Coverage directory used by tools like istanbul -coverage - -# nyc test coverage -.nyc_output - -# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) -.grunt - -# node-waf configuration -.lock-wscript - -# Compiled binary addons (http://nodejs.org/api/addons.html) -build/Release - -# Dependency directories -node_modules -jspm_packages - -# Optional npm cache directory -.npm - -# Optional REPL history -.node_repl_history - -################ -# JetBrains -################ -.idea - -## File-based project format: -*.iws - -## Plugin-specific files: - -# IntelliJ -/out/ - -# mpeltonen/sbt-idea plugin -.idea_modules/ - -# JIRA plugin -atlassian-ide-plugin.xml - -# Crashlytics plugin (for Android Studio and IntelliJ) -com_crashlytics_export_strings.xml -crashlytics.properties -crashlytics-build.properties -fabric.properties - - -############ -# iOS -############ -# Xcode -# -# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore - -## Build generated -ios/build/ -ios/DerivedData/ - -## Various settings -*.pbxuser -!default.pbxuser -*.mode1v3 -!default.mode1v3 -*.mode2v3 -!default.mode2v3 -*.perspectivev3 -!default.perspectivev3 -ios/xcuserdata/ - -## Other -*.moved-aside -*.xcuserstate - -## Obj-C/Swift specific -*.hmap -*.ipa -*.dSYM.zip -*.dSYM - -# CocoaPods -# -# We recommend against adding the Pods directory to your .gitignore. However -# you should judge for yourself, the pros and cons are mentioned at: -# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control -# -ios/Pods/ - -# Carthage -# -# Add this line if you want to avoid checking in source code from Carthage dependencies. -# Carthage/Checkouts - -Carthage/Build - -# fastlane -# -# It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the -# screenshots whenever they are needed. -# For more information about the recommended setup visit: -# https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Gitignore.md - -fastlane/report.xml -fastlane/screenshots - - -############ -# Android -############ -# Built application files -*.apk -*.ap_ - -# Files for the Dalvik VM -*.dex - -# Java class files -*.class - -# Generated files -android/bin/ -android/gen/ -android/out/ - -# Gradle files -android/.gradle/ -android/build/ - -# Local configuration file (sdk path, etc) -local.properties - -# Proguard folder generated by Eclipse -android/proguard/ - -# Log Files -*.log - -# Android Studio Navigation editor temp files -android/.navigation/ - -# Android Studio captures folder -android/captures/ - -# Intellij -*.iml - -# Keystore files -*.jks - -################## -# React-Native -################## # OSX # .DS_Store @@ -193,21 +20,72 @@ DerivedData *.hmap *.ipa *.xcuserstate -project.xcworkspace +**/.xcode.env.local -# Android/IJ +# Android/IntelliJ # +build/ .idea .gradle local.properties +*.iml +*.hprof +.cxx/ +*.keystore +!debug.keystore # node.js # node_modules/ npm-debug.log +yarn-error.log + +# fastlane +# +# It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the +# screenshots whenever they are needed. +# For more information about the recommended setup visit: +# https://docs.fastlane.tools/best-practices/source-control/ + +**/fastlane/report.xml +**/fastlane/Preview.html +**/fastlane/screenshots +**/fastlane/test_output + +# Bundle artifact +*.jsbundle + +# Ruby / CocoaPods +**/Pods/ +/vendor/bundle/ + +# Temporary files created by Metro to check the health of the file watcher +.metro-health-check* + +# testing +/coverage -# BUCK -buck-out/ -\.buckd/ -android/app/libs -android/keystores/debug.keystore +# Yarn +.yarn/* +!.yarn/patches +!.yarn/plugins +!.yarn/releases +!.yarn/sdks +!.yarn/versions + +# Project specific + +example/.yarn/* +!example/.yarn/patches +!example/.yarn/plugins +!example/.yarn/releases +!example/.yarn/sdks +!example/.yarn/versions + +ios/build/ +ios/DerivedData/ +dist/ +### Xcode ### +*.xcodeproj/* +!*.xcodeproj/project.pbxproj +!*.xcworkspace/contents.xcworkspacedata diff --git a/.npmignore b/.npmignore index 7725d8967d..94d5d567b7 100644 --- a/.npmignore +++ b/.npmignore @@ -7,3 +7,5 @@ example-android/ android/build/ img/ ios/lib/DerivedData/ +images/ +docs/ diff --git a/.prettierrc.js b/.prettierrc.js new file mode 100644 index 0000000000..a4abc02e25 --- /dev/null +++ b/.prettierrc.js @@ -0,0 +1,13 @@ +module.exports = { + arrowParens: 'always', + bracketSameLine: true, + tabs: false, + tabWidth: 2, + bracketSpacing: true, + singleQuote: true, + trailingComma: 'all', + printWidth: 120, + semi: true, + jsxBracketSameLine: false, + jsxSingleQuote: false, +}; diff --git a/.swiftlint.yml b/.swiftlint.yml new file mode 100644 index 0000000000..4eaa1b3001 --- /dev/null +++ b/.swiftlint.yml @@ -0,0 +1,21 @@ +included: + - ios + - example/ios + +excluded: + - ios/Pods + - example/ios/Pods + +disabled_rules: + - todo + +line_length: 160 +type_body_length: 400 +function_body_length: 50 + +identifier_name: + excluded: + - on + - x + - y + - at diff --git a/Brewfile b/Brewfile new file mode 100644 index 0000000000..4d9396ec1b --- /dev/null +++ b/Brewfile @@ -0,0 +1,2 @@ +brew 'swiftlint' + diff --git a/Brewfile.lock.json b/Brewfile.lock.json new file mode 100644 index 0000000000..5943b20df8 --- /dev/null +++ b/Brewfile.lock.json @@ -0,0 +1,62 @@ +{ + "entries": { + "brew": { + "swiftlint": { + "version": "0.53.0", + "bottle": { + "rebuild": 0, + "root_url": "https://ghcr.io/v2/homebrew/core", + "files": { + "arm64_sonoma": { + "cellar": ":any_skip_relocation", + "url": "https://ghcr.io/v2/homebrew/core/swiftlint/blobs/sha256:240ccda9de55d948d0c635798079074099bfcb73ffda41428900fdc748aeea7b", + "sha256": "240ccda9de55d948d0c635798079074099bfcb73ffda41428900fdc748aeea7b" + }, + "arm64_ventura": { + "cellar": ":any_skip_relocation", + "url": "https://ghcr.io/v2/homebrew/core/swiftlint/blobs/sha256:7b7ceb7896c6833965cc4eac9001255d8adde6c5432045d5a8ab6aea8a9e81d9", + "sha256": "7b7ceb7896c6833965cc4eac9001255d8adde6c5432045d5a8ab6aea8a9e81d9" + }, + "arm64_monterey": { + "cellar": ":any_skip_relocation", + "url": "https://ghcr.io/v2/homebrew/core/swiftlint/blobs/sha256:78c2a4c3f4a2f6847b484527b0f0f916da71e3ee29e49890fd44b63fe7b38e26", + "sha256": "78c2a4c3f4a2f6847b484527b0f0f916da71e3ee29e49890fd44b63fe7b38e26" + }, + "sonoma": { + "cellar": ":any_skip_relocation", + "url": "https://ghcr.io/v2/homebrew/core/swiftlint/blobs/sha256:abdca78dd8a8bd268053b3be195fe891bb74aef5502ab3a6b871ae0c6bb04540", + "sha256": "abdca78dd8a8bd268053b3be195fe891bb74aef5502ab3a6b871ae0c6bb04540" + }, + "ventura": { + "cellar": ":any_skip_relocation", + "url": "https://ghcr.io/v2/homebrew/core/swiftlint/blobs/sha256:be711c707bf3b49fa0dd6e2ae576b309aad620f9b56a2c6e7b1ac5cf35cf652a", + "sha256": "be711c707bf3b49fa0dd6e2ae576b309aad620f9b56a2c6e7b1ac5cf35cf652a" + }, + "monterey": { + "cellar": ":any_skip_relocation", + "url": "https://ghcr.io/v2/homebrew/core/swiftlint/blobs/sha256:13487d68a971dbe035019364e19d70641af2a18c06e52925d238685b384a7979", + "sha256": "13487d68a971dbe035019364e19d70641af2a18c06e52925d238685b384a7979" + }, + "x86_64_linux": { + "cellar": "/home/linuxbrew/.linuxbrew/Cellar", + "url": "https://ghcr.io/v2/homebrew/core/swiftlint/blobs/sha256:fbbc56fccfcfcd34564feb7325567e2ff3638d3c609396a5c4aa13311c7b26e0", + "sha256": "fbbc56fccfcfcd34564feb7325567e2ff3638d3c609396a5c4aa13311c7b26e0" + } + } + } + } + } + }, + "system": { + "macos": { + "sonoma": { + "HOMEBREW_VERSION": "4.2.0-54-g0b804d4", + "HOMEBREW_PREFIX": "/opt/homebrew", + "Homebrew/homebrew-core": "api", + "CLT": "15.1.0.0.1.1700200546", + "Xcode": "15.0", + "macOS": "14.1" + } + } + } +} diff --git a/LICENSE b/LICENSE index 85e970c11c..d13cc4b26a 100644 --- a/LICENSE +++ b/LICENSE @@ -1,7 +1,5 @@ The MIT License (MIT) -Copyright (c) 2014 Wix.com - Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights diff --git a/README.md b/README.md index 045668f65a..2185f27c82 100644 --- a/README.md +++ b/README.md @@ -1,105 +1,253 @@ +

+ 🎈 React Native Camera Kit +

+ +

+ A high performance, easy to use, rock solid
+ camera library for React Native apps. +

+ +

+ + React Native Camera Kit is released under the MIT license. + + + Current npm package version. + +

+ + + + + +
+ + +
    +
  • Cross Platform (iOS and Android)

  • +
  • Optimized for performance and high photo capture rate

  • +
  • QR / Barcode scanning support

  • +
  • Camera preview support in iOS simulator

  • +
+
+ +## Installation (RN > 0.60) -# react-native-camera-kit +```bash +yarn add react-native-camera-kit +``` -Native camera control. +```bash +cd ios && pod install && cd .. +``` -![](img/crazyUnicorn.png) ![](img/zoom.png) +Android: +[Review your Kotlin configuration](./docs/kotlin.md) to ensure it's compatible with this library. -## Installation +## Permissions +You must use a separate library for prompting the user for permissions before rendering the `` component. +We recommend zoontek's library, react-native-permissions: +https://github.com/zoontek/react-native-permissions#ios-flow -#### Install using npm or yarn: +**If you fail to prompt for permission, the camera will appear blank / black.** -```bash -npm install react-native-camera-kit --save -``` +### Why no permissions API? -Or if you're using yarn: +Conceptually, permissions are simple: Granted / Denied. +However, in reality it's not that simple due to privacy enhancements on iOS and Android. -```bash -yarn add react-native-camera-kit -``` +[Here's an example diagram from react-native-permissions's README](https://github.com/zoontek/react-native-permissions#ios-flow), which illustrates the complexity of the user-experience, which we don't want to duplicate in a camera library: -#### iOS +``` + ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ + ┃ check(PERMISSIONS.IOS.CAMERA) ┃ + ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ + β”‚ + Is the feature available + on this deviceΒ ? + β”‚ ╔════╗ + β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β•‘ NO ║──────────────┐ + β”‚ β•šβ•β•β•β•β• β”‚ + ╔═════╗ β–Ό + β•‘ YES β•‘ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” + β•šβ•β•β•β•β•β• β”‚ RESULTS.UNAVAILABLE β”‚ + β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + Is the permission + requestableΒ ? + β”‚ ╔════╗ + β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β•‘ NO ║──────────────┐ + β”‚ β•šβ•β•β•β•β• β”‚ + ╔═════╗ β–Ό + β•‘ YES β•‘ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” + β•šβ•β•β•β•β•β• β”‚ RESULTS.BLOCKED / β”‚ + β”‚ β”‚ RESULTS.LIMITED / β”‚ + β”‚ β”‚ RESULTS.GRANTED β”‚ + β–Ό β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” + β”‚ RESULTS.DENIED β”‚ + β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + β”‚ + β–Ό + ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ + ┃ request(PERMISSIONS.IOS.CAMERA) ┃ + ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ + β”‚ + Does the user accept + the requestΒ ? + β”‚ ╔════╗ + β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β•‘ NO ║──────────────┐ + β”‚ β•šβ•β•β•β•β• β”‚ + ╔═════╗ β–Ό + β•‘ YES β•‘ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” + β•šβ•β•β•β•β•β• β”‚ RESULTS.BLOCKED β”‚ + β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + β–Ό + β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” + β”‚ RESULTS.GRANTED β”‚ + β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ +``` -- Locate the module lib folder in your node modules: `PROJECT_DIR/node_modules/react-native-camera-kit/ios/lib` -- Drag the `ReactNativeCameraKit.xcodeproj` project file into your project -- Add `libReactNativeCameraKit.a` to all your target **Linked Frameworks and Libraries** (prone to be forgotten) -- Add to your project ```info.plist``` the keys ```Privacy - Camera Usage Description``` and ```Privacy - Photo Library Usage Description``` as described [here](https://developer.apple.com/library/content/documentation/General/Reference/InfoPlistKeyReference/Articles/CocoaKeys.html). +In earlier versions of react-native-camera-kit, permissions were provided with an API, but for the above reasons, these APIs will be removed. #### Android -Add the following to your project's `settings.gradle` file: - +Add the following uses-permission to your `AndroidManifest.xml` (usually found at: `android/src/main/`) -```diff -+ include ':rncamerakit' -+ project(':rncamerakit').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-camera-kit/android/') +```java + + ``` -Then add to your app `app/build.gradle` in the `dependencies` section: +#### iOS -```diff -+ compile project(":rncamerakit") -``` +Add the following usage descriptions to your `Info.plist` (usually found at: `ios/PROJECT_NAME/`) -Then in `MainApplication.java` add: +```xml +NSCameraUsageDescription +For taking photos -```diff -+ import com.wix.RNCameraKit.RNCameraKitPackage; +NSPhotoLibraryUsageDescription +For saving photos ``` -And in the package list in the same file (e.g. `getPackages`) add: +## Running the example project -```diff -+ new RNCameraKitPackage() +- `yarn bootstrap` +- `yarn example ios` or `yarn example android` + +## Components + +### Camera + +Barebones camera component if you need advanced/customized interface + +```ts +import { Camera, CameraType } from 'react-native-camera-kit'; ``` -## Running the example project - -- ```cd old-example``` -- ```yarn``` or ```npm install``` (the ```yarn```/```npm``` should be in the example folder) -- ```react-native run-ios``` or ```react-native run-android``` - -## APIs - -### CameraKitCamera - Camera component - -```js - this.camera = cam} - style={{ - flex: 1, - backgroundColor: 'white' - }} - cameraOptions={{ - flashMode: 'auto', // on/off/auto(default) - focusMode: 'on', // off/on(default) - zoomMode: 'on', // off/on(default) - ratioOverlay:'1:1', // optional, ratio overlay on the camera and crop the image seamlessly - ratioOverlayColor: '#00000077' // optional - }} - onReadQRCode={(event) => console.log(event.nativeEvent.qrcodeStringValue)} // optional - +```tsx + (this.camera = ref)} + cameraType={CameraType.Back} // front/back(default) + flashMode="auto" /> ``` -### CameraKitCamera cameraOptions +#### Barcode / QR Code Scanning -Attribute | Values | Description ------------------ | ---------------------- | ----------- -`flashMode` |`'on'`/`'off'`/`'auto'` | camera flash mode (default is `auto`) -`focusMode` | `'on'`/`'off'` | camera focus mode (default is `on`) -`zoomMode` | `'on'`/`'off'` | camera zoom mode -`ratioOverlay` | `['int':'int', ...]` | overlay on top of the camera view (crop the image to the selected size) Example: `['16:9', '1:1', '3:4']` -`ratioOverlayColor` | Color | any color with alpha (default is ```'#ffffff77'```) +Additionally, the Camera can be used for barcode scanning -### CameraKitCamera API +```tsx + Alert.alert('QR code found')} // optional + showFrame={true} // (default false) optional, show frame with transparent layer (qr code or barcode will be read on this area ONLY), start animation for scanner, that stops when a code has been found. Frame always at center of the screen + laserColor='red' // (default red) optional, color of laser in scanner frame + frameColor='white' // (default white) optional, color of border of scanner frame +/> +``` + +### Camera Props (Optional) + +| Props | Type | Description | +| ------------------------------ | -------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `ref` | Ref | Reference on the camera view | +| `style` | StyleProp\ | Style to apply on the camera view | +| `flashMode` | `'on'`/`'off'`/`'auto'` | Camera flash mode. Default: `auto` | +| `focusMode` | `'on'`/`'off'` | Camera focus mode. Default: `on` | +| `zoomMode` | `'on'`/`'off'` | Enable the pinch to zoom gesture. Default: `on` | +| `zoom` | `number` | Control the zoom. Default: `1.0` | +| `maxZoom` | `number` | Maximum zoom allowed (but not beyond what camera allows). Default: `undefined` (camera default max) | +| `onZoom` | Function | Callback when user makes a pinch gesture, regardless of what the `zoom` prop was set to. Returned event contains `zoom`. Ex: `onZoom={(e) => console.log(e.nativeEvent.zoom)}`. | +| `torchMode` | `'on'`/`'off'` | Toggle flash light when camera is active. Default: `off` | +| `cameraType` | CameraType.Back/CameraType.Front | Choose what camera to use. Default: `CameraType.Back` | +| `onOrientationChange` | Function | Callback when physical device orientation changes. Returned event contains `orientation`. Ex: `onOrientationChange={(event) => console.log(event.nativeEvent.orientation)}`. Use `import { Orientation } from 'react-native-camera-kit'; if (event.nativeEvent.orientation === Orientation.PORTRAIT) { ... }` to understand the new value | +| **Android only** | +| `onError` | Function | Android only. Callback when camera fails to initialize. Ex: `onError={(e) => console.log(e.nativeEvent.errorMessage)}`. | +| `shutterPhotoSound` | `boolean` | Android only. Enable or disable the shutter sound when capturing a photo. Default: `true` | +| **iOS only** | +| `ratioOverlay` | `'int:int'` | Show a guiding overlay in the camera preview for the selected ratio. Does not crop image as of v9.0. Example: `'16:9'` | +| `ratioOverlayColor` | Color | Any color with alpha. Default: `'#ffffff77'` | +| `resetFocusTimeout` | `number` | Dismiss tap to focus after this many milliseconds. Default `0` (disabled). Example: `5000` is 5 seconds. | +| `resetFocusWhenMotionDetected` | Boolean | Dismiss tap to focus when focus area content changes. Native iOS feature, see documentation: https://developer.apple.com/documentation/avfoundation/avcapturedevice/1624644-subjectareachangemonitoringenabl?language=objc). Default `true`. | +| `resizeMode` | `'cover' / 'contain'` | Determines the scaling and cropping behavior of content within the view. `cover` (resizeAspectFill on iOS) scales the content to fill the view completely, potentially cropping content if its aspect ratio differs from the view. `contain` (resizeAspect on iOS) scales the content to fit within the view's bounds without cropping, ensuring all content is visible but may introduce letterboxing. Default behavior depends on the specific use case. | +| `scanThrottleDelay` | `number` | Duration between scan detection in milliseconds. Default 2000 (2s) | +| `maxPhotoQualityPrioritization` | `'balanced'` / `'quality'` / `'speed'` | [iOS 13 and newer](https://developer.apple.com/documentation/avfoundation/avcapturephotooutput/3182995-maxphotoqualityprioritization). `'speed'` provides a 60-80% median capture time reduction vs 'quality' setting. Tested on iPhone 6S Max (66% faster) and iPhone 15 Pro Max (76% faster!). Default `balanced` | +| `onCaptureButtonPressIn` | Function | Callback when iPhone capture button is pressed in. Ex: `onCaptureButtonPressIn={() => console.log("volume button pressed in")}` | +| `onCaptureButtonPressOut` | Function | Callback when iPhone capture button is released. Ex: `onCaptureButtonPressOut={() => console.log("volume button released")}` | +| **Barcode only** | +| `scanBarcode` | `boolean` | Enable barcode scanner. Default: `false` | +| `showFrame` | `boolean` | Show frame in barcode scanner. Default: `false` | +| `laserColor` | Color | Color of barcode scanner laser visualization. Default: `red` | +| `frameColor` | Color | Color of barcode scanner frame visualization. Default: `yellow` | +| `onReadCode` | Function | Callback when scanner successfully reads barcode. Returned event contains `codeStringValue`. Default: `null`. Ex: `onReadCode={(event) => console.log(event.nativeEvent.codeStringValue)}` | + +### Imperative API + +_Note: Must be called on a valid camera ref_ + +#### capture() + +Capture image as JPEG. + +A temporary file is created. You _must_ move this file to a permanent location (e.g. the app's 'Documents' folder) if you need it beyond the current session of the app as it may be deleted when the user leaves the app. You can move files by using a file system library such as [react-native-fs](https://github.com/itinance/react-native-fs) or [expo-filesystem](https://docs.expo.io/versions/latest/sdk/filesystem/). +(On Android we currently have an unsupported `outputPath` prop but it's subject to change at any time). + +Note that the reason you're getting a URL despite it being a file is because Android 10+ encourages URIs. To keep things consistent regardless of settings or platform we always send back a URI. + +```ts +const { uri } = await this.camera.capture(); +// uri = 'file:///data/user/0/com.myorg.myapp/cache/ckcap123123123123.jpg' +``` + +If you want to store it permanently, here's an example using [react-native-fs](https://github.com/itinance/react-native-fs): + +```ts +import RNFS from 'react-native-fs'; +// [...] +let { uri } = await this.camera.capture(); +if (uri.startsWith('file://')) { + // Platform dependent, iOS & Android uses '/' + const pathSplitter = '/'; + // file:///foo/bar.jpg => /foo/bar.jpg + const filePath = uri.replace('file://', ''); + // /foo/bar.jpg => [foo, bar.jpg] + const pathSegments = filePath.split(pathSplitter); + // [foo, bar.jpg] => bar.jpg + const fileName = pathSegments[pathSegments.length - 1]; + + await RNFS.moveFile(filePath, `${RNFS.DocumentDirectoryPath}/${fileName}`); + uri = `file://${destFilePath}`; +} +``` -#### checkDeviceCameraAuthorizationStatus +#### checkDeviceCameraAuthorizationStatus (**iOS only**) -```js -const isCameraAuthorized = await CameraKitCamera.checkDeviceCameraAuthorizationStatus(); +```ts +const isCameraAuthorized = await Camera.checkDeviceCameraAuthorizationStatus(); ``` return values: @@ -108,141 +256,29 @@ return values: `AVAuthorizationStatusNotDetermined` returns `-1` -otherwise, returns ```false``` +otherwise, returns `false` -#### requestDeviceCameraAuthorization +#### requestDeviceCameraAuthorization (**iOS only**) -```js -const isUserAuthorizedCamera = await CameraKitCamera.requestDeviceCameraAuthorization(); +```ts +const isUserAuthorizedCamera = await Camera.requestDeviceCameraAuthorization(); ``` `AVAuthorizationStatusAuthorized` returns `true` otherwise, returns `false` -#### capture - must have the wanted camera capture reference - -Capture image (`shouldSaveToCameraRoll: boolean`) - -```js -const image = await this.camera.capture(true); -``` - -#### setFlashMode - must have the wanted camera capture reference +## Using with Expo -Set flash mode (`auto`/`on`/`off`) +If you are using Expo Managed Workflow, you can use this library with a third-party plugin `expo-react-native-camera-kit`. -```js -const success = await this.camera.setFlashMode(newFlashData.mode); -``` - -#### changeCamera - must have the wanted camera capture reference - -Change to fornt/rear camera - -```js -const success = await this.camera.changeCamera(); -``` - - -### CameraKitGalleryView - Gallery grid component - -Native Gallery View (based on `UICollectionView`(iOS) and ` RecyclerView` (Android)) - -![](img/camerakitgalleryview.png) - -```js - this.gallery = gallery} - style={{flex: 1, marginTop: 20}} - minimumInteritemSpacing={10} - minimumLineSpacing={10} - albumName={} - columnCount={3} - onTapImage={event => { - // event.nativeEvent.selected - ALL selected images ids - }} - selectedImages={} - selectedImageIcon={require(''))} - unSelectedImageIcon={require('')} -/> -``` - -Attribute | Values | Description --------- | ----- | ------------ -`minimumInteritemSpacing` | Float | Minimum inner Item spacing -`minimumLineSpacing` | Float | Minimum line spacing -`imageStrokeColor` | Color | Image stroke color -`imageStrokeColorWidth` | Number > 0 | Image stroke color width -`albumName` | String | Album name to show -`columnCount` | Integer | How many clumns in one row -`onTapImage` | Function | Callback when image tapped -`selectedImages` | Array | Selected images (will show the selected badge) -`selectedImageIcon` | `require(_PATH_)` | - _DEPRECATED_ use Selection - Selected image badge image -`unSelectedImageIcon` | `require(_PATH_)` | - _DEPRECATED_ use Selection - Unselected image badge image -`selection` | Object | See [Selection section](#selection) -`getUrlOnTapImage` | Boolean | iOS only - On image tap return the image internal (tmp folder) uri (intead of `Photos.framework` asset id) -`customButtonStyle` | Object | See [Custom Button](#custom-button) section -`onCustomButtonPress` | Function | Callback when custom button tapped -`contentInset` (iOS) | Object | The amount by which the gellery view content is inset from its edges (similar to `ScrollView` contentInset) -`remoteDownloadIndicatorType` | String (`'spinner'` / `'progress-bar'` / `'progress-pie'`) | iOS only - see [Images stored in iCloud](#images-stored-in-iCloud) -`remoteDownloadIndicatorColor` | Color | iOS only - Color of the remote download indicator to show -`onRemoteDownloadChanged` | Function | iOS only - Callback when the device curentlly download remote image stored in the iCloud. - -#### Custom Button - -Attribute | Values | Description --------- | ----- | ------------ -`image` | `require(_PATH_)` | Custom button image -`backgroundColor` | Color | Custom button background color - -#### Selection - -Attribute | Values | Description --------- | ----- | ------------ -`selectedImage` |`require(_PATH_)`|Selected image badge image -`unselectedImage` |`require(_PATH_)`|Unselected image badge image -`imagePosition` |`bottom/top-right/left` / `center`| Selected/Unselected badge image position (Default:`top-right`) -`overlayColor` |Color| Image selected overlay color -`imageSizeAndroid` |`large`/`medium`| Android Only - Selected badge image size - -#### Images stored in iCloud -On iOS images can be stored in iCould if the device is **low on space** which means full-resolution photos automatically replaced with optimized version and full resolution versions are stored in iCloud. - -In this case, we need to download the image from iCloud and *Photos Framework* by Apple does a great job. Downloading take time and we deal with UI, so we need to show loading/progress indicator. -In order to do so, we provide 3 types of loading/progress inidcators: - -Sets `remoteDownloadIndicatorType` prop (and `remoteDownloadIndicatorColor` in order to sets the Color) on CameraKitGalleryView: - -Attribute | Values --------- | :-----: - `'spinner'` | ![](img/spinner.png) - `'progress-bar'`| ![](img/progressBar.png) - `'progress-pie'`| ![](img/pie.png) - - >In order to simulate this loading behaviour, since reach low on storage situation is hard, add this prop `iCloudDownloadSimulateTime={TIME_IN_SECONDS}`, just **DO NOT FORGET TO REMOVE IT**. - -## QR Code -```js - this.onBottomButtonPressed(event)} - scanBarcode={true} - laserColor={"blue"} - frameColor={"yellow"} - - onReadQRCode={((event) => Alert.alert("Qr code found"))} //optional - hideControls={false} //(default false) optional, hide buttons and additional controls on top and bottom of screen - showFrame={true} //(default false) optional, show frame with transparent layer (qr code or barcode will be read on this area ONLY), start animation for scanner,that stoped when find any code. Frame always at center of the screen - offsetForScannerFrame = {10} //(default 30) optional, offset from left and right side of the screen - heightForScannerFrame = {300} //(default 200) optional, change height of the scanner frame - colorForScannerFrame = {'red'} //(default white) optional, change colot of the scanner frame -/> -``` +[See more here](https://github.com/avantstay/expo-react-native-camera-kit) -## Credits +## Contributing -* [M13ProgressSuite](https://github.com/Marxon13/M13ProgressSuite) component by Marxon13 - A suite containing many tools to display progress information on iOS. +- Pull Requests are welcome, if you open a pull request we will do our best to get to it in a timely manner +- Pull Request Reviews are even more welcome! we need help testing, reviewing, and updating open PRs +- If you are interested in contributing more actively, please contact us. ## License diff --git a/ReactNativeCameraKit.podspec b/ReactNativeCameraKit.podspec new file mode 100644 index 0000000000..c7f5bf6732 --- /dev/null +++ b/ReactNativeCameraKit.podspec @@ -0,0 +1,34 @@ +require 'json' + +package = JSON.parse(File.read(File.join(__dir__, 'package.json'))) + +Pod::Spec.new do |s| + s.name = "ReactNativeCameraKit" + s.version = package["version"] + s.summary = "A high performance, easy to use camera API" + s.license = "MIT" + + s.authors = "CameraKit" + s.homepage = "https://github.com/teslamotors/react-native-camera-kit" + s.platform = :ios, "11.0" + + s.source = { :git => "https://github.com/teslamotors/react-native-camera-kit.git", :tag => "v#{s.version}" } + s.source_files = "ios/**/*.{h,m,mm,swift}" + s.private_header_files = 'ios/ReactNativeCameraKit/ReactNativeCameraKit-Swift.pre.h' + + if ENV['USE_FRAMEWORKS'] + exisiting_flags = s.attributes_hash["compiler_flags"] + if exisiting_flags.present? + s.compiler_flags = exisiting_flags + "-DCK_USE_FRAMEWORKS=1" + else + s.compiler_flags = "-DCK_USE_FRAMEWORKS=1" + end + end + + if defined?(install_modules_dependencies()) != nil + install_modules_dependencies(s) + else + s.dependency 'React-Core' + end + +end diff --git a/android/build.gradle b/android/build.gradle index a34e8e00b6..38cc502b24 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -1,26 +1,71 @@ apply plugin: 'com.android.library' +apply plugin: 'kotlin-android' -android { - compileSdkVersion 25 - buildToolsVersion '26.0.2' +def isNewArchitectureEnabled() { + // To opt-in for the New Architecture, you can either: + // - Set `newArchEnabled` to true inside the `gradle.properties` file + // - Invoke gradle with `-newArchEnabled=true` + // - Set an environment variable `ORG_GRADLE_PROJECT_newArchEnabled=true` + return project.hasProperty("newArchEnabled") && project.newArchEnabled == "true" +} + +if (isNewArchitectureEnabled()) { + apply plugin: 'com.facebook.react' +} +android { + def agpVersion = com.android.Version.ANDROID_GRADLE_PLUGIN_VERSION + if (agpVersion.tokenize('.')[0].toInteger() >= 7) { + namespace "com.rncamerakit" + } + compileSdkVersion = 34 defaultConfig { - minSdkVersion 16 - targetSdkVersion 25 + minSdkVersion = 24 + // noinspection ExpiredTargetSdkVersion + targetSdkVersion = 34 versionCode 1 versionName "1.0" ndk { - abiFilters "armeabi-v7a", "x86" + abiFilters "arm64-v8a", "x86" } + buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString() } lintOptions { warning 'InvalidPackage' } + + if (!isNewArchitectureEnabled()) { + sourceSets { + main { + java.srcDirs += 'src/paper/java' + } + } + } } dependencies { implementation 'com.facebook.react:react-native:+' - implementation 'com.android.support:recyclerview-v7:25.0.1' - implementation 'com.google.zxing:core:3.3.0' - implementation group: 'com.drewnoakes', name: 'metadata-extractor', version: '2.9.1' + implementation group: 'com.drewnoakes', name: 'metadata-extractor', version: '2.18.0' + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlinVersion" + + // CameraX core library using the camera2 implementation + def camerax_version = "1.1.0" + // The following line is optional, as the core library is included indirectly by camera-camera2 + implementation "androidx.camera:camera-core:${camerax_version}" + implementation "androidx.camera:camera-camera2:${camerax_version}" + // If you want to additionally use the CameraX Lifecycle library + implementation "androidx.camera:camera-lifecycle:${camerax_version}" + // If you want to additionally use the CameraX VideoCapture library + // implementation "androidx.camera:camera-video:${camerax_version}" + // If you want to additionally use the CameraX View class + implementation "androidx.camera:camera-view:${camerax_version}" + // If you want to additionally add CameraX ML Kit Vision Integration + // implementation "androidx.camera:camera-mlkit-vision:${camerax_version}" + // If you want to additionally use the CameraX Extensions library + // implementation "androidx.camera:camera-extensions:${camerax_version}" + + implementation 'com.google.mlkit:barcode-scanning:17.0.2' +} +repositories { + mavenCentral() } diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties index 04e285f340..2ea3535dc0 100644 --- a/android/gradle/wrapper/gradle-wrapper.properties +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,7 @@ -#Mon Dec 28 10:00:20 PST 2015 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-all.zip +networkTimeout=10000 +validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip diff --git a/android/gradlew b/android/gradlew index 9d82f78915..1aa94a4269 100644 --- a/android/gradlew +++ b/android/gradlew @@ -1,74 +1,127 @@ -#!/usr/bin/env bash +#!/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 UN*X -## +# +# 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/HEAD/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/. +# ############################################################################## -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS="" +# 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_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" +MAX_FD=maximum -warn ( ) { +warn () { echo "$*" -} +} >&2 -die ( ) { +die () { echo echo "$*" echo exit 1 -} +} >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; esac -# Attempt to set APP_HOME -# Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi -done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null - 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" + JAVACMD=$JAVA_HOME/jre/sh/java else - JAVACMD="$JAVA_HOME/bin/java" + JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME @@ -77,84 +130,120 @@ 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. + JAVACMD=java + if ! command -v java >/dev/null 2>&1 + then + 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 fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac fi -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -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" ) -# For Cygwin, switch paths to Windows format before running java -if $cygwin ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" + 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 - i=$((i+1)) + # 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 - case $i in - (0) set -- ;; - (1) set -- "$args0" ;; - (2) set -- "$args0" "$args1" ;; - (3) set -- "$args0" "$args1" "$args2" ;; - (4) set -- "$args0" "$args1" "$args2" "$args3" ;; - (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac fi -# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules -function splitJvmOpts() { - JVM_OPTS=("$@") -} -eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS -JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" -exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" +# 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"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# 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/android/gradlew.bat b/android/gradlew.bat index aec99730b4..7101f8e467 100644 --- a/android/gradlew.bat +++ b/android/gradlew.bat @@ -1,4 +1,20 @@ -@if "%DEBUG%" == "" @echo off +@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 @@ -8,26 +24,30 @@ @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal -@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= - set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused 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 init +if %ERRORLEVEL% equ 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. +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail @@ -35,54 +55,36 @@ goto fail set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe -if exist "%JAVA_EXE%" goto init +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. +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail -:init -@rem Get command-line arguments, handling Windowz variants - -if not "%OS%" == "Windows_NT" goto win9xME_args -if "%@eval[2+2]" == "4" goto 4NT_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* -goto execute - -:4NT_args -@rem Get arguments from the 4NT Shell from JP Software -set CMD_LINE_ARGS=%$ - :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 %CMD_LINE_ARGS% +"%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 +if %ERRORLEVEL% equ 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 +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal diff --git a/android/src/main/AndroidManifest.xml b/android/src/main/AndroidManifest.xml index bfa0a77ed0..e99731b3e2 100644 --- a/android/src/main/AndroidManifest.xml +++ b/android/src/main/AndroidManifest.xml @@ -1,5 +1,5 @@ + package="com.rncamerakit"> diff --git a/android/src/main/java/com/rncamerakit/CKCamera.kt b/android/src/main/java/com/rncamerakit/CKCamera.kt new file mode 100644 index 0000000000..d2a2a97668 --- /dev/null +++ b/android/src/main/java/com/rncamerakit/CKCamera.kt @@ -0,0 +1,650 @@ +package com.rncamerakit + +import android.Manifest +import android.animation.Animator +import android.animation.AnimatorListenerAdapter +import android.annotation.SuppressLint +import android.app.Activity +import android.content.Context +import android.content.pm.PackageManager +import android.graphics.Color +import android.hardware.SensorManager +import android.media.AudioManager +import android.media.MediaActionSound +import android.net.Uri +import android.util.DisplayMetrics +import android.util.Log +import android.view.* +import android.widget.FrameLayout +import android.widget.LinearLayout +import androidx.annotation.ColorInt +import androidx.appcompat.app.AppCompatActivity +import androidx.camera.core.* +import androidx.camera.lifecycle.ProcessCameraProvider +import androidx.camera.view.PreviewView +import androidx.core.app.ActivityCompat +import androidx.core.content.ContextCompat +import androidx.lifecycle.LifecycleObserver +import com.facebook.react.bridge.Arguments +import com.facebook.react.bridge.Promise +import com.facebook.react.bridge.WritableMap +import com.facebook.react.uimanager.ThemedReactContext +import com.facebook.react.uimanager.events.RCTEventEmitter +import com.rncamerakit.barcode.BarcodeFrame +import java.io.File +import java.util.* +import java.util.concurrent.ExecutorService +import java.util.concurrent.Executors +import kotlin.math.abs +import kotlin.math.max +import kotlin.math.min +import android.graphics.Canvas +import android.graphics.Paint +import android.graphics.RectF +import com.facebook.react.uimanager.UIManagerHelper +import com.google.mlkit.vision.barcode.common.Barcode +import com.rncamerakit.events.* + +class RectOverlay constructor(context: Context) : + View(context) { + + private val rectBounds: MutableList = mutableListOf() + private val paint = Paint().apply { + style = Paint.Style.STROKE + color = ContextCompat.getColor(context, android.R.color.holo_green_light) + strokeWidth = 5f + } + + override fun onDraw(canvas: Canvas) { + super.onDraw(canvas) + // Pass it a list of RectF (rectBounds) + rectBounds.forEach { canvas.drawRect(it, paint) } + } + + fun drawRectBounds(rectBounds: List) { + this.rectBounds.clear() + this.rectBounds.addAll(rectBounds) + invalidate() + postDelayed({ + this.rectBounds.clear() + invalidate() + }, 1000) + } +} + +@SuppressLint("ViewConstructor") // Extra constructors unused. Not using visual layout tools +class CKCamera(context: ThemedReactContext) : FrameLayout(context), LifecycleObserver { + private val currentContext: ThemedReactContext = context + + private var camera: Camera? = null + private var preview: Preview? = null + private var imageCapture: ImageCapture? = null + private var imageAnalyzer: ImageAnalysis? = null + private var orientationListener: OrientationEventListener? = null + private var viewFinder: PreviewView = PreviewView(context) + private var rectOverlay: RectOverlay = RectOverlay(context) + private var barcodeFrame: BarcodeFrame? = null + private var cameraExecutor: ExecutorService = Executors.newSingleThreadExecutor() + private var cameraProvider: ProcessCameraProvider? = null + private var outputPath: String? = null + private var shutterAnimationDuration: Int = 50 + private var shutterPhotoSound: Boolean = true + private var effectLayer = View(context) + + // Camera Props + private var lensType = CameraSelector.LENS_FACING_BACK + private var autoFocus = "on" + private var zoomMode = "on" + private var lastOnZoom = 0.0 + private var zoom: Double? = null + private var maxZoom: Double? = null + private var zoomStartedAt = 1.0f + private var pinchGestureStartedAt = 0.0f + + // Barcode Props + private var scanBarcode: Boolean = false + private var frameColor = Color.GREEN + private var laserColor = Color.RED + + private fun getActivity() : Activity { + return currentContext.currentActivity!! + } + + init { + viewFinder.layoutParams = LinearLayout.LayoutParams( + LayoutParams.MATCH_PARENT, + LayoutParams.MATCH_PARENT + ) + installHierarchyFitter(viewFinder) + addView(viewFinder) + + effectLayer.alpha = 0F + effectLayer.setBackgroundColor(Color.BLACK) + addView(effectLayer) + addView(rectOverlay) + } + + override fun onAttachedToWindow() { + super.onAttachedToWindow() + if (hasPermissions()) { + viewFinder.post { setupCamera() } + } + } + + override fun onDetachedFromWindow() { + super.onDetachedFromWindow() + + cameraExecutor.shutdown() + orientationListener?.disable() + cameraProvider?.unbindAll() + } + + // If this is not called correctly, view finder will be black/blank + // https://github.com/facebook/react-native/issues/17968#issuecomment-633308615 + private fun installHierarchyFitter(view: ViewGroup) { + Log.d(TAG, "CameraView looking for ThemedReactContext") + if (context is ThemedReactContext) { // only react-native setup + Log.d(TAG, "CameraView found ThemedReactContext") + view.setOnHierarchyChangeListener(object : OnHierarchyChangeListener { + override fun onChildViewRemoved(parent: View?, child: View?) = Unit + override fun onChildViewAdded(parent: View?, child: View?) { + parent?.measure( + MeasureSpec.makeMeasureSpec(measuredWidth, MeasureSpec.EXACTLY), + MeasureSpec.makeMeasureSpec(measuredHeight, MeasureSpec.EXACTLY) + ) + parent?.layout(0, 0, parent.measuredWidth, parent.measuredHeight) + } + }) + } + } + + /** Initialize CameraX, and prepare to bind the camera use cases */ + @SuppressLint("ClickableViewAccessibility") + private fun setupCamera() { + val cameraProviderFuture = ProcessCameraProvider.getInstance(getActivity()) + cameraProviderFuture.addListener({ + // Used to bind the lifecycle of cameras to the lifecycle owner + cameraProvider = cameraProviderFuture.get() + + // Rotate the image according to device orientation, even when UI orientation is locked + orientationListener = object : OrientationEventListener(context, SensorManager.SENSOR_DELAY_UI) { + override fun onOrientationChanged(orientation: Int) { + val imageCapture = imageCapture ?: return + var newOrientation: Int = imageCapture.targetRotation + if (orientation >= 315 || orientation < 45) { + newOrientation = Surface.ROTATION_0 + } else if (orientation in 225..314) { + newOrientation = Surface.ROTATION_90 + } else if (orientation in 135..224) { + newOrientation = Surface.ROTATION_180 + } else if (orientation in 45..134) { + newOrientation = Surface.ROTATION_270 + } + if (newOrientation != imageCapture.targetRotation) { + imageCapture.targetRotation = newOrientation + onOrientationChange(newOrientation) + } + } + } + orientationListener!!.enable() + + val scaleDetector = ScaleGestureDetector(context, object: ScaleGestureDetector.SimpleOnScaleGestureListener() { + override fun onScaleBegin(detector: ScaleGestureDetector): Boolean { + val cameraZoom = camera?.cameraInfo?.zoomState?.value?.zoomRatio ?: return false + detector ?: return false + zoomStartedAt = cameraZoom + pinchGestureStartedAt = detector.currentSpan + return true + } + override fun onScale(detector: ScaleGestureDetector): Boolean { + if (zoomMode == "off") return true + if (detector == null) return true + val videoDevice = camera ?: return true + val pinchScale = detector.currentSpan / pinchGestureStartedAt + + val desiredZoomFactor = zoomStartedAt * pinchScale + val zoomForDevice = getValidZoom(videoDevice, desiredZoomFactor.toDouble()) + + if (zoomForDevice != (videoDevice.cameraInfo.zoomState.value?.zoomRatio ?: -1)) { + // Only trigger zoom changes if it's an uncontrolled component (zoom isn't manually set) + // otherwise it's likely to cause issues inf. loops + if (zoom == null) { + videoDevice.cameraControl.setZoomRatio(zoomForDevice.toFloat()) + } + onZoom(zoomForDevice) + } + return true + } + }) + + // Tap to focus + viewFinder.setOnTouchListener { _, event -> + if (event.action != MotionEvent.ACTION_UP) { + return@setOnTouchListener scaleDetector.onTouchEvent(event) + } + focusOnPoint(event.x, event.y) + return@setOnTouchListener true + } + + bindCameraUseCases() + }, ContextCompat.getMainExecutor(getActivity())) + } + + private fun setZoomFor(videoDevice: Camera, zoom: Double) { + videoDevice.cameraControl.setZoomRatio(zoom.toFloat()) + } + + private fun resetZoom(videoDevice: Camera) { + var zoomForDevice = getValidZoom(videoDevice, 1.0) + val zoomPropValue = this.zoom + if (zoomPropValue != null) { + zoomForDevice = getValidZoom(videoDevice, zoomPropValue) + } + setZoomFor(videoDevice, zoomForDevice) + this.onZoom(zoomForDevice) + } + + private fun getValidZoom(videoDevice: Camera?, zoom: Double): Double { + var zoomOrDefault = zoom + val minZoomFactor = videoDevice?.cameraInfo?.zoomState?.value?.minZoomRatio?.toDouble() + var maxZoomFactor: Double? = videoDevice?.cameraInfo?.zoomState?.value?.maxZoomRatio?.toDouble() + val maxZoom = this.maxZoom + if (maxZoom != null) { + maxZoomFactor = min(maxZoomFactor ?: maxZoom, maxZoom) + } + if (maxZoomFactor != null) { + zoomOrDefault = min(zoomOrDefault, maxZoomFactor) + } + if (minZoomFactor != null) { + zoomOrDefault = max(zoomOrDefault, minZoomFactor) + } + return zoomOrDefault + } + + private fun bindCameraUseCases() { + if (viewFinder.display == null) return + // Get screen metrics used to setup camera for full screen resolution + val metrics = DisplayMetrics().also { viewFinder.display.getRealMetrics(it) } + Log.d(TAG, "Screen metrics: ${metrics.widthPixels} x ${metrics.heightPixels}") + + val screenAspectRatio = aspectRatio(metrics.widthPixels, metrics.heightPixels) + Log.d(TAG, "Preview aspect ratio: $screenAspectRatio") + + val rotation = viewFinder.display.rotation + + // CameraProvider + val cameraProvider = cameraProvider + ?: throw IllegalStateException("Camera initialization failed.") + + // CameraSelector + val cameraSelector = CameraSelector.Builder().requireLensFacing(lensType).build() + + // Preview + preview = Preview.Builder() + // We request aspect ratio but no resolution + .setTargetAspectRatio(screenAspectRatio) + // Set initial target rotation + .setTargetRotation(rotation) + .build() + + // ImageCapture + imageCapture = ImageCapture.Builder() + .setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY) + // We request aspect ratio but no resolution to match preview config, but letting + // CameraX optimize for whatever specific resolution best fits our use cases + .setTargetAspectRatio(screenAspectRatio) + // Set initial target rotation, we will have to call this again if rotation changes + // during the lifecycle of this use case + .setTargetRotation(rotation) + .build() + + // ImageAnalysis + imageAnalyzer = ImageAnalysis.Builder() + .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST) + .setTargetAspectRatio(screenAspectRatio) + .build() + + val useCases = mutableListOf(preview, imageCapture) + + if (scanBarcode) { + val analyzer = QRCodeAnalyzer { barcodes -> + if (barcodes.isNotEmpty()) { + onBarcodeRead(barcodes) + } + } + imageAnalyzer!!.setAnalyzer(cameraExecutor, analyzer) + useCases.add(imageAnalyzer) + } + + // Must unbind the use-cases before rebinding them + cameraProvider.unbindAll() + + try { + // A variable number of use-cases can be passed here - + // camera provides access to CameraControl & CameraInfo + val newCamera = cameraProvider.bindToLifecycle(getActivity() as AppCompatActivity, cameraSelector, *useCases.toTypedArray()) + camera = newCamera + + resetZoom(newCamera) + + // Attach the viewfinder's surface provider to preview use case + preview?.setSurfaceProvider(viewFinder.surfaceProvider) + } catch (exc: Exception) { + Log.e(TAG, "Use case binding failed", exc) + + val surfaceId = UIManagerHelper.getSurfaceId(currentContext) + UIManagerHelper + .getEventDispatcherForReactTag(currentContext, id) + ?.dispatchEvent(ErrorEvent(surfaceId, id, exc.message)) + } + } + + /** + * [androidx.camera.core.ImageAnalysisConfig] requires enum value of + * [androidx.camera.core.AspectRatio]. Currently it has values of 4:3 & 16:9. + * + * Detecting the most suitable ratio for dimensions provided in @params by counting absolute + * of preview ratio to one of the provided values. + * + * @param width - preview width + * @param height - preview height + * @return suitable aspect ratio + */ + private fun aspectRatio(width: Int, height: Int): Int { + val previewRatio = max(width, height).toDouble() / min(width, height) + if (abs(previewRatio - RATIO_4_3_VALUE) <= abs(previewRatio - RATIO_16_9_VALUE)) { + return AspectRatio.RATIO_4_3 + } + return AspectRatio.RATIO_16_9 + } + + private fun flashViewFinder() { + if (shutterAnimationDuration == 0) return + + effectLayer + .animate() + .alpha(1F) + .setDuration(shutterAnimationDuration.toLong()) + .setListener(object : AnimatorListenerAdapter() { + override fun onAnimationEnd(animation: Animator) { + effectLayer.animate().alpha(0F).duration = shutterAnimationDuration.toLong() + } + }).start() + } + + fun setShutterAnimationDuration(duration: Int) { + shutterAnimationDuration = duration + } + + fun setShutterPhotoSound(enabled: Boolean) { + shutterPhotoSound = enabled; + } + + fun capture(options: Map, promise: Promise) { + // Create the output file option to store the captured image in MediaStore + val outputPath: String = when { + outputPath != null -> outputPath!! + else -> { + val out = File.createTempFile("ckcap", ".jpg", context.cacheDir) + out.deleteOnExit() + out.canonicalPath + } + } + + val outputFile = File(outputPath) + val outputOptions = ImageCapture.OutputFileOptions + .Builder(outputFile) + .build() + + flashViewFinder() + + if (shutterPhotoSound) { + val audio = getActivity().getSystemService(Context.AUDIO_SERVICE) as AudioManager + if (audio.ringerMode == AudioManager.RINGER_MODE_NORMAL) { + MediaActionSound().play(MediaActionSound.SHUTTER_CLICK) + } + } + + // Setup image capture listener which is triggered after photo has been taken + imageCapture?.takePicture( + outputOptions, ContextCompat.getMainExecutor(getActivity()), object : ImageCapture.OnImageSavedCallback { + override fun onError(ex: ImageCaptureException) { + Log.e(TAG, "CameraView: Photo capture failed: ${ex.message}", ex) + promise.reject("E_CAPTURE_FAILED", "takePicture failed: ${ex.message}") + } + + override fun onImageSaved(output: ImageCapture.OutputFileResults) { + try { + val uri = output.savedUri ?: Uri.fromFile(outputFile) + val id = uri?.path + val name = uri?.lastPathSegment + val path = uri?.path + + val savedUri = (output.savedUri ?: outputPath).toString() + onPictureTaken(savedUri) + Log.d(TAG, "CameraView: Photo capture succeeded: $savedUri") + + val imageInfo = Arguments.createMap() + imageInfo.putString("uri", uri.toString()) + imageInfo.putString("id", id) + imageInfo.putString("name", name) + imageInfo.putInt("width", width) + imageInfo.putInt("height", height) + imageInfo.putString("path", path) + + promise.resolve(imageInfo) + } catch (ex: Exception) { + Log.e(TAG, "Error while saving or decoding saved photo: ${ex.message}", ex) + promise.reject("E_ON_IMG_SAVED", "Error while reading saved photo: ${ex.message}") + } + } + }) + } + + private fun focusOnPoint(x: Float?, y: Float?) { + if (x === null || y === null) { + camera?.cameraControl?.cancelFocusAndMetering() + return + } + val factory = viewFinder.meteringPointFactory + val builder = FocusMeteringAction.Builder(factory.createPoint(x, y)) + + // Auto-cancel will clear focus points (and engage AF) after a duration + if (autoFocus == "off") builder.disableAutoCancel() + + camera?.cameraControl?.startFocusAndMetering(builder.build()) + val focusRects = listOf(RectF(x-75, y-75, x+75, y+75)) + rectOverlay.drawRectBounds(focusRects) + } + + private fun onBarcodeRead(barcodes: List) { + val codeFormat = CodeFormat.fromBarcodeType(barcodes.first().format); + val surfaceId = UIManagerHelper.getSurfaceId(currentContext) + UIManagerHelper + .getEventDispatcherForReactTag(currentContext, id) + ?.dispatchEvent(ReadCodeEvent(surfaceId, id, barcodes.first().rawValue, codeFormat.code)) + } + + private fun onOrientationChange(orientation: Int) { + val remappedOrientation = when (orientation) { + Surface.ROTATION_0 -> RNCameraKitModule.PORTRAIT + Surface.ROTATION_90 -> RNCameraKitModule.LANDSCAPE_LEFT + Surface.ROTATION_180 -> RNCameraKitModule.PORTRAIT_UPSIDE_DOWN + Surface.ROTATION_270 -> RNCameraKitModule.LANDSCAPE_RIGHT + else -> { + Log.e(TAG, "CameraView: Unknown device orientation detected: $orientation") + return + } + } + + val surfaceId = UIManagerHelper.getSurfaceId(currentContext) + UIManagerHelper + .getEventDispatcherForReactTag(currentContext, id) + ?.dispatchEvent(OrientationChangeEvent(surfaceId, id, remappedOrientation)) + } + + private fun onPictureTaken(uri: String) { + val surfaceId = UIManagerHelper.getSurfaceId(currentContext) + UIManagerHelper + .getEventDispatcherForReactTag(currentContext, id) + ?.dispatchEvent(PictureTakenEvent(surfaceId, id, uri)) + } + + fun setFlashMode(mode: String?) { + val imageCapture = imageCapture ?: return + val camera = camera ?: return + when (mode) { + "on" -> { + camera.cameraControl.enableTorch(false) + imageCapture.flashMode = ImageCapture.FLASH_MODE_ON + } + "off" -> { + camera.cameraControl.enableTorch(false) + imageCapture.flashMode = ImageCapture.FLASH_MODE_OFF + } + else -> { // 'auto' and any wrong values + imageCapture.flashMode = ImageCapture.FLASH_MODE_AUTO + camera.cameraControl.enableTorch(false) + } + } + } + + fun setTorchMode(mode: String?) { + val camera = camera ?: return + when (mode) { + "on" -> { + camera.cameraControl.enableTorch(true) + } + "off" -> { + camera.cameraControl.enableTorch(false) + } + else -> { // 'auto' and any wrong values + camera.cameraControl.enableTorch(false) + } + } + } + + fun setAutoFocus(mode: String = "on") { + autoFocus = mode + when(mode) { + // "cancel" clear AF points and engages continuous auto-focus + "on" -> camera?.cameraControl?.cancelFocusAndMetering() + // 'off': Handled when you tap to focus + } + } + + fun setZoomMode(mode: String?) { + zoomMode = mode ?: "off" + } + + fun setZoom(factor: Double?) { + zoom = factor + var zoomOrDefault = zoom ?: return + val videoDevice = camera ?: return + + val zoomForDevice = this.getValidZoom(camera, zoomOrDefault) + this.setZoomFor(videoDevice, zoomForDevice) + } + + private fun onZoom(desiredZoom: Double?) { + val cameraZoom = camera?.cameraInfo?.zoomState?.value?.zoomRatio?.toDouble() ?: return + val desiredOrCameraZoom = desiredZoom ?: cameraZoom + // ignore duplicate events when zooming to min/max + // but always notify if a desiredZoom wasn't given, + // since that means they wanted to reset setZoom(1.0) + // so we should tell them what zoom it really is + if (desiredZoom != null && desiredOrCameraZoom == lastOnZoom) { + return + } + + lastOnZoom = desiredOrCameraZoom + val surfaceId = UIManagerHelper.getSurfaceId(currentContext) + UIManagerHelper + .getEventDispatcherForReactTag(currentContext, id) + ?.dispatchEvent(ZoomEvent(surfaceId, id, desiredOrCameraZoom)) + } + + fun setMaxZoom(factor: Double?) { + maxZoom = factor + + // Re-update zoom value in case the max was increased + setZoom(zoom) + } + + fun setScanBarcode(enabled: Boolean) { + val restartCamera = enabled != scanBarcode + scanBarcode = enabled + if (restartCamera) bindCameraUseCases() + } + + fun setCameraType(type: String = "back") { + val newLensType = when (type) { + "front" -> CameraSelector.LENS_FACING_FRONT + else -> CameraSelector.LENS_FACING_BACK + } + val restartCamera = lensType != newLensType + lensType = newLensType + if (restartCamera) bindCameraUseCases() + } + + fun setOutputPath(path: String) { + outputPath = path + } + + fun setShowFrame(enabled: Boolean) { + if (enabled) { + barcodeFrame = BarcodeFrame(context) + val actualPreviewWidth = resources.displayMetrics.widthPixels + val actualPreviewHeight = resources.displayMetrics.heightPixels + val height: Int = convertDeviceHeightToSupportedAspectRatio(actualPreviewWidth, actualPreviewHeight) + barcodeFrame!!.setFrameColor(frameColor) + barcodeFrame!!.setLaserColor(laserColor) + (barcodeFrame as View).layout(0, 0, this.effectLayer.width, this.effectLayer.height) + addView(barcodeFrame) + } else if (barcodeFrame != null) { + removeView(barcodeFrame) + barcodeFrame = null + } + } + + fun setLaserColor(@ColorInt color: Int) { + laserColor = color + if (barcodeFrame != null) { + barcodeFrame!!.setLaserColor(laserColor) + } + } + + fun setFrameColor(@ColorInt color: Int) { + frameColor = color + if (barcodeFrame != null) { + barcodeFrame!!.setFrameColor(color) + } + } + + private fun convertDeviceHeightToSupportedAspectRatio(actualWidth: Int, actualHeight: Int): Int { + val maxScreenRatio = 16 / 9f + return (if (actualHeight / actualWidth > maxScreenRatio) actualWidth * maxScreenRatio else actualHeight).toInt() + } + + private fun hasPermissions(): Boolean { + val requiredPermissions = arrayOf(Manifest.permission.CAMERA) + if (requiredPermissions.all { + ContextCompat.checkSelfPermission(context, it) == PackageManager.PERMISSION_GRANTED + }) { + return true + } + ActivityCompat.requestPermissions( + getActivity(), + requiredPermissions, + 42 // random callback identifier + ) + return false + } + + companion object { + + private const val TAG = "CameraKit" + private const val RATIO_4_3_VALUE = 4.0 / 3.0 + private const val RATIO_16_9_VALUE = 16.0 / 9.0 + } +} diff --git a/android/src/main/java/com/rncamerakit/CKCameraManager.kt b/android/src/main/java/com/rncamerakit/CKCameraManager.kt new file mode 100644 index 0000000000..6c3b22acb3 --- /dev/null +++ b/android/src/main/java/com/rncamerakit/CKCameraManager.kt @@ -0,0 +1,144 @@ +package com.rncamerakit + +import android.graphics.Color +import android.util.Log +import androidx.annotation.ColorInt +import com.facebook.react.bridge.ReadableArray +import com.facebook.react.bridge.ReadableType +import com.facebook.react.common.MapBuilder +import com.facebook.react.common.ReactConstants.TAG +import com.facebook.react.uimanager.SimpleViewManager +import com.facebook.react.uimanager.ThemedReactContext +import com.facebook.react.uimanager.ViewManagerDelegate +import com.facebook.react.uimanager.annotations.ReactProp +import com.facebook.react.viewmanagers.CKCameraManagerDelegate +import com.facebook.react.viewmanagers.CKCameraManagerInterface +import com.rncamerakit.events.* + +class CKCameraManager : SimpleViewManager(), CKCameraManagerInterface { + + private val delegate: ViewManagerDelegate = CKCameraManagerDelegate(this) + + override fun getDelegate(): ViewManagerDelegate = delegate + + override fun getName() : String { + return "CKCamera" + } + + override fun createViewInstance(context: ThemedReactContext): CKCamera { + return CKCamera(context) + } + + override fun receiveCommand(view: CKCamera, commandId: String?, args: ReadableArray?) { + var logCommand = "CameraManager received command $commandId(" + for (i in 0..(args?.size() ?: 0)) { + if (i > 0) { + logCommand += ", " + } + logCommand += when (args?.getType(0)) { + ReadableType.Null -> "Null" + ReadableType.Array -> "Array" + ReadableType.Boolean -> "Boolean" + ReadableType.Map -> "Map" + ReadableType.Number -> "Number" + ReadableType.String -> "String" + else -> "" + } + } + logCommand += ")" + Log.d(TAG, logCommand) + } + + override fun getExportedCustomDirectEventTypeConstants(): Map { + return MapBuilder.of( + OrientationChangeEvent.EVENT_NAME, MapBuilder.of("registrationName", "onOrientationChange"), + ReadCodeEvent.EVENT_NAME, MapBuilder.of("registrationName", "onReadCode"), + PictureTakenEvent.EVENT_NAME, MapBuilder.of("registrationName", "onPictureTaken"), + ZoomEvent.EVENT_NAME, MapBuilder.of("registrationName", "onZoom"), + ErrorEvent.EVENT_NAME, MapBuilder.of("registrationName", "onError") + ) + } + + @ReactProp(name = "cameraType") + override fun setCameraType(view: CKCamera, type: String?) { + view.setCameraType(type ?: "back") + } + + @ReactProp(name = "flashMode") + override fun setFlashMode(view: CKCamera, mode: String?) { + view.setFlashMode(mode) + } + + @ReactProp(name = "torchMode") + override fun setTorchMode(view: CKCamera, mode: String?) { + view.setTorchMode(mode) + } + + @ReactProp(name = "focusMode") + override fun setFocusMode(view: CKCamera, mode: String?) { + view.setAutoFocus(mode ?: "on") + } + + @ReactProp(name = "zoomMode") + override fun setZoomMode(view: CKCamera, mode: String?) { + view.setZoomMode(mode) + } + + @ReactProp(name = "zoom", defaultDouble = -1.0) + override fun setZoom(view: CKCamera, factor: Double) { + view.setZoom(if (factor == -1.0) null else factor) + } + + @ReactProp(name = "maxZoom", defaultDouble = 420.0) + override fun setMaxZoom(view: CKCamera, factor: Double) { + view.setMaxZoom(factor) + } + + @ReactProp(name = "scanBarcode") + override fun setScanBarcode(view: CKCamera, enabled: Boolean) { + view.setScanBarcode(enabled) + } + + @ReactProp(name = "showFrame") + override fun setShowFrame(view: CKCamera, enabled: Boolean) { + view.setShowFrame(enabled) + } + + @ReactProp(name = "laserColor", defaultInt = Color.RED) + override fun setLaserColor(view: CKCamera, @ColorInt color: Int?) { + view.setLaserColor(color ?: Color.RED) + } + + @ReactProp(name = "frameColor", defaultInt = Color.GREEN) + override fun setFrameColor(view: CKCamera, @ColorInt color: Int?) { + view.setFrameColor(color ?: Color.GREEN) + } + + @ReactProp(name = "outputPath") + override fun setOutputPath(view: CKCamera, path: String?) { + view.setOutputPath(path ?: "") + } + + @ReactProp(name = "shutterAnimationDuration") + override fun setShutterAnimationDuration(view: CKCamera, duration: Int) { + view.setShutterAnimationDuration(duration) + } + + @ReactProp(name = "shutterPhotoSound") + override fun setShutterPhotoSound(view: CKCamera, enabled: Boolean) { + view.setShutterPhotoSound(enabled); + } + + // Methods only available on iOS + override fun setRatioOverlay(view: CKCamera?, value: String?) = Unit + + override fun setRatioOverlayColor(view: CKCamera?, value: Int?) = Unit + + override fun setResetFocusTimeout(view: CKCamera?, value: Int) = Unit + + override fun setResetFocusWhenMotionDetected(view: CKCamera?, value: Boolean) = Unit + + override fun setResizeMode(view: CKCamera?, value: String?) = Unit + + override fun setScanThrottleDelay(view: CKCamera?, value: Int) = Unit +} diff --git a/android/src/main/java/com/rncamerakit/CodeFormat.kt b/android/src/main/java/com/rncamerakit/CodeFormat.kt new file mode 100644 index 0000000000..207c7151da --- /dev/null +++ b/android/src/main/java/com/rncamerakit/CodeFormat.kt @@ -0,0 +1,56 @@ +package com.rncamerakit + +import com.google.mlkit.vision.barcode.common.Barcode + +enum class CodeFormat(val code: String) { + CODE_128("code-128"), + CODE_39("code-39"), + CODE_93("code-93"), + CODABAR("codabar"), + EAN_13("ean-13"), + EAN_8("ean-8"), + ITF("itf"), + UPC_E("upc-e"), + QR("qr"), + PDF_417("pdf-417"), + AZTEC("aztec"), + DATA_MATRIX("data-matrix"), + UNKNOWN("unknown"); + + fun toBarcodeType(): Int { + return when (this) { + CODE_128 -> Barcode.FORMAT_CODE_128 + CODE_39 -> Barcode.FORMAT_CODE_39 + CODE_93 -> Barcode.FORMAT_CODE_93 + CODABAR -> Barcode.FORMAT_CODABAR + EAN_13 -> Barcode.FORMAT_EAN_13 + EAN_8 -> Barcode.FORMAT_EAN_8 + ITF -> Barcode.FORMAT_ITF + UPC_E -> Barcode.FORMAT_UPC_E + QR -> Barcode.FORMAT_QR_CODE + PDF_417 -> Barcode.FORMAT_PDF417 + AZTEC -> Barcode.FORMAT_AZTEC + DATA_MATRIX -> Barcode.FORMAT_DATA_MATRIX + UNKNOWN -> -1 // Or any other default value you prefer + } + } + + companion object { + fun fromBarcodeType(@Barcode.BarcodeFormat barcodeType: Int): CodeFormat = + when (barcodeType) { + Barcode.FORMAT_CODE_128 -> CODE_128 + Barcode.FORMAT_CODE_39 -> CODE_39 + Barcode.FORMAT_CODE_93 -> CODE_93 + Barcode.FORMAT_CODABAR -> CODABAR + Barcode.FORMAT_EAN_13 -> EAN_13 + Barcode.FORMAT_EAN_8 -> EAN_8 + Barcode.FORMAT_ITF -> ITF + Barcode.FORMAT_UPC_E -> UPC_E + Barcode.FORMAT_QR_CODE -> QR + Barcode.FORMAT_PDF417 -> PDF_417 + Barcode.FORMAT_AZTEC -> AZTEC + Barcode.FORMAT_DATA_MATRIX -> DATA_MATRIX + else -> UNKNOWN + } + } +} diff --git a/android/src/main/java/com/rncamerakit/QRCodeAnalyzer.kt b/android/src/main/java/com/rncamerakit/QRCodeAnalyzer.kt new file mode 100644 index 0000000000..7af1df106d --- /dev/null +++ b/android/src/main/java/com/rncamerakit/QRCodeAnalyzer.kt @@ -0,0 +1,32 @@ +package com.rncamerakit + +import android.annotation.SuppressLint +import androidx.camera.core.ExperimentalGetImage +import androidx.camera.core.ImageAnalysis +import androidx.camera.core.ImageProxy +import com.google.mlkit.vision.barcode.BarcodeScanning +import com.google.mlkit.vision.barcode.common.Barcode +import com.google.mlkit.vision.common.InputImage + +class QRCodeAnalyzer ( + private val onQRCodesDetected: (qrCodes: List) -> Unit +) : ImageAnalysis.Analyzer { + @SuppressLint("UnsafeExperimentalUsageError") + @ExperimentalGetImage + override fun analyze(image: ImageProxy) { + val inputImage = InputImage.fromMediaImage(image.image!!, image.imageInfo.rotationDegrees) + + val scanner = BarcodeScanning.getClient() + scanner.process(inputImage) + .addOnSuccessListener { barcodes -> + val strBarcodes = mutableListOf() + barcodes.forEach { barcode -> + strBarcodes.add(barcode ?: return@forEach) + } + onQRCodesDetected(strBarcodes) + } + .addOnCompleteListener{ + image.close() + } + } +} \ No newline at end of file diff --git a/android/src/main/java/com/rncamerakit/RNCameraKitModule.kt b/android/src/main/java/com/rncamerakit/RNCameraKitModule.kt new file mode 100644 index 0000000000..15d7cf6086 --- /dev/null +++ b/android/src/main/java/com/rncamerakit/RNCameraKitModule.kt @@ -0,0 +1,83 @@ +package com.rncamerakit + +import com.facebook.react.bridge.* +import com.facebook.react.uimanager.UIManagerHelper + +/** + * Native module for interacting with the camera in React Native applications. + * + * This module provides methods to capture photos using the camera and constants + * related to camera orientation. + * + * @param reactContext The application's ReactApplicationContext. + */ +class RNCameraKitModule(private val reactContext: ReactApplicationContext) : NativeCameraKitModuleSpec(reactContext) { + + companion object { + // Constants for camera orientation + /** + * Represents the portrait orientation with the top of the device up. + */ + const val PORTRAIT = 0 // ⬆️ + + /** + * Represents the landscape orientation with the left side of the device up. + */ + const val LANDSCAPE_LEFT = 1 // ⬅️ + + /** + * Represents the portrait orientation with the bottom of the device up. + */ + const val PORTRAIT_UPSIDE_DOWN = 2 // ⬇️ + + /** + * Represents the landscape orientation with the right side of the device up. + */ + const val LANDSCAPE_RIGHT = 3 // ➑️ + + const val REACT_CLASS = "RNCameraKitModule" + } + + override fun getName(): String { + return REACT_CLASS + } + + /** + * Provides constants related to camera orientation. + * + * @return A map containing camera orientation constants. + */ + override fun getConstants(): Map { + return hashMapOf( + "PORTRAIT" to PORTRAIT, + "PORTRAIT_UPSIDE_DOWN" to PORTRAIT_UPSIDE_DOWN, + "LANDSCAPE_LEFT" to LANDSCAPE_LEFT, + "LANDSCAPE_RIGHT" to LANDSCAPE_RIGHT + ) + } + + override fun requestDeviceCameraAuthorization(promise: Promise?) = Unit + + override fun checkDeviceCameraAuthorizationStatus(promise: Promise?) = Unit + + /** + * Captures a photo using the camera. + * + * @param options The options for the capture operation. + * @param viewTag The tag of the camera view. + * @param promise The promise to resolve the capture result. + */ + @ReactMethod + override fun capture(options: ReadableMap?, tag: Double?, promise: Promise) { + val viewTag = tag?.toInt() + if (viewTag != null && options != null) { + val uiManager = UIManagerHelper.getUIManagerForReactTag(reactContext, viewTag) + reactContext.runOnUiQueueThread { + val camera = uiManager?.resolveView(viewTag) as CKCamera + camera.capture(options.toHashMap(), promise) + } + } else { + promise.reject("E_CAPTURE_FAILED", "options or/and tag arguments are null, options: $options, tag: $viewTag") + } + } +} diff --git a/android/src/main/java/com/rncamerakit/RNCameraKitPackage.kt b/android/src/main/java/com/rncamerakit/RNCameraKitPackage.kt new file mode 100644 index 0000000000..02cb26e05b --- /dev/null +++ b/android/src/main/java/com/rncamerakit/RNCameraKitPackage.kt @@ -0,0 +1,43 @@ +package com.rncamerakit + +import com.facebook.react.TurboReactPackage +import com.facebook.react.bridge.NativeModule +import com.facebook.react.bridge.ReactApplicationContext +import com.facebook.react.module.annotations.ReactModuleList +import com.facebook.react.module.model.ReactModuleInfo +import com.facebook.react.module.model.ReactModuleInfoProvider +import com.facebook.react.uimanager.ViewManager +import java.util.* + +@ReactModuleList(nativeModules = [RNCameraKitModule::class]) +class RNCameraKitPackage : TurboReactPackage() { + + override fun createViewManagers(reactContext: ReactApplicationContext): List> { + val viewManagers: MutableList> = ArrayList() + viewManagers.add(CKCameraManager()) + return viewManagers + } + + override fun getModule(s: String, reactApplicationContext: ReactApplicationContext): NativeModule? { + when (s) { + RNCameraKitModule.REACT_CLASS -> return RNCameraKitModule(reactApplicationContext) + } + return null + } + + override fun getReactModuleInfoProvider(): ReactModuleInfoProvider { + return ReactModuleInfoProvider { + val moduleInfos: MutableMap = HashMap() + val isTurboModule = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED + moduleInfos[RNCameraKitModule.REACT_CLASS] = ReactModuleInfo( + RNCameraKitModule.REACT_CLASS, + RNCameraKitModule.REACT_CLASS, + false, // canOverrideExistingModule + false, // needsEagerInit + false, // isCxxModule + isTurboModule // isTurboModule + ) + moduleInfos + } + } +} diff --git a/android/src/main/java/com/rncamerakit/barcode/BarcodeFrame.kt b/android/src/main/java/com/rncamerakit/barcode/BarcodeFrame.kt new file mode 100644 index 0000000000..ae694a839c --- /dev/null +++ b/android/src/main/java/com/rncamerakit/barcode/BarcodeFrame.kt @@ -0,0 +1,90 @@ +package com.rncamerakit.barcode + +import android.content.Context +import android.graphics.* +import android.view.View +import androidx.annotation.ColorInt + +import com.rncamerakit.R +import kotlin.math.max +import kotlin.math.min + +class BarcodeFrame(context: Context) : View(context) { + private var borderPaint: Paint = Paint() + private var laserPaint: Paint = Paint() + var frameRect: Rect = Rect() + + private var frameWidth = 0 + private var frameHeight = 0 + private var borderMargin = 0 + private var previousFrameTime = System.currentTimeMillis() + private var laserY = 0 + + private fun init(context: Context) { + borderPaint = Paint() + borderPaint.style = Paint.Style.STROKE + borderPaint.strokeWidth = STROKE_WIDTH.toFloat() + laserPaint.style = Paint.Style.STROKE + laserPaint.strokeWidth = STROKE_WIDTH.toFloat() + borderMargin = context.resources.getDimensionPixelSize(R.dimen.border_length) + } + + override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec) + val marginHeight = 40 + val marginWidth = 40 + val frameMaxWidth = 1200 + val frameMaxHeight = 600 + val frameMinWidth = 100 + val frameMinHeight = 100 + frameWidth = max(frameMinWidth, min(frameMaxWidth, measuredWidth - (marginWidth * 2))) + frameHeight = max(frameMinHeight, min(frameMaxHeight, measuredHeight - (marginHeight * 2))) + frameRect.left = (measuredWidth / 2) - (frameWidth / 2) + frameRect.right = (measuredWidth / 2) + (frameWidth / 2) + frameRect.top = (measuredHeight / 2) - (frameHeight / 2) + frameRect.bottom = (measuredHeight / 2) + (frameHeight / 2) + } + + override fun onDraw(canvas: Canvas) { + val timeElapsed = System.currentTimeMillis() - previousFrameTime + super.onDraw(canvas) + drawBorder(canvas) + drawLaser(canvas, timeElapsed) + previousFrameTime = System.currentTimeMillis() + this.invalidate(frameRect) + } + + private fun drawBorder(canvas: Canvas) { + canvas.drawLine(frameRect.left.toFloat(), frameRect.top.toFloat(), frameRect.left.toFloat(), (frameRect.top + borderMargin).toFloat(), borderPaint) + canvas.drawLine(frameRect.left.toFloat(), frameRect.top.toFloat(), (frameRect.left + borderMargin).toFloat(), frameRect.top.toFloat(), borderPaint) + canvas.drawLine(frameRect.left.toFloat(), frameRect.bottom.toFloat(), frameRect.left.toFloat(), (frameRect.bottom - borderMargin).toFloat(), borderPaint) + canvas.drawLine(frameRect.left.toFloat(), frameRect.bottom.toFloat(), (frameRect.left + borderMargin).toFloat(), frameRect.bottom.toFloat(), borderPaint) + canvas.drawLine(frameRect.right.toFloat(), frameRect.top.toFloat(), (frameRect.right - borderMargin).toFloat(), frameRect.top.toFloat(), borderPaint) + canvas.drawLine(frameRect.right.toFloat(), frameRect.top.toFloat(), frameRect.right.toFloat(), (frameRect.top + borderMargin).toFloat(), borderPaint) + canvas.drawLine(frameRect.right.toFloat(), frameRect.bottom.toFloat(), frameRect.right.toFloat(), (frameRect.bottom - borderMargin).toFloat(), borderPaint) + canvas.drawLine(frameRect.right.toFloat(), frameRect.bottom.toFloat(), (frameRect.right - borderMargin).toFloat(), frameRect.bottom.toFloat(), borderPaint) + } + + private fun drawLaser(canvas: Canvas, timeElapsed: Long) { + if (laserY > frameRect.bottom || laserY < frameRect.top) laserY = frameRect.top + canvas.drawLine((frameRect.left + STROKE_WIDTH).toFloat(), laserY.toFloat(), (frameRect.right - STROKE_WIDTH).toFloat(), laserY.toFloat(), laserPaint) + laserY += (timeElapsed / ANIMATION_SPEED).toInt() + } + + fun setFrameColor(@ColorInt borderColor: Int) { + borderPaint.color = borderColor + } + + fun setLaserColor(@ColorInt laserColor: Int) { + laserPaint.color = laserColor + } + + companion object { + private const val STROKE_WIDTH = 5 + private const val ANIMATION_SPEED = 4 + } + + init { + init(context) + } +} diff --git a/android/src/main/java/com/rncamerakit/events/ErrorEvent.kt b/android/src/main/java/com/rncamerakit/events/ErrorEvent.kt new file mode 100644 index 0000000000..a015425954 --- /dev/null +++ b/android/src/main/java/com/rncamerakit/events/ErrorEvent.kt @@ -0,0 +1,22 @@ +package com.rncamerakit.events + +import com.facebook.react.bridge.Arguments +import com.facebook.react.bridge.WritableMap +import com.facebook.react.uimanager.events.Event + +class ErrorEvent( + surfaceId: Int, + viewId: Int, + private val errorMessage: String?, +) : Event(surfaceId, viewId) { + override fun getEventName(): String = EVENT_NAME + + override fun getEventData(): WritableMap = + Arguments.createMap().apply { + putString("errorMessage", errorMessage) + } + + companion object { + const val EVENT_NAME = "topError" + } +} diff --git a/android/src/main/java/com/rncamerakit/events/OrientationChangeEvent.kt b/android/src/main/java/com/rncamerakit/events/OrientationChangeEvent.kt new file mode 100644 index 0000000000..5685f4ffad --- /dev/null +++ b/android/src/main/java/com/rncamerakit/events/OrientationChangeEvent.kt @@ -0,0 +1,22 @@ +package com.rncamerakit.events + +import com.facebook.react.bridge.Arguments +import com.facebook.react.bridge.WritableMap +import com.facebook.react.uimanager.events.Event + +class OrientationChangeEvent( + surfaceId: Int, + viewId: Int, + private val orientation: Int, +) : Event(surfaceId, viewId) { + override fun getEventName(): String = EVENT_NAME + + override fun getEventData(): WritableMap = + Arguments.createMap().apply { + putInt("orientation", orientation) + } + + companion object { + const val EVENT_NAME = "topOrientationChange" + } +} diff --git a/android/src/main/java/com/rncamerakit/events/PictureTakenEvent.kt b/android/src/main/java/com/rncamerakit/events/PictureTakenEvent.kt new file mode 100644 index 0000000000..fc71ba7405 --- /dev/null +++ b/android/src/main/java/com/rncamerakit/events/PictureTakenEvent.kt @@ -0,0 +1,22 @@ +package com.rncamerakit.events + +import com.facebook.react.bridge.Arguments +import com.facebook.react.bridge.WritableMap +import com.facebook.react.uimanager.events.Event + +class PictureTakenEvent( + surfaceId: Int, + viewId: Int, + private val uri: String, +) : Event(surfaceId, viewId) { + override fun getEventName(): String = EVENT_NAME + + override fun getEventData(): WritableMap = + Arguments.createMap().apply { + putString("uri", uri) + } + + companion object { + const val EVENT_NAME = "topPictureTaken" + } +} diff --git a/android/src/main/java/com/rncamerakit/events/ReadCodeEvent.kt b/android/src/main/java/com/rncamerakit/events/ReadCodeEvent.kt new file mode 100644 index 0000000000..ff3d3a7465 --- /dev/null +++ b/android/src/main/java/com/rncamerakit/events/ReadCodeEvent.kt @@ -0,0 +1,24 @@ +package com.rncamerakit.events + +import com.facebook.react.bridge.Arguments +import com.facebook.react.bridge.WritableMap +import com.facebook.react.uimanager.events.Event + +class ReadCodeEvent( + surfaceId: Int, + viewId: Int, + private val codeStringValue: String?, + private val codeFormat: String, +) : Event(surfaceId, viewId) { + override fun getEventName(): String = EVENT_NAME + + override fun getEventData(): WritableMap = + Arguments.createMap().apply { + putString("codeFormat", codeFormat) + putString("codeStringValue", codeStringValue) + } + + companion object { + const val EVENT_NAME = "topReadCode" + } +} diff --git a/android/src/main/java/com/rncamerakit/events/ZoomEvent.kt b/android/src/main/java/com/rncamerakit/events/ZoomEvent.kt new file mode 100644 index 0000000000..55626827aa --- /dev/null +++ b/android/src/main/java/com/rncamerakit/events/ZoomEvent.kt @@ -0,0 +1,22 @@ +package com.rncamerakit.events + +import com.facebook.react.bridge.Arguments +import com.facebook.react.bridge.WritableMap +import com.facebook.react.uimanager.events.Event + +class ZoomEvent( + surfaceId: Int, + viewId: Int, + private val zoom: Double, +) : Event(surfaceId, viewId) { + override fun getEventName(): String = EVENT_NAME + + override fun getEventData(): WritableMap = + Arguments.createMap().apply { + putDouble("zoom", zoom) + } + + companion object { + const val EVENT_NAME = "topZoom" + } +} diff --git a/android/src/main/java/com/wix/RNCameraKit/DeviceUtils.java b/android/src/main/java/com/wix/RNCameraKit/DeviceUtils.java deleted file mode 100644 index d04f02eeac..0000000000 --- a/android/src/main/java/com/wix/RNCameraKit/DeviceUtils.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.wix.RNCameraKit; - -import android.os.Build; - -public class DeviceUtils { - public static boolean isGoogleDevice() { - return (Build.MANUFACTURER.toLowerCase().contains("google") && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) || - (Build.MANUFACTURER.toLowerCase().contains("lge") && Build.BRAND.toLowerCase().equals("google")); - } -} diff --git a/android/src/main/java/com/wix/RNCameraKit/RNCameraKitPackage.java b/android/src/main/java/com/wix/RNCameraKit/RNCameraKitPackage.java deleted file mode 100644 index 64e95cc38b..0000000000 --- a/android/src/main/java/com/wix/RNCameraKit/RNCameraKitPackage.java +++ /dev/null @@ -1,67 +0,0 @@ -package com.wix.RNCameraKit; - -import android.support.annotation.Nullable; - -import com.facebook.react.ReactPackage; -import com.facebook.react.bridge.JavaScriptModule; -import com.facebook.react.bridge.NativeModule; -import com.facebook.react.bridge.ReactApplicationContext; -import com.facebook.react.uimanager.ViewManager; -import com.wix.RNCameraKit.camera.CameraModule; -import com.wix.RNCameraKit.camera.CameraViewManager; -import com.wix.RNCameraKit.camera.permission.CameraPermissionRequestCallback; -import com.wix.RNCameraKit.gallery.GalleryViewManager; -import com.wix.RNCameraKit.gallery.NativeGalleryModule; -import com.wix.RNCameraKit.gallery.permission.StoragePermissionRequestCallback; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -public class RNCameraKitPackage implements ReactPackage { - - @Nullable private CameraPermissionRequestCallback cameraPermissionRequestCallback; - @Nullable private StoragePermissionRequestCallback storagePermissionRequestCallback; - - public RNCameraKitPackage() { - - } - - public RNCameraKitPackage(CameraPermissionRequestCallback cameraPermissionRequestCallback, StoragePermissionRequestCallback storagePermissionRequestCallback) { - this.cameraPermissionRequestCallback = cameraPermissionRequestCallback; - this.storagePermissionRequestCallback = storagePermissionRequestCallback; - } - - @Override - public List createNativeModules(ReactApplicationContext reactContext) { - List modules = new ArrayList<>(); - - CameraModule cameraModule = new CameraModule(reactContext); - if (cameraPermissionRequestCallback != null) { - cameraPermissionRequestCallback.setCameraModule(cameraModule); - } - modules.add(cameraModule); - - NativeGalleryModule galleryModule = new NativeGalleryModule(reactContext); - if (storagePermissionRequestCallback != null) { - storagePermissionRequestCallback.setGalleryModule(galleryModule); - } - modules.add(galleryModule); - - return modules; - } - - // Deprecated RN 0.47 - public List> createJSModules() { - return Collections.emptyList(); - } - - @Override - public List createViewManagers(ReactApplicationContext reactContext) { - List viewManagers = new ArrayList<>(); - viewManagers.add(new GalleryViewManager()); - viewManagers.add(new CameraViewManager()); - return viewManagers; - } - -} diff --git a/android/src/main/java/com/wix/RNCameraKit/SaveImageTask.java b/android/src/main/java/com/wix/RNCameraKit/SaveImageTask.java deleted file mode 100644 index 1e7d3198a0..0000000000 --- a/android/src/main/java/com/wix/RNCameraKit/SaveImageTask.java +++ /dev/null @@ -1,260 +0,0 @@ -package com.wix.RNCameraKit; - -import android.content.Context; -import android.database.Cursor; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.graphics.Matrix; -import android.hardware.Camera; -import android.net.Uri; -import android.os.AsyncTask; -import android.provider.MediaStore; -import android.support.annotation.Nullable; -import android.util.Log; -import android.util.Patterns; - -import com.drew.imaging.ImageMetadataReader; -import com.drew.imaging.ImageProcessingException; -import com.drew.metadata.Metadata; -import com.drew.metadata.MetadataException; -import com.drew.metadata.exif.ExifIFD0Directory; -import com.facebook.react.bridge.Arguments; -import com.facebook.react.bridge.Promise; -import com.facebook.react.bridge.WritableMap; -import com.wix.RNCameraKit.camera.CameraViewManager; - -import java.io.BufferedInputStream; -import java.io.ByteArrayInputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.net.URL; - -import static com.facebook.react.common.ReactConstants.TAG; - -public class SaveImageTask extends AsyncTask { - - private final Context context; - private final Promise promise; - private boolean saveToCameraRoll; - private String bitmapUrl = null; - - public SaveImageTask(Context context, Promise promise, boolean saveToCameraRoll) { - this.context = context; - this.promise = promise; - this.saveToCameraRoll = saveToCameraRoll; - } - - public SaveImageTask(String bitmapUrl, Context context, Promise promise, boolean saveToCameraRoll) { - this(context, promise, saveToCameraRoll); - this.bitmapUrl = bitmapUrl; - if (this.bitmapUrl != null) { - this.bitmapUrl = this.bitmapUrl.replace("file://",""); - } - } - - private Bitmap getImageBitmapFromRemoteImageFile() { - Bitmap image; - try { - URL url = new URL(bitmapUrl); - image = BitmapFactory.decodeStream(url.openStream()); - } catch (IOException e) { - image = null; - } - return image; - } - - private Bitmap getImageBitmapFromLocalImageFile() { - Bitmap image; - FileInputStream fis; - File imageFile = new File(bitmapUrl); - try { - fis = new FileInputStream(imageFile); - image = BitmapFactory.decodeStream(fis); - fis.close(); - } catch (IOException e) { - e.printStackTrace(); - image = null; - } - - if (imageFile.exists()) { - imageFile.delete(); - } - return image; - } - - private Bitmap getImageBitmap(byte[]... data) { - Bitmap image; - if (bitmapUrl != null) { - if (Patterns.WEB_URL.matcher(bitmapUrl.toLowerCase()).matches()) { - image = getImageBitmapFromRemoteImageFile(); - } else { - image = getImageBitmapFromLocalImageFile(); - } - } - else { - byte[] rawImageData = data[0]; - image = decodeAndRotateIfNeeded(rawImageData); - } - return image; - } - - @Override - protected Void doInBackground(byte[]... data) { - Bitmap image = getImageBitmap(data); - if (image == null) { - promise.reject("CameraKit", "failed to get Bitmap image"); - return null; - } - - WritableMap imageInfo = saveToCameraRoll ? saveToMediaStore(image) : saveTempImageFile(image); - if (imageInfo == null) - promise.reject("CameraKit", "failed to save image to MediaStore"); - else { - promise.resolve(imageInfo); - CameraViewManager.reconnect(); - } - return null; - } - - private WritableMap createImageInfo(String filePath, String id, String fileName, long fileSize, int width, int height) { - WritableMap imageInfo = Arguments.createMap(); - imageInfo.putString("uri", filePath); - imageInfo.putString("id", id); - imageInfo.putString("name", fileName); - imageInfo.putInt("size", (int) fileSize); - imageInfo.putInt("width", width); - imageInfo.putInt("height", height); - return imageInfo; - } - - private WritableMap saveToMediaStore(Bitmap image) { - try { - String fileUri = MediaStore.Images.Media.insertImage(context.getContentResolver(), image, System.currentTimeMillis() + "", ""); - Cursor cursor = context.getContentResolver().query(Uri.parse(fileUri), new String[]{ - MediaStore.Images.ImageColumns.DATA, - MediaStore.Images.ImageColumns.DISPLAY_NAME - }, null, null, null); - cursor.moveToFirst(); - int pathIndex = cursor.getColumnIndexOrThrow(MediaStore.Images.ImageColumns.DATA); - int nameIndex = cursor.getColumnIndexOrThrow(MediaStore.Images.ImageColumns.DISPLAY_NAME); - String filePath = cursor.getString(pathIndex); - String fileName = cursor.getString(nameIndex); - long fileSize = new File(filePath).length(); - cursor.close(); - - return createImageInfo(filePath, filePath, fileName, fileSize, image.getWidth(), image.getHeight()); - } catch (Exception e) { - return null; - } - } - - private Bitmap decodeAndRotateIfNeeded(byte[] rawImageData) { - Matrix bitmapMatrix = getRotationMatrix(rawImageData); - Bitmap image = BitmapFactory.decodeByteArray(rawImageData, 0, rawImageData.length); - if (bitmapMatrix.isIdentity()) - return image; - else - return rotateImage(image, bitmapMatrix); - } - - private Bitmap rotateImage(Bitmap image, Matrix bitmapMatrix) { - return Bitmap.createBitmap(image, 0, 0, image.getWidth(), image.getHeight(), bitmapMatrix, false); - } - - private Matrix getRotationMatrix(byte[] rawImageData) { - try { - return tryGetRotationMatrix(rawImageData); - } catch (Exception e) { - return new Matrix(); - } - } - - private Matrix tryGetRotationMatrix(byte[] rawImageData) throws ImageProcessingException, IOException, MetadataException { - Matrix matrix = new Matrix(); - Metadata metadata = readMetadata(rawImageData); - final ExifIFD0Directory exifIFD0Directory = metadata.getFirstDirectoryOfType(ExifIFD0Directory.class); - boolean hasOrientation = exifIFD0Directory.containsTag(ExifIFD0Directory.TAG_ORIENTATION); - if (hasOrientation) { - final int exifOrientation = exifIFD0Directory.getInt(ExifIFD0Directory.TAG_ORIENTATION); - boolean isFacingFront = CameraViewManager.getCameraInfo().facing == Camera.CameraInfo.CAMERA_FACING_FRONT; - convertExifOrientationToMatrix(matrix, exifOrientation, isFacingFront); - } - return matrix; - } - - private void convertExifOrientationToMatrix(Matrix matrix, int exifOrientation, boolean isCameraFacingFront) { - switch (exifOrientation) { - case 1: - break; // top left - case 2: - matrix.postScale(-1, 1); - break; // top right - case 3: - matrix.postRotate(180); - break; // bottom right - case 4: - matrix.postRotate(180); - matrix.postScale(-1, 1); - break; // bottom left - case 5: - matrix.postRotate(90); - matrix.postScale(-1, 1); - break; // left top - case 6: - matrix.postRotate(90); - break; // right top - case 7: - matrix.postRotate(270); - matrix.postScale(-1, 1); - break; // right bottom - case 8: - matrix.postRotate(270); - break; // left bottom - default: - break; // Unknown - } - if (isCameraFacingFront) { - matrix.postRotate(180); - } - } - - private Metadata readMetadata(byte[] rawImageData) throws ImageProcessingException, IOException { - Metadata metadata = null; - ByteArrayInputStream inputStream = null; - BufferedInputStream bufferedInputStream = null; - try { - inputStream = new ByteArrayInputStream(rawImageData); - bufferedInputStream = new BufferedInputStream(inputStream); - metadata = ImageMetadataReader.readMetadata(bufferedInputStream, rawImageData.length); - } finally { - if (bufferedInputStream != null) bufferedInputStream.close(); - if (inputStream != null) inputStream.close(); - } - return metadata; - } - - @Nullable - private WritableMap saveTempImageFile(Bitmap image) { - File imageFile; - FileOutputStream outputStream; - - Long tsLong = System.currentTimeMillis()/1000; - String fileName = "temp_Image_" + tsLong.toString() + ".jpg"; - - try { - imageFile = new File(context.getCacheDir(), fileName); - if (imageFile.exists()) { - imageFile.delete(); - } - outputStream = new FileOutputStream(imageFile); - image.compress(Bitmap.CompressFormat.JPEG, 100, outputStream); - outputStream.close(); - } catch (IOException e) { - Log.d(TAG, "Error accessing file: " + e.getMessage()); - imageFile = null; - } - return (imageFile != null) ? createImageInfo(Uri.fromFile(imageFile).toString(), imageFile.getAbsolutePath(), fileName, imageFile.length(), image.getWidth(), image.getHeight()) : null; - } -} diff --git a/android/src/main/java/com/wix/RNCameraKit/SharedPrefs.java b/android/src/main/java/com/wix/RNCameraKit/SharedPrefs.java deleted file mode 100644 index eac3182446..0000000000 --- a/android/src/main/java/com/wix/RNCameraKit/SharedPrefs.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.wix.RNCameraKit; - -import android.content.Context; -import android.content.SharedPreferences; - -// We're saving in shared preferences if a permission was requested since for some unknown reason, -// activitycompat.shouldshowrequestpermissionrationale always returned false -public class SharedPrefs { - public static boolean getBoolean(Context context, String key) { - return prefs(context).getBoolean(key, false); - } - - public static void putBoolean(Context context, String key, boolean value) { - prefs(context).edit().putBoolean(key, value).apply(); - } - - private static SharedPreferences prefs(Context context) { - return context.getSharedPreferences("RN_CAMERA_KIT", Context.MODE_PRIVATE); - } - - -} diff --git a/android/src/main/java/com/wix/RNCameraKit/Utils.java b/android/src/main/java/com/wix/RNCameraKit/Utils.java deleted file mode 100644 index f9e0f10a93..0000000000 --- a/android/src/main/java/com/wix/RNCameraKit/Utils.java +++ /dev/null @@ -1,224 +0,0 @@ -package com.wix.RNCameraKit; - -import android.content.ContentResolver; -import android.content.Context; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.net.Uri; -import android.support.annotation.NonNull; - -import com.facebook.react.bridge.Arguments; -import com.facebook.react.bridge.ReadableArray; -import com.facebook.react.bridge.ReadableMap; -import com.facebook.react.bridge.WritableMap; - -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.util.ArrayList; -import java.util.Date; - -import javax.annotation.Nullable; - -public class Utils { - - private final static String CONTENT_PREFIX = "content://"; - public final static String FILE_PREFIX = "file://"; - private static final int MAX_SAMPLE_SIZE = 8; - private static final float MAX_SCREEN_RATIO = 16 / 9f; - - @Nullable - public static String getStringSafe(ReadableMap map, String key) { - if (map.hasKey(key)) { - return map.getString(key); - } - return null; - } - - public static @Nullable Integer getIntSafe(ReadableMap map, String key) { - if (map.hasKey(key)) { - return map.getInt(key); - } - return null; - } - - public static @Nullable Boolean getBooleanSafe(ReadableMap map, String key) { - if (map.hasKey(key)) { - return map.getBoolean(key); - } - return null; - } - - public static @NonNull ArrayList readableArrayToList(ReadableArray items) { - ArrayList list = new ArrayList<>(); - for(int i = 0; i < items.size(); i++) { - list.add(items.getString(i)); - } - return list; - } - - - @NonNull - public static WritableMap resizeImage(Context context, ReadableMap image, String imageUrlString, int maxResolution, int compressionQuality) throws IOException { - Bitmap sourceImage; - sourceImage = Utils.loadBitmapFromFile(context, imageUrlString, maxResolution, maxResolution); - - if (sourceImage == null) { - throw new IOException("Unable to load source image from path"); - } - - Bitmap scaledImage = Utils.resizeImage(sourceImage, maxResolution, maxResolution); - if (sourceImage != scaledImage) { - sourceImage.recycle(); - } - - // Save the resulting image - File path = context.getCacheDir(); - String resizedImagePath = Utils.saveImage(scaledImage, path, Long.toString(new Date().getTime()), Bitmap.CompressFormat.JPEG, compressionQuality); - - // Clean up remaining image - scaledImage.recycle(); - - WritableMap ans = Arguments.createMap(); - ans.merge(image); - ans.putString("uri", FILE_PREFIX+resizedImagePath); - ans.putInt("size", (int)new File(resizedImagePath).length()); - ans.putInt("width", scaledImage.getWidth()); - ans.putInt("height", scaledImage.getHeight()); - return ans; - } - - - /** - * Resize the specified bitmap, keeping its aspect ratio. - */ - private static Bitmap resizeImage(Bitmap image, int maxWidth, int maxHeight) { - Bitmap newImage = null; - if (image == null) { - return null; // Can't load the image from the given path. - } - - if (maxHeight > 0 && maxWidth > 0) { - float width = image.getWidth(); - float height = image.getHeight(); - - float ratio = Math.min((float)maxWidth / width, (float)maxHeight / height); - - int finalWidth = (int) (width * ratio); - int finalHeight = (int) (height * ratio); - newImage = Bitmap.createScaledBitmap(image, finalWidth, finalHeight, true); - } - - return newImage; - } - - - /** - * Compute the inSampleSize value to use to load a bitmap. - * Adapted from https://developer.android.com/training/displaying-bitmaps/load-bitmap.html - */ - public static int calculateInSampleSize(int width, int height, int reqWidth, int reqHeight) { - - if (reqHeight == 0 || reqWidth == 0) { - return 1; - } - - int inSampleSize = 1; - - if (height > reqHeight || width > reqWidth) { - - final int halfHeight = height / 2; - final int halfWidth = width / 2; - - while (inSampleSize <= MAX_SAMPLE_SIZE - && (halfHeight / inSampleSize) >= reqHeight - && (halfWidth / inSampleSize) >= reqWidth) { - inSampleSize *= 2; - } - } - - return inSampleSize; - } - - private static Bitmap loadBitmap(Context context, String imagePath, BitmapFactory.Options options) throws IOException { - Bitmap sourceImage = null; - if (!imagePath.startsWith(CONTENT_PREFIX)) { - try { - sourceImage = BitmapFactory.decodeFile(imagePath, options); - } catch (Exception e) { - e.printStackTrace(); - throw new IOException("Error decoding image file"); - } - } else { - ContentResolver cr = context.getContentResolver(); - InputStream input = cr.openInputStream(Uri.parse(imagePath)); - if (input != null) { - sourceImage = BitmapFactory.decodeStream(input, null, options); - input.close(); - } - } - return sourceImage; - } - - /** - * Loads the bitmap resource from the file specified in imagePath. - */ - private static Bitmap loadBitmapFromFile(Context context, String imagePath, int newWidth, - int newHeight) throws IOException { - // Decode the image bounds to find the size of the source image. - BitmapFactory.Options options = new BitmapFactory.Options(); - options.inJustDecodeBounds = true; - loadBitmap(context, imagePath, options); - - // Set a sample size according to the image size to lower memory usage. - options.inSampleSize = calculateInSampleSize(options.outWidth, options.outHeight , newWidth, newHeight); - options.inJustDecodeBounds = false; - return loadBitmap(context, imagePath, options); - } - - - /** - * Save the given bitmap in a directory. Extension is automatically generated using the bitmap format. - */ - private static String saveImage(Bitmap bitmap, File saveDirectory, String fileName, - Bitmap.CompressFormat compressFormat, int quality) - throws IOException { - if (bitmap == null) { - throw new IOException("The bitmap couldn't be resized"); - } - - File newFile = new File(saveDirectory, fileName + "." + compressFormat.name()); - if(!newFile.createNewFile()) { - throw new IOException("The file already exists"); - } - - ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); - bitmap.compress(compressFormat, quality, outputStream); - byte[] bitmapData = outputStream.toByteArray(); - - outputStream.flush(); - outputStream.close(); - - FileOutputStream fos = new FileOutputStream(newFile); - fos.write(bitmapData); - fos.flush(); - fos.close(); - - return newFile.getAbsolutePath(); - } - - /** - * Since Camera API 1 doesn't support the new 18:9 and 18.5:9 screen aspect ratio, we convert to the - * max supported aspect ratio - 16:9 - */ - public static int convertDeviceHeightToSupportedAspectRatio(float actualWidth, float actualHeight) { - return (int) (actualHeight / actualWidth > MAX_SCREEN_RATIO ? actualWidth * MAX_SCREEN_RATIO : actualHeight); - } - - - public static void runOnWorkerThread(Runnable runnable) { - new Thread(runnable).start(); - } -} diff --git a/android/src/main/java/com/wix/RNCameraKit/camera/CameraModule.java b/android/src/main/java/com/wix/RNCameraKit/camera/CameraModule.java deleted file mode 100644 index 3cf1c2dd72..0000000000 --- a/android/src/main/java/com/wix/RNCameraKit/camera/CameraModule.java +++ /dev/null @@ -1,116 +0,0 @@ -package com.wix.RNCameraKit.camera; - -import android.hardware.Camera; - -import com.facebook.react.bridge.LifecycleEventListener; -import com.facebook.react.bridge.Promise; -import com.facebook.react.bridge.ReactApplicationContext; -import com.facebook.react.bridge.ReactContextBaseJavaModule; -import com.facebook.react.bridge.ReactMethod; -import com.wix.RNCameraKit.camera.commands.Capture; -import com.wix.RNCameraKit.camera.permission.CameraPermission; - - -public class CameraModule extends ReactContextBaseJavaModule { - - private final CameraPermission cameraPermission; - private Promise checkPermissionStatusPromise; - - public CameraModule(ReactApplicationContext reactContext) { - super(reactContext); - cameraPermission = new CameraPermission(); - checkPermissionWhenActivityIsAvailable(); - } - - private void checkPermissionWhenActivityIsAvailable() { - getReactApplicationContext().addLifecycleEventListener(new LifecycleEventListener() { - @Override - public void onHostResume() { - if (checkPermissionStatusPromise != null && getCurrentActivity() != null) { - getCurrentActivity().runOnUiThread(new Runnable() { - @Override - public void run() { - checkPermissionStatusPromise.resolve(cameraPermission.checkAuthorizationStatus(getCurrentActivity())); - checkPermissionStatusPromise = null; - } - }); - } - } - - @Override - public void onHostPause() { - - } - - @Override - public void onHostDestroy() { - - } - }); - } - - @Override - public String getName() { - return "CameraModule"; - } - - @ReactMethod - public void checkDeviceCameraAuthorizationStatus(Promise promise) { - if (getCurrentActivity() == null) { - checkPermissionStatusPromise = promise; - } else { - promise.resolve(cameraPermission.checkAuthorizationStatus(getCurrentActivity())); - } - } - - @ReactMethod - public void requestDeviceCameraAuthorization(Promise promise) { - cameraPermission.requestAccess(getCurrentActivity(), promise); - } - - @ReactMethod - public void hasFrontCamera(Promise promise) { - - int numCameras = Camera.getNumberOfCameras(); - for (int i = 0; i < numCameras; i++) { - Camera.CameraInfo info = new Camera.CameraInfo(); - Camera.getCameraInfo(i, info); - if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) { - promise.resolve(true); - return; - } - } - promise.resolve(false); - } - - @ReactMethod - public void hasFlashForCurrentCamera(Promise promise) { - Camera camera = CameraViewManager.getCamera(); - promise.resolve(camera.getParameters().getSupportedFlashModes() != null); - } - - @ReactMethod - public void changeCamera(Promise promise) { - promise.resolve(CameraViewManager.changeCamera()); - } - - @ReactMethod - public void setFlashMode(String mode, Promise promise) { - promise.resolve(CameraViewManager.setFlashMode(mode)); - } - - @ReactMethod - public void getFlashMode(Promise promise) { - Camera camera = CameraViewManager.getCamera(); - promise.resolve(camera.getParameters().getFlashMode()); - } - - @ReactMethod - public void capture(boolean saveToCameraRoll, final Promise promise) { - new Capture(getReactApplicationContext(), saveToCameraRoll).execute(promise); - } - - public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { - cameraPermission.onRequestPermissionsResult(requestCode, permissions, grantResults); - } -} diff --git a/android/src/main/java/com/wix/RNCameraKit/camera/CameraView.java b/android/src/main/java/com/wix/RNCameraKit/camera/CameraView.java deleted file mode 100644 index 0821bbcf83..0000000000 --- a/android/src/main/java/com/wix/RNCameraKit/camera/CameraView.java +++ /dev/null @@ -1,141 +0,0 @@ -package com.wix.RNCameraKit.camera; - -import android.graphics.Color; -import android.graphics.Rect; -import android.support.annotation.ColorInt; -import android.view.SurfaceHolder; -import android.view.SurfaceView; -import android.view.View; -import android.widget.FrameLayout; - -import com.facebook.react.uimanager.ThemedReactContext; -import com.wix.RNCameraKit.Utils; -import com.wix.RNCameraKit.camera.barcode.BarcodeFrame; - -import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; - -public class CameraView extends FrameLayout implements SurfaceHolder.Callback { - private SurfaceView surface; - - private boolean showFrame; - private Rect frameRect; - private BarcodeFrame barcodeFrame; - @ColorInt private int frameColor = Color.GREEN; - @ColorInt private int laserColor = Color.RED; - - public CameraView(ThemedReactContext context) { - super(context); - surface = new SurfaceView(context); - setBackgroundColor(Color.BLACK); - addView(surface, MATCH_PARENT, MATCH_PARENT); - surface.getHolder().addCallback(this); - } - - @Override - protected void onLayout(boolean changed, int left, int top, int right, int bottom) { - int actualPreviewWidth = getResources().getDisplayMetrics().widthPixels; - int actualPreviewHeight = getResources().getDisplayMetrics().heightPixels; - int height = Utils.convertDeviceHeightToSupportedAspectRatio(actualPreviewWidth, actualPreviewHeight); - surface.layout(0, 0, actualPreviewWidth, height); - if (barcodeFrame != null) { - ((View) barcodeFrame).layout(0, 0, actualPreviewWidth, height); - } - } - - @Override - public void surfaceCreated(SurfaceHolder holder) { - CameraViewManager.setCameraView(this); - } - - @Override - public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { - CameraViewManager.setCameraView(this); - } - - @Override - public void surfaceDestroyed(SurfaceHolder holder) { - CameraViewManager.removeCameraView(); - } - - - public SurfaceHolder getHolder() { - return surface.getHolder(); - } - - private final Runnable measureAndLayout = new Runnable() { - @Override - public void run() { - measure( - MeasureSpec.makeMeasureSpec(getWidth(), MeasureSpec.EXACTLY), - MeasureSpec.makeMeasureSpec(getHeight(), MeasureSpec.EXACTLY)); - layout(getLeft(), getTop(), getRight(), getBottom()); - } - }; - - @Override - public void requestLayout() { - super.requestLayout(); - post(measureAndLayout); - } - - public void setShowFrame(boolean showFrame) { - this.showFrame = showFrame; - } - - public void showFrame() { - if (showFrame) { - barcodeFrame = new BarcodeFrame(getContext()); - barcodeFrame.setFrameColor(frameColor); - barcodeFrame.setLaserColor(laserColor); - addView(barcodeFrame); - requestLayout(); - } - } - - public Rect getFramingRectInPreview(int previewWidth, int previewHeight) { - if (frameRect == null) { - if (barcodeFrame != null) { - Rect framingRect = new Rect(barcodeFrame.getFrameRect()); - int frameWidth = barcodeFrame.getWidth(); - int frameHeight = barcodeFrame.getHeight(); - - if (previewWidth < frameWidth) { - framingRect.left = framingRect.left * previewWidth / frameWidth; - framingRect.right = framingRect.right * previewWidth / frameWidth; - } - if (previewHeight < frameHeight) { - framingRect.top = framingRect.top * previewHeight / frameHeight; - framingRect.bottom = framingRect.bottom * previewHeight / frameHeight; - } - - frameRect = framingRect; - } else { - frameRect = new Rect(0, 0, previewWidth, previewHeight); - } - } - return frameRect; - } - - public void setFrameColor(@ColorInt int color) { - this.frameColor = color; - if (barcodeFrame != null) { - barcodeFrame.setFrameColor(color); - } - } - - public void setLaserColor(@ColorInt int color) { - this.laserColor = color; - if (barcodeFrame != null) { - barcodeFrame.setLaserColor(laserColor); - } - } - - /** - * Set background color for Surface view on the period, while camera is not loaded yet. - * Provides opportunity for user to hide period while camera is loading - * @param color - color of the surfaceview - */ - public void setSurfaceBgColor(@ColorInt int color) { - surface.setBackgroundColor(color); - } -} diff --git a/android/src/main/java/com/wix/RNCameraKit/camera/CameraViewManager.java b/android/src/main/java/com/wix/RNCameraKit/camera/CameraViewManager.java deleted file mode 100644 index 0e37c4cace..0000000000 --- a/android/src/main/java/com/wix/RNCameraKit/camera/CameraViewManager.java +++ /dev/null @@ -1,338 +0,0 @@ -package com.wix.RNCameraKit.camera; - -import android.content.Context; -import android.graphics.Color; -import android.graphics.PixelFormat; -import android.graphics.Point; -import android.graphics.Rect; -import android.hardware.Camera; -import android.hardware.SensorManager; -import android.support.annotation.ColorInt; -import android.support.annotation.IntRange; -import android.view.Display; -import android.view.OrientationEventListener; -import android.view.WindowManager; - -import com.facebook.react.bridge.Arguments; -import com.facebook.react.bridge.WritableMap; -import com.facebook.react.common.MapBuilder; -import com.facebook.react.uimanager.SimpleViewManager; -import com.facebook.react.uimanager.ThemedReactContext; -import com.facebook.react.uimanager.annotations.ReactProp; -import com.facebook.react.uimanager.events.RCTEventEmitter; -import com.google.zxing.Result; -import com.wix.RNCameraKit.Utils; -import com.wix.RNCameraKit.camera.barcode.BarcodeScanner; - -import java.io.IOException; -import java.util.List; -import java.util.Map; -import java.util.Stack; -import java.util.concurrent.atomic.AtomicBoolean; - -import javax.annotation.Nullable; - -import static com.wix.RNCameraKit.camera.Orientation.getSupportedRotation; - -@SuppressWarnings("MagicNumber deprecation") -// We're still using Camera API 1, everything is deprecated -public class CameraViewManager extends SimpleViewManager { - - private static Camera camera = null; - private static int currentCamera = 0; - private static String flashMode = Camera.Parameters.FLASH_MODE_AUTO; - private static Stack cameraViews = new Stack<>(); - private static ThemedReactContext reactContext; - private static OrientationEventListener orientationListener; - private static int currentRotation = 0; - private static AtomicBoolean cameraReleased = new AtomicBoolean(false); - - private static boolean shouldScan = false; - - private static BarcodeScanner scanner; - private static Camera.PreviewCallback previewCallback = new Camera.PreviewCallback() { - @Override - public void onPreviewFrame(final byte[] data, final Camera camera) { - Utils.runOnWorkerThread(new Runnable() { - @Override - public void run() { - if (scanner != null) { - scanner.onPreviewFrame(data, camera); - } - } - }); - } - }; - - public static Camera getCamera() { - return camera; - } - - @Override - public String getName() { - return "CameraView"; - } - - @Override - protected CameraView createViewInstance(ThemedReactContext reactContext) { - CameraViewManager.reactContext = reactContext; - return new CameraView(reactContext); - } - - static void setCameraView(CameraView cameraView) { - if (!cameraViews.isEmpty() && cameraViews.peek() == cameraView) return; - CameraViewManager.cameraViews.push(cameraView); - connectHolder(); - createOrientationListener(); - } - - private static void createOrientationListener() { - if (orientationListener != null) return; - orientationListener = new OrientationEventListener(reactContext, SensorManager.SENSOR_DELAY_NORMAL) { - @Override - public void onOrientationChanged(@IntRange(from = -1, to = 359) int angle) { - if (angle == OrientationEventListener.ORIENTATION_UNKNOWN) return; - setCameraRotation(359 - angle, false); - } - }; - orientationListener.enable(); - } - - static boolean setFlashMode(String mode) { - if (camera == null) { - return false; - } - Camera.Parameters parameters = camera.getParameters(); - List supportedModes = parameters.getSupportedFlashModes(); - if (supportedModes != null && supportedModes.contains(mode)) { - flashMode = mode; - parameters.setFlashMode(flashMode); - camera.setParameters(parameters); - camera.startPreview(); - return true; - } else { - return false; - } - } - - static boolean changeCamera() { - if (Camera.getNumberOfCameras() == 1) { - return false; - } - currentCamera++; - currentCamera = currentCamera % Camera.getNumberOfCameras(); - initCamera(); - connectHolder(); - - return true; - } - - private static void initCamera() { - if (camera != null) { - releaseCamera(); - } - try { - camera = Camera.open(currentCamera); - updateCameraSize(); - cameraReleased.set(false); - setCameraRotation(currentRotation, true); - } catch (RuntimeException e) { - e.printStackTrace(); - } - setBarcodeScanner(); - } - - private static void releaseCamera() { - camera.setOneShotPreviewCallback(null); - cameraReleased.set(true); - camera.release(); - } - - private static void connectHolder() { - if (cameraViews.isEmpty() || cameraViews.peek().getHolder() == null) return; - - new Thread(new Runnable() { - @Override - public void run() { - if (camera == null) { - initCamera(); - } - - if (cameraViews.isEmpty()) { - return; - } - - cameraViews.peek().post(new Runnable() { - @Override - public void run() { - try { - camera.stopPreview(); - camera.setPreviewDisplay(cameraViews.peek().getHolder()); - camera.startPreview(); - if (shouldScan) { - camera.setOneShotPreviewCallback(previewCallback); - } - cameraViews.peek().setSurfaceBgColor(Color.TRANSPARENT); - cameraViews.peek().showFrame(); - } catch (IOException | RuntimeException e) { - e.printStackTrace(); - } - } - }); - } - }).start(); - } - - static void removeCameraView() { - if (!cameraViews.isEmpty()) { - cameraViews.pop(); - } - if (!cameraViews.isEmpty()) { - connectHolder(); - } else if (camera != null) { - releaseCamera(); - camera = null; - } - if (cameraViews.isEmpty()) { - clearOrientationListener(); - } - } - - private static void clearOrientationListener() { - if (orientationListener != null) { - orientationListener.disable(); - orientationListener = null; - } - } - - private static void setCameraRotation(int rotation, boolean force) { - if (camera == null) return; - int supportedRotation = getSupportedRotation(rotation); - if (supportedRotation == currentRotation && !force) return; - currentRotation = supportedRotation; - - if (cameraReleased.get()) return; - Camera.Parameters parameters = camera.getParameters(); - parameters.setRotation(supportedRotation); - parameters.setPictureFormat(PixelFormat.JPEG); - camera.setDisplayOrientation(Orientation.getDeviceOrientation(reactContext.getCurrentActivity())); - camera.setParameters(parameters); - } - - public static Camera.CameraInfo getCameraInfo() { - Camera.CameraInfo info = new Camera.CameraInfo(); - Camera.getCameraInfo(currentCamera, info); - return info; - } - - private static Camera.Size getOptimalPreviewSize(List sizes, int w, int h) { - final double ASPECT_TOLERANCE = 0.15; - double targetRatio = (double) h / w; - if (sizes == null) return null; - Camera.Size optimalSize = null; - double minDiff = Double.MAX_VALUE; - for (Camera.Size size : sizes) { - double ratio = (double) size.width / size.height; - if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE) continue; - if (Math.abs(size.height - h) < minDiff) { - optimalSize = size; - minDiff = Math.abs(size.height - h); - } - } - if (optimalSize == null) { - minDiff = Double.MAX_VALUE; - for (Camera.Size size : sizes) { - if (Math.abs(size.height - h) < minDiff) { - optimalSize = size; - minDiff = Math.abs(size.height - h); - } - } - } - return optimalSize; - } - - private static void updateCameraSize() { - try { - Camera camera = CameraViewManager.getCamera(); - - WindowManager wm = (WindowManager) reactContext.getSystemService(Context.WINDOW_SERVICE); - Display display = wm.getDefaultDisplay(); - Point size = new Point(); - display.getSize(size); - size.y = Utils.convertDeviceHeightToSupportedAspectRatio(size.x, size.y); - if (camera == null) return; - List supportedPreviewSizes = camera.getParameters().getSupportedPreviewSizes(); - List supportedPictureSizes = camera.getParameters().getSupportedPictureSizes(); - Camera.Size optimalSize = getOptimalPreviewSize(supportedPreviewSizes, size.x, size.y); - Camera.Size optimalPictureSize = getOptimalPreviewSize(supportedPictureSizes, size.x, size.y); - Camera.Parameters parameters = camera.getParameters(); - parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE); - parameters.setPreviewSize(optimalSize.width, optimalSize.height); - parameters.setPictureSize(optimalPictureSize.width, optimalPictureSize.height); - parameters.setFlashMode(flashMode); - camera.setParameters(parameters); - } catch (RuntimeException ignored) { - } - } - - public static void reconnect() { - connectHolder(); - } - - public static int getRotationCount() { - return currentRotation / 90; - } - - public static void setBarcodeScanner() { - scanner = new BarcodeScanner(previewCallback, new BarcodeScanner.ResultHandler() { - @Override - public void handleResult(Result result) { - WritableMap event = Arguments.createMap(); - event.putString("codeStringValue", result.getText()); - if (!cameraViews.empty()) - reactContext.getJSModule(RCTEventEmitter.class).receiveEvent(cameraViews.peek().getId(), "onReadCode", event); - } - }); - } - - @Nullable - @Override - public Map getExportedCustomDirectEventTypeConstants() { - return MapBuilder.builder() - .put("onReadCode", - MapBuilder.of("registrationName", "onReadCode")) - .build(); - } - - @ReactProp(name = "scanBarcode") - public void setShouldScan(CameraView view, boolean scanBarcode) { - shouldScan = scanBarcode; - if (shouldScan && camera != null) { - camera.setOneShotPreviewCallback(previewCallback); - } - } - - @ReactProp(name = "showFrame", defaultBoolean = false) - public void setFrame(CameraView view, boolean show) { - view.setShowFrame(show); - } - - @ReactProp(name = "frameColor", defaultInt = Color.GREEN) - public void setFrameColor(CameraView view, @ColorInt int color) { - view.setFrameColor(color); - } - - @ReactProp(name = "laserColor", defaultInt = Color.RED) - public void setLaserColor(CameraView view, @ColorInt int color) { - view.setLaserColor(color); - } - - @ReactProp(name = "surfaceColor") - public void setSurfaceBackground(CameraView view, @ColorInt int color) { - view.setSurfaceBgColor(color); - } - - public static synchronized Rect getFramingRectInPreview(int previewWidth, int previewHeight) { - return cameraViews.peek().getFramingRectInPreview(previewWidth, previewHeight); - } -} diff --git a/android/src/main/java/com/wix/RNCameraKit/camera/Orientation.java b/android/src/main/java/com/wix/RNCameraKit/camera/Orientation.java deleted file mode 100644 index 1850d6a684..0000000000 --- a/android/src/main/java/com/wix/RNCameraKit/camera/Orientation.java +++ /dev/null @@ -1,74 +0,0 @@ -package com.wix.RNCameraKit.camera; - -import android.app.Activity; -import android.hardware.Camera; -import android.view.Surface; - -import com.wix.RNCameraKit.DeviceUtils; - -import static com.wix.RNCameraKit.camera.CameraViewManager.getCameraInfo; - -@SuppressWarnings({"MagicNumber", "deprecation"}) -class Orientation { - private static final int PORTRAIT_ROTATION = 90; - - static int getDeviceOrientation(Activity activity) { - if (activity == null) return PORTRAIT_ROTATION; - int rotation = activity.getWindowManager().getDefaultDisplay().getRotation(); - Camera.CameraInfo info = getCameraInfo(); - int degrees = 0; - switch (rotation) { - case Surface.ROTATION_0: degrees = 0; break; - case Surface.ROTATION_90: degrees = 90; break; - case Surface.ROTATION_180: degrees = 180; break; - case Surface.ROTATION_270: degrees = 270; break; - } - - int result; - if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) { - result = (info.orientation + degrees) % 360; - result = (360 - result) % 360; // compensate the mirror - } else { // back-facing - result = (info.orientation - degrees + 360) % 360; - } - return result; - } - - static int getSupportedRotation(int rotation) { - int degrees = convertRotationToSupportedAxis(rotation); - return isFrontFacingCamera() ? adaptFrontCamera(degrees) : adaptBackCamera(degrees); - } - - private static int convertRotationToSupportedAxis(int rotation) { - if (rotation < 45) { - return 0; - } else if (rotation < 135) { - return 90; - } else if (rotation < 225) { - return 180; - } else if (rotation < 315){ - return 270; - } - return 0; - } - - private static boolean isFrontFacingCamera() { - return getCameraInfo().facing == Camera.CameraInfo.CAMERA_FACING_FRONT; - } - - private static int adaptBackCamera(int degrees) { - return (getCameraInfo().orientation - degrees + 360) % 360; - } - - private static int adaptFrontCamera(int degrees) { - if (DeviceUtils.isGoogleDevice()) { - int result = (getCameraInfo().orientation + degrees) % 360; - result = (result) % 360; // compensate the mirror - return result; - } else { - int result = (getCameraInfo().orientation + degrees + 180) % 360; - result = (result) % 360; // compensate the mirror - return result; - } - } -} diff --git a/android/src/main/java/com/wix/RNCameraKit/camera/barcode/BarcodeFrame.java b/android/src/main/java/com/wix/RNCameraKit/camera/barcode/BarcodeFrame.java deleted file mode 100644 index b4646d78b1..0000000000 --- a/android/src/main/java/com/wix/RNCameraKit/camera/barcode/BarcodeFrame.java +++ /dev/null @@ -1,110 +0,0 @@ -package com.wix.RNCameraKit.camera.barcode; - -import android.content.Context; -import android.graphics.Canvas; -import android.graphics.Paint; -import android.graphics.PorterDuff; -import android.graphics.PorterDuffXfermode; -import android.graphics.Rect; -import android.support.annotation.ColorInt; -import android.view.View; - -import com.wix.RNCameraKit.R; - -public class BarcodeFrame extends View { - - private static final int STROKE_WIDTH = 5; - private static final int ANIMATION_SPEED = 8; - private static final int WIDTH_SCALE = 7; - private static final double HEIGHT_SCALE = 2.75; - - private Paint dimPaint; - private Paint framePaint; - private Paint borderPaint; - private Paint laserPaint; - private Rect frameRect; - private int width; - private int height; - private int borderMargin; - - private long previousFrameTime = System.currentTimeMillis(); - private int laserY; - - public BarcodeFrame(Context context) { - super(context); - init(context); - } - - private void init(Context context) { - framePaint = new Paint(); - framePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); - dimPaint = new Paint(); - dimPaint.setStyle(Paint.Style.FILL); - dimPaint.setColor(context.getResources().getColor(R.color.bg_dark)); - borderPaint = new Paint(); - borderPaint.setStyle(Paint.Style.STROKE); - borderPaint.setStrokeWidth(STROKE_WIDTH); - laserPaint = new Paint(); - laserPaint.setStyle(Paint.Style.STROKE); - laserPaint.setStrokeWidth(STROKE_WIDTH); - - frameRect = new Rect(); - borderMargin = context.getResources().getDimensionPixelSize(R.dimen.border_length); - } - - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - super.onMeasure(widthMeasureSpec, heightMeasureSpec); - - width = getMeasuredWidth(); - height = getMeasuredHeight(); - int marginWidth = width / WIDTH_SCALE; - int marginHeight = (int) (height / HEIGHT_SCALE); - - frameRect.left = marginWidth; - frameRect.right = width - marginWidth; - frameRect.top = marginHeight; - frameRect.bottom = height - marginHeight; - } - - @Override - protected void onDraw(Canvas canvas) { - long timeElapsed = (System.currentTimeMillis() - previousFrameTime); - super.onDraw(canvas); - canvas.drawRect(0, 0, width, height, dimPaint); - canvas.drawRect(frameRect, framePaint); - drawBorder(canvas); - drawLaser(canvas, timeElapsed); - previousFrameTime = System.currentTimeMillis(); - this.invalidate(frameRect); - } - - private void drawBorder(Canvas canvas) { - canvas.drawLine(frameRect.left, frameRect.top, frameRect.left, frameRect.top + borderMargin, borderPaint); - canvas.drawLine(frameRect.left, frameRect.top, frameRect.left + borderMargin, frameRect.top, borderPaint); - canvas.drawLine(frameRect.left, frameRect.bottom, frameRect.left, frameRect.bottom - borderMargin, borderPaint); - canvas.drawLine(frameRect.left, frameRect.bottom, frameRect.left + borderMargin, frameRect.bottom, borderPaint); - canvas.drawLine(frameRect.right, frameRect.top, frameRect.right - borderMargin, frameRect.top, borderPaint); - canvas.drawLine(frameRect.right, frameRect.top, frameRect.right, frameRect.top + borderMargin, borderPaint); - canvas.drawLine(frameRect.right, frameRect.bottom, frameRect.right, frameRect.bottom - borderMargin, borderPaint); - canvas.drawLine(frameRect.right, frameRect.bottom, frameRect.right - borderMargin, frameRect.bottom, borderPaint); - } - - private void drawLaser(Canvas canvas, long timeElapsed) { - if (laserY > frameRect.bottom || laserY < frameRect.top) laserY = frameRect.top; - canvas.drawLine(frameRect.left + STROKE_WIDTH, laserY, frameRect.right - STROKE_WIDTH, laserY, laserPaint); - laserY += (timeElapsed) / ANIMATION_SPEED; - } - - public Rect getFrameRect() { - return frameRect; - } - - public void setFrameColor(@ColorInt int borderColor) { - borderPaint.setColor(borderColor); - } - - public void setLaserColor(@ColorInt int laserColor) { - laserPaint.setColor(laserColor); - } -} diff --git a/android/src/main/java/com/wix/RNCameraKit/camera/barcode/BarcodeScanner.java b/android/src/main/java/com/wix/RNCameraKit/camera/barcode/BarcodeScanner.java deleted file mode 100644 index 08a59119bb..0000000000 --- a/android/src/main/java/com/wix/RNCameraKit/camera/barcode/BarcodeScanner.java +++ /dev/null @@ -1,145 +0,0 @@ -package com.wix.RNCameraKit.camera.barcode; - - -import android.graphics.Rect; -import android.hardware.Camera; -import android.os.Handler; -import android.os.Looper; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.util.Log; - -import com.google.zxing.BarcodeFormat; -import com.google.zxing.BinaryBitmap; -import com.google.zxing.DecodeHintType; -import com.google.zxing.LuminanceSource; -import com.google.zxing.MultiFormatReader; -import com.google.zxing.ReaderException; -import com.google.zxing.Result; -import com.google.zxing.common.HybridBinarizer; -import com.wix.RNCameraKit.camera.CameraViewManager; - -import java.util.ArrayList; -import java.util.EnumMap; -import java.util.List; -import java.util.Map; - -public class BarcodeScanner { - - public interface ResultHandler { - void handleResult(Result result); - } - - private MultiFormatReader mMultiFormatReader; - private static final List ALL_FORMATS = new ArrayList<>(); - private ResultHandler resultHandler; - - private Camera.PreviewCallback previewCallback; - - static { - ALL_FORMATS.add(BarcodeFormat.AZTEC); - ALL_FORMATS.add(BarcodeFormat.CODABAR); - ALL_FORMATS.add(BarcodeFormat.CODE_39); - ALL_FORMATS.add(BarcodeFormat.CODE_93); - ALL_FORMATS.add(BarcodeFormat.CODE_128); - ALL_FORMATS.add(BarcodeFormat.DATA_MATRIX); - ALL_FORMATS.add(BarcodeFormat.EAN_8); - ALL_FORMATS.add(BarcodeFormat.EAN_13); - ALL_FORMATS.add(BarcodeFormat.ITF); - ALL_FORMATS.add(BarcodeFormat.MAXICODE); - ALL_FORMATS.add(BarcodeFormat.PDF_417); - ALL_FORMATS.add(BarcodeFormat.QR_CODE); - ALL_FORMATS.add(BarcodeFormat.RSS_14); - ALL_FORMATS.add(BarcodeFormat.RSS_EXPANDED); - ALL_FORMATS.add(BarcodeFormat.UPC_A); - ALL_FORMATS.add(BarcodeFormat.UPC_E); - ALL_FORMATS.add(BarcodeFormat.UPC_EAN_EXTENSION); - } - - public BarcodeScanner(@NonNull Camera.PreviewCallback previewCallback, @NonNull ResultHandler resultHandler) { - Map hints = new EnumMap<>(DecodeHintType.class); - hints.put(DecodeHintType.POSSIBLE_FORMATS, ALL_FORMATS); - mMultiFormatReader = new MultiFormatReader(); - mMultiFormatReader.setHints(hints); - - this.previewCallback = previewCallback; - this.resultHandler = resultHandler; - } - - public void onPreviewFrame(byte[] data, final Camera camera) { - try { - Camera.Size size = camera.getParameters().getPreviewSize(); - int width = size.width; - int height = size.height; - - int tmp = width; - width = height; - height = tmp; - data = getRotatedData(data, camera); - - final Result result = decodeResult(getLuminanceSource(data, width, height)); - - if (result != null) { - new Handler(Looper.getMainLooper()).post(new Runnable() { - @Override - public void run() { - resultHandler.handleResult(result); - } - }); - } - camera.setOneShotPreviewCallback(previewCallback); - } catch (RuntimeException e) { - Log.w("CameraKit", e.toString()); - } - } - - @Nullable - private Result decodeResult(LuminanceSource source) { - Result rawResult = null; - if (source != null) { - BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source)); - try { - rawResult = mMultiFormatReader.decodeWithState(bitmap); - } catch (ReaderException ignored) { - } finally { - mMultiFormatReader.reset(); - } - - if (rawResult == null && source.isRotateSupported()) { - LuminanceSource rotatedSource = source.rotateCounterClockwise(); - bitmap = new BinaryBitmap(new HybridBinarizer(rotatedSource)); - try { - rawResult = mMultiFormatReader.decodeWithState(bitmap); - } catch (ReaderException ignored) { - } finally { - mMultiFormatReader.reset(); - } - } - } - return rawResult; - } - - private LuminanceSource getLuminanceSource(byte[] data, int width, int height) { - Rect rect = CameraViewManager.getFramingRectInPreview(width, height); - try { - return new RotateLuminanceSource(data, width, height, rect.left, rect.top, - rect.width(), rect.height(), false); - } catch (Exception e) { - e.printStackTrace(); - } - return null; - } - - private byte[] getRotatedData(byte[] data, Camera camera) { - Camera.Size size = camera.getParameters().getPreviewSize(); - int width = size.width; - int height = size.height; - - byte[] rotatedData = new byte[data.length]; - for (int y = 0; y < height; y++) { - for (int x = 0; x < width; x++) - rotatedData[x * height + height - y - 1] = data[x + y * width]; - } - return rotatedData; - } -} diff --git a/android/src/main/java/com/wix/RNCameraKit/camera/barcode/RotateLuminanceSource.java b/android/src/main/java/com/wix/RNCameraKit/camera/barcode/RotateLuminanceSource.java deleted file mode 100644 index a76a1f4726..0000000000 --- a/android/src/main/java/com/wix/RNCameraKit/camera/barcode/RotateLuminanceSource.java +++ /dev/null @@ -1,164 +0,0 @@ -package com.wix.RNCameraKit.camera.barcode; - -import com.google.zxing.LuminanceSource; - -/** - * This class is mostly copy of {@link com.google.zxing.PlanarYUVLuminanceSource} class. - * The only difference is adding {@code rotateCounterClockwise()} method - * It was copied due to PlanarYUVLuminanceSource being final, so it can not be extended - * Zxing license - {https://github.com/zxing/zxing/blob/master/LICENSE} - */ -public class RotateLuminanceSource extends LuminanceSource { - - private static final int THUMBNAIL_SCALE_FACTOR = 2; - - private final byte[] yuvData; - private final int dataWidth; - private final int dataHeight; - private final int left; - private final int top; - - RotateLuminanceSource(byte[] yuvData, - int dataWidth, - int dataHeight, - int left, - int top, - int width, - int height, - boolean reverseHorizontal) { - super(width, height); - - if (left + width > dataWidth || top + height > dataHeight) { - throw new IllegalArgumentException("Crop rectangle does not fit within image data."); - } - - this.yuvData = yuvData; - this.dataWidth = dataWidth; - this.dataHeight = dataHeight; - this.left = left; - this.top = top; - if (reverseHorizontal) { - reverseHorizontal(width, height); - } - } - - @Override - public byte[] getRow(int y, byte[] row) { - if (y < 0 || y >= getHeight()) { - throw new IllegalArgumentException("Requested row is outside the image: " + y); - } - int width = getWidth(); - if (row == null || row.length < width) { - row = new byte[width]; - } - int offset = (y + top) * dataWidth + left; - System.arraycopy(yuvData, offset, row, 0, width); - return row; - } - - @Override - public byte[] getMatrix() { - int width = getWidth(); - int height = getHeight(); - - // If the caller asks for the entire underlying image, save the copy and give them the - // original data. The docs specifically warn that result.length must be ignored. - if (width == dataWidth && height == dataHeight) { - return yuvData; - } - - int area = width * height; - byte[] matrix = new byte[area]; - int inputOffset = top * dataWidth + left; - - // If the width matches the full width of the underlying data, perform a single copy. - if (width == dataWidth) { - System.arraycopy(yuvData, inputOffset, matrix, 0, area); - return matrix; - } - - // Otherwise copy one cropped row at a time. - for (int y = 0; y < height; y++) { - int outputOffset = y * width; - System.arraycopy(yuvData, inputOffset, matrix, outputOffset, width); - inputOffset += dataWidth; - } - return matrix; - } - - @Override - public boolean isCropSupported() { - return true; - } - - @Override - public LuminanceSource crop(int left, int top, int width, int height) { - return new RotateLuminanceSource(yuvData, - dataWidth, - dataHeight, - this.left + left, - this.top + top, - width, - height, - false); - } - - public int[] renderThumbnail() { - int width = getWidth() / THUMBNAIL_SCALE_FACTOR; - int height = getHeight() / THUMBNAIL_SCALE_FACTOR; - int[] pixels = new int[width * height]; - byte[] yuv = yuvData; - int inputOffset = top * dataWidth + left; - - for (int y = 0; y < height; y++) { - int outputOffset = y * width; - for (int x = 0; x < width; x++) { - int grey = yuv[inputOffset + x * THUMBNAIL_SCALE_FACTOR] & 0xff; - pixels[outputOffset + x] = 0xFF000000 | (grey * 0x00010101); - } - inputOffset += dataWidth * THUMBNAIL_SCALE_FACTOR; - } - return pixels; - } - - /** - * @return width of image from {@link #renderThumbnail()} - */ - public int getThumbnailWidth() { - return getWidth() / THUMBNAIL_SCALE_FACTOR; - } - - /** - * @return height of image from {@link #renderThumbnail()} - */ - public int getThumbnailHeight() { - return getHeight() / THUMBNAIL_SCALE_FACTOR; - } - - private void reverseHorizontal(int width, int height) { - byte[] yuvData = this.yuvData; - for (int y = 0, rowStart = top * dataWidth + left; y < height; y++, rowStart += dataWidth) { - int middle = rowStart + width / 2; - for (int x1 = rowStart, x2 = rowStart + width - 1; x1 < middle; x1++, x2--) { - byte temp = yuvData[x1]; - yuvData[x1] = yuvData[x2]; - yuvData[x2] = temp; - } - } - } - - @Override - public boolean isRotateSupported() { - return true; - } - - @Override - public LuminanceSource rotateCounterClockwise() { - byte[] rotatedData = new byte[yuvData.length]; - for (int y = 0; y < dataHeight; y++) { - for (int x = 0; x < dataWidth; x++) - rotatedData[x * dataHeight + dataHeight - y - 1] = yuvData[x + y * dataWidth]; - } - return new RotateLuminanceSource(rotatedData, dataHeight, dataWidth, top, (dataWidth - left - getWidth()), getHeight(), getWidth(), false); - } -} diff --git a/android/src/main/java/com/wix/RNCameraKit/camera/commands/Capture.java b/android/src/main/java/com/wix/RNCameraKit/camera/commands/Capture.java deleted file mode 100644 index a21f1784f5..0000000000 --- a/android/src/main/java/com/wix/RNCameraKit/camera/commands/Capture.java +++ /dev/null @@ -1,39 +0,0 @@ -package com.wix.RNCameraKit.camera.commands; - -import android.content.Context; -import android.hardware.Camera; - -import com.facebook.react.bridge.Promise; - -import com.wix.RNCameraKit.camera.CameraViewManager; -import com.wix.RNCameraKit.SaveImageTask; - -public class Capture implements Command { - - private final Context context; - private boolean saveToCameraRoll; - - public Capture(Context context, boolean saveToCameraRoll) { - this.context = context; - this.saveToCameraRoll = saveToCameraRoll; - } - - @Override - public void execute(final Promise promise) { - try { - tryTakePicture(promise); - } catch (Exception e) { - e.printStackTrace(); - } - } - - private void tryTakePicture(final Promise promise) throws Exception { - CameraViewManager.getCamera().takePicture(null, null, new Camera.PictureCallback() { - @Override - public void onPictureTaken(byte[] data, Camera camera) { - camera.stopPreview(); - new SaveImageTask(context, promise, saveToCameraRoll).execute(data); - } - }); - } -} diff --git a/android/src/main/java/com/wix/RNCameraKit/camera/commands/Command.java b/android/src/main/java/com/wix/RNCameraKit/camera/commands/Command.java deleted file mode 100644 index 43ee0feb92..0000000000 --- a/android/src/main/java/com/wix/RNCameraKit/camera/commands/Command.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.wix.RNCameraKit.camera.commands; - -import com.facebook.react.bridge.Promise; - -public interface Command { - void execute(Promise promise); -} diff --git a/android/src/main/java/com/wix/RNCameraKit/camera/permission/CameraPermission.java b/android/src/main/java/com/wix/RNCameraKit/camera/permission/CameraPermission.java deleted file mode 100644 index 4cfb561cbd..0000000000 --- a/android/src/main/java/com/wix/RNCameraKit/camera/permission/CameraPermission.java +++ /dev/null @@ -1,69 +0,0 @@ -package com.wix.RNCameraKit.camera.permission; - -import android.Manifest; -import android.app.Activity; -import android.support.v4.app.ActivityCompat; -import android.support.v4.content.PermissionChecker; - -import com.facebook.react.bridge.Promise; -import com.wix.RNCameraKit.SharedPrefs; - -public class CameraPermission { - private static final int CAMERA_PERMISSION_REQUEST_CODE = 1002; - private static final int PERMISSION_GRANTED = 1; - private static final int PERMISSION_NOT_DETERMINED = -1; - private static final int PERMISSION_DENIED = 0; - - private Promise requestAccessPromise; - - public void requestAccess(Activity activity, Promise promise) { - if (isPermissionGranted(activity)) { - promise.resolve(true); - } - requestAccessPromise = promise; - permissionRequested(activity, Manifest.permission.CAMERA); - ActivityCompat.requestPermissions(activity, - new String[]{Manifest.permission.CAMERA}, - CAMERA_PERMISSION_REQUEST_CODE); - } - - public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { - if (isCameraPermission(requestCode, permissions)) { - if (requestAccessPromise != null) { - requestAccessPromise.resolve(grantResults[0] == PermissionChecker.PERMISSION_GRANTED); - requestAccessPromise = null; - } - } - } - - private boolean isCameraPermission(int requestCode, String[] permissions) { - if (permissions.length > 0) { - return requestCode == CAMERA_PERMISSION_REQUEST_CODE && - Manifest.permission.CAMERA.equals(permissions[0]); - } - return false; - } - - public int checkAuthorizationStatus(Activity activity) { - final int statusCode = PermissionChecker.checkCallingOrSelfPermission(activity, Manifest.permission.CAMERA); - if (statusCode == PermissionChecker.PERMISSION_GRANTED) { - return PERMISSION_GRANTED; - } - if (requestingPermissionForFirstTime(activity, Manifest.permission.CAMERA)) { - return PERMISSION_NOT_DETERMINED; - } - return PERMISSION_DENIED; - } - - private boolean requestingPermissionForFirstTime(Activity activity, String permissionName) { - return !SharedPrefs.getBoolean(activity, permissionName); - } - - private void permissionRequested(Activity activity, String permissionName) { - SharedPrefs.putBoolean(activity, permissionName, true); - } - - private boolean isPermissionGranted(Activity activity) { - return checkAuthorizationStatus(activity) == PermissionChecker.PERMISSION_GRANTED; - } -} diff --git a/android/src/main/java/com/wix/RNCameraKit/camera/permission/CameraPermissionRequestCallback.java b/android/src/main/java/com/wix/RNCameraKit/camera/permission/CameraPermissionRequestCallback.java deleted file mode 100644 index 33a3c7ddb9..0000000000 --- a/android/src/main/java/com/wix/RNCameraKit/camera/permission/CameraPermissionRequestCallback.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.wix.RNCameraKit.camera.permission; - -import com.wix.RNCameraKit.camera.CameraModule; - -public class CameraPermissionRequestCallback { - - private CameraModule cameraModule; - - public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { - cameraModule.onRequestPermissionsResult(requestCode, permissions, grantResults); - } - - public void setCameraModule(CameraModule cameraModule) { - this.cameraModule = cameraModule; - } -} diff --git a/android/src/main/java/com/wix/RNCameraKit/gallery/GalleryAdapter.java b/android/src/main/java/com/wix/RNCameraKit/gallery/GalleryAdapter.java deleted file mode 100644 index eaf54d3a93..0000000000 --- a/android/src/main/java/com/wix/RNCameraKit/gallery/GalleryAdapter.java +++ /dev/null @@ -1,390 +0,0 @@ -package com.wix.RNCameraKit.gallery; - -import android.database.Cursor; -import android.graphics.Color; -import android.graphics.drawable.Drawable; -import android.provider.MediaStore; -import android.support.v7.widget.RecyclerView; -import android.view.Gravity; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ImageView; - -import com.facebook.react.bridge.ReactContext; -import com.facebook.react.uimanager.UIManagerModule; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Timer; -import java.util.TimerTask; -import java.util.concurrent.LinkedBlockingDeque; -import java.util.concurrent.ThreadPoolExecutor; -import java.util.concurrent.TimeUnit; - -public class GalleryAdapter extends RecyclerView.Adapter { - - public static final int SELECTED_IMAGE_SIZE_NORMAL = SelectableImage.SELECTED_IMAGE_NORMAL_SIZE_DP; - public static final int SELECTED_IMAGE_SIZE_LARGE = SelectableImage.SELECTED_IMAGE_LARGE_SIZE_DP; - - private static final int[] selectedPositionTypeToGravity = new int[] { - Gravity.TOP | Gravity.RIGHT, - Gravity.TOP | Gravity.LEFT, - Gravity.BOTTOM | Gravity.RIGHT, - Gravity.BOTTOM | Gravity.LEFT, - Gravity.CENTER - }; - - private static final int DEFAULT_CUSTOM_BUTTON_BACKGROUND_COLOR = Color.parseColor("#f2f4f5"); - - private static int VIEW_TYPE_IMAGE = 0; - private static int VIEW_TYPE_CUSTOM_BUTTON = 1; - - private static final String[] PROJECTION = new String[]{ - MediaStore.Images.Media.DATA, - MediaStore.Images.Media._ID, - MediaStore.Images.Media.MIME_TYPE, - MediaStore.Images.Media.WIDTH, - MediaStore.Images.Media.HEIGHT, - MediaStore.Images.Media.ORIENTATION - }; - - private class Image { - String uri; - Integer id; - String mimeType; - Integer width; - Integer height; - Integer orientation; - - public Image(String uri, Integer id, String mimeType, Integer width, Integer height,Integer orientation) { - this.uri = uri; - this.id = id; - this.mimeType = mimeType; - this.width = width; - this.height = height; - this.orientation = orientation; - } - } - - abstract class AbsViewHolder extends RecyclerView.ViewHolder { - AbsViewHolder(View itemView) { - super(itemView); - } - - public abstract void bind(int position); - } - - class ImageHolder extends AbsViewHolder implements View.OnClickListener { - Image image; - boolean isSupported = true; - - ImageHolder(SelectableImage itemView) { - super(itemView); - } - - public void bind(int position) { - final Image image = images.get(position); - this.image = image; - this.isSupported = isSupported(image); - - final boolean selected = isSelected(); - final boolean forceBind = hasImageChanged(); - - final SelectableImage selectableImageView = (SelectableImage) this.itemView; - selectableImageView.setUnsupportedUIParams(overlayColor, unsupportedFinalImage, unsupportedText, unsupportedTextColor); - selectableImageView.setDrawables(selectedDrawable, unselectedDrawable, selectionOverlayColor); - selectableImageView.bind(executor, selected, forceBind, image.id, isSupported,image.orientation); - selectableImageView.setOnClickListener(this); - } - - @Override - public void onClick(View v) { - if (!isSupported) { - return; - } - - final boolean isSelected = v.isSelected(); - if (!enableSelection && !isSelected) { - return; - } - - onTapImage(image.uri, image.width, image.height); - v.setSelected(!isSelected); - } - - private boolean isSelected() { - return (selectedUris.indexOf(image.uri) + 1) > 0; - } - - private boolean isSupported(Image image) { - if (supportedFileTypes.isEmpty()) { - return true; - } else { - for (String supportedMime : supportedFileTypes) { - if (supportedMime == null) { - continue; - } else if (image.mimeType == null) { - return false; - } else if (image.mimeType.toLowerCase().equals(supportedMime.toLowerCase())) { - return true; - } - } - return false; - } - } - - private boolean hasImageChanged() { - boolean hasImageChanged = (dirtyUris.indexOf(image.uri)) >= 0; - if (hasImageChanged) { - dirtyUris.remove(image.uri); - } - return hasImageChanged; - } - } - - class CustomButtonViewHolder extends AbsViewHolder implements View.OnClickListener { - - CustomButtonViewHolder() { - super(new ImageView(GalleryAdapter.this.reactContext.getApplicationContext())); - - final ImageView imageView = (ImageView) this.itemView; - imageView.setScaleType(ImageView.ScaleType.CENTER); - imageView.setOnClickListener(this); - } - - @Override - public void bind(int position) { - final ImageView imageView = (ImageView) this.itemView; - imageView.setImageDrawable(GalleryAdapter.this.customButtonImage); - imageView.setBackgroundColor(GalleryAdapter.this.customButtonBackgroundColor); - } - - @Override - public void onClick(View v) { - onTapCustomButton(); - } - } - - private String overlayColor; - private Integer selectionOverlayColor; - private Drawable unsupportedFinalImage; - private String unsupportedText; - private String unsupportedTextColor; - private List dirtyUris = new ArrayList<>(); - private ArrayList selectedUris = new ArrayList<>(); - private ArrayList supportedFileTypes = new ArrayList<>(); - private String albumName = ""; - private Drawable selectedDrawable; - private Drawable customButtonImage; - private Integer selectedDrawableGravity; - private Integer selectedDrawableSize; - private Drawable unselectedDrawable; - private int customButtonBackgroundColor = DEFAULT_CUSTOM_BUTTON_BACKGROUND_COLOR; - private boolean enableSelection = true; - - private final GalleryView galleryView; - private final ReactContext reactContext; - private final ThreadPoolExecutor executor; - - private boolean isDirty = true; - private ArrayList images = new ArrayList<>(); - - public GalleryAdapter(ReactContext reactContext, GalleryView galleryView) { - this.reactContext = reactContext; - this.galleryView = galleryView; - setHasStableIds(true); - int cores = Runtime.getRuntime().availableProcessors(); - executor = new ThreadPoolExecutor(cores, cores, 1, TimeUnit.SECONDS, new LinkedBlockingDeque()); - setAlbum(albumName); - } - - public void setAlbum(String albumName) { - this.albumName = albumName; - - isDirty = true; - } - - public void setSelectedUris(ArrayList selectedUris) { - this.selectedUris = selectedUris; - } - - void setDirtyUris(List dirtyUris) { - this.dirtyUris = dirtyUris; - - isDirty = true; - } - - public void setSelectedDrawable(Drawable selectedDrawable) { - this.selectedDrawable = selectedDrawable; - } - - public void setUnselectedDrawable(Drawable unselectedDrawable) { - this.unselectedDrawable = unselectedDrawable; - } - - public void setSelectionDrawablePosition(int positionType) { - this.selectedDrawableGravity = selectedPositionTypeToGravity[positionType]; - } - - public void setSelectedDrawableSize(int selectedDrawableSize) { - this.selectedDrawableSize = selectedDrawableSize; - } - - public void setSelectionOverlayColor(Integer overlayColor) { - this.selectionOverlayColor = overlayColor; - } - - public void setSupportedFileTypes(ArrayList supportedFileTypes) { - this.supportedFileTypes = supportedFileTypes; - - isDirty = true; - } - - public void setUnsupportedUIParams(String overlayColor, Drawable unsupportedFinalImage, String unsupportedText, String unsupportedTextColor) { - this.overlayColor = overlayColor; - this.unsupportedFinalImage = unsupportedFinalImage; - this.unsupportedText = unsupportedText; - this.unsupportedTextColor = unsupportedTextColor; - } - - public void setCustomButtonImage(Drawable customButtonImage) { - this.customButtonImage = customButtonImage; - } - - public void setCustomButtonBackgroundColor(int color) { - this.customButtonBackgroundColor = color; - } - - public void setShouldEnabledSelection(Boolean enable) { - this.enableSelection = enable; - } - - @Override - public int getItemViewType(int position) { - if (shouldShowCustomButton() && position == 0) { - return VIEW_TYPE_CUSTOM_BUTTON; - } - return VIEW_TYPE_IMAGE; - } - - void refreshData() { - refreshData(false); - } - - void refreshData(boolean force) { - if (!isDirty && !force) { - return; - } - isDirty = false; - - int preItemsCount = getItemCount(); - images.clear(); - - String selection = ""; - String[] args = null; - if (albumName != null && !albumName.isEmpty() && !albumName.equals("All Photos")) { - selection = MediaStore.Images.Media.BUCKET_DISPLAY_NAME + "=?"; - args = new String[]{albumName}; - } - - Cursor cursor = reactContext.getApplicationContext().getContentResolver().query( - MediaStore.Images.Media.EXTERNAL_CONTENT_URI, - PROJECTION, - selection, - args, - null - ); - - if (cursor.moveToFirst()) { - int dataIndex = cursor.getColumnIndex(MediaStore.Images.Media.DATA); - int idIndex = cursor.getColumnIndex(MediaStore.Images.Media._ID); - int mimeIndex = cursor.getColumnIndex(MediaStore.Images.Media.MIME_TYPE); - int widthIndex = cursor.getColumnIndex(MediaStore.Images.Media.WIDTH); - int heightIndex = cursor.getColumnIndex(MediaStore.Images.Media.HEIGHT); - int orientationIndex = cursor.getColumnIndex(MediaStore.Images.Media.ORIENTATION); - do { - images.add(new Image(cursor.getString(dataIndex), cursor.getInt(idIndex), cursor.getString(mimeIndex), - cursor.getInt(widthIndex), cursor.getInt(heightIndex), cursor.getInt(orientationIndex))); - } while (cursor.moveToNext()); - } - - if (shouldShowCustomButton()) { - images.add(new Image(null, -1, "", 0, 0,0)); - } - Collections.reverse(images); - cursor.close(); - notifyItemsLoaded(preItemsCount, getItemCount()); - } - - private void notifyItemsLoaded(final int preCount, final int postCount) { - reactContext.runOnUiQueueThread(new Runnable() { - @Override - public void run() { - if (!galleryView.isComputingLayout()) { - if (preCount == 0) { - notifyItemRangeInserted(0, postCount); - } else { - galleryView.swapAdapter(GalleryAdapter.this, true); - } - // http://stackoverflow.com/a/42549611/453052 - galleryView.scrollBy(0, 0); - } else { - new Timer().schedule(new TimerTask() { - @Override - public void run() { - notifyItemsLoaded(preCount, postCount); - } - }, 10); - } - } - }); - } - - @Override - public AbsViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { - if (viewType == VIEW_TYPE_IMAGE) { - SelectableImage v = new SelectableImage(reactContext, selectedDrawableGravity, selectedDrawableSize); - v.setScaleType(ImageView.ScaleType.CENTER_CROP); - v.setBackgroundColor(Color.LTGRAY); - return new ImageHolder(v); - } - - if (viewType == VIEW_TYPE_CUSTOM_BUTTON) { - return new CustomButtonViewHolder(); - } - - return null; - } - - @Override - public void onBindViewHolder(final AbsViewHolder holder, final int position) { - holder.bind(position); - } - - @Override - public long getItemId(int position) { - return images.get(position).id; - } - - @Override - public int getItemCount() { - return images.size(); - } - - private boolean shouldShowCustomButton() { - return customButtonImage != null; - } - - public void onTapImage(String uri, Integer width, Integer height) { - reactContext.getNativeModule(UIManagerModule.class).getEventDispatcher().dispatchEvent(new TapImageEvent(getRootViewId(), uri, width, height)); - } - - public void onTapCustomButton() { - reactContext.getNativeModule(UIManagerModule.class).getEventDispatcher().dispatchEvent(new TapCustomButtonEvent(getRootViewId())); - } - - private int getRootViewId() { - return galleryView.getId(); - } -} diff --git a/android/src/main/java/com/wix/RNCameraKit/gallery/GalleryView.java b/android/src/main/java/com/wix/RNCameraKit/gallery/GalleryView.java deleted file mode 100644 index 40da291886..0000000000 --- a/android/src/main/java/com/wix/RNCameraKit/gallery/GalleryView.java +++ /dev/null @@ -1,67 +0,0 @@ -package com.wix.RNCameraKit.gallery; - -import android.content.Context; -import android.graphics.Rect; -import android.support.v7.widget.GridLayoutManager; -import android.support.v7.widget.RecyclerView; -import android.util.Log; -import android.view.View; - -public class GalleryView extends RecyclerView { - - private class GridLayoutViewManagerWrapper extends GridLayoutManager { - - GridLayoutViewManagerWrapper(Context context, int spanCount) { - super(context, spanCount); - } - - @Override - public void onLayoutChildren(Recycler recycler, State state) { - try { - super.onLayoutChildren(recycler, state); - } catch (IndexOutOfBoundsException e) { - Log.e("WIX", "IOOBE in RecyclerView"); - } - } - } - - private int itemSpacing; - private int lineSpacing; - - public GalleryView(Context context) { - super(context); - setHasFixedSize(true); - getRecycledViewPool().setMaxRecycledViews(0, 20); - } - - private void updateDecorator() { - addItemDecoration(new ItemDecoration() { - @Override - public void getItemOffsets(Rect outRect, View view, RecyclerView parent, State state) { - outRect.top = lineSpacing; - outRect.left = itemSpacing; - outRect.right = itemSpacing; - outRect.bottom = lineSpacing; - } - }); - } - - public void setItemSpacing(int itemSpacing) { - this.itemSpacing = itemSpacing; - updateDecorator(); - } - - public void setLineSpacing(int lineSpacing) { - this.lineSpacing = lineSpacing; - updateDecorator(); - } - - public void setColumnCount(int columnCount) { - if (getLayoutManager() == null || ((GridLayoutViewManagerWrapper) getLayoutManager()).getSpanCount() != columnCount) { - GridLayoutManager layoutManager = new GridLayoutViewManagerWrapper(getContext(), columnCount); - layoutManager.setOrientation(GridLayoutManager.VERTICAL); - setLayoutManager(layoutManager); - } - } - -} diff --git a/android/src/main/java/com/wix/RNCameraKit/gallery/GalleryViewManager.java b/android/src/main/java/com/wix/RNCameraKit/gallery/GalleryViewManager.java deleted file mode 100644 index 6f0fc1740c..0000000000 --- a/android/src/main/java/com/wix/RNCameraKit/gallery/GalleryViewManager.java +++ /dev/null @@ -1,266 +0,0 @@ -package com.wix.RNCameraKit.gallery; - -import android.graphics.drawable.Drawable; -import android.os.Handler; -import android.os.HandlerThread; -import android.view.View; - -import com.facebook.react.bridge.ReadableArray; -import com.facebook.react.bridge.ReadableMap; -import com.facebook.react.common.MapBuilder; -import com.facebook.react.uimanager.SimpleViewManager; -import com.facebook.react.uimanager.ThemedReactContext; -import com.facebook.react.uimanager.annotations.ReactProp; - -import java.util.ArrayList; -import java.util.Map; - -import javax.annotation.Nullable; - -import static com.wix.RNCameraKit.Utils.*; - -public class GalleryViewManager extends SimpleViewManager { - - private static final int COMMAND_REFRESH_GALLERY = 1; - - private final String UNSUPPORTED_IMAGE_KEY = "unsupportedImage"; - private final String UNSUPPORTED_TEXT_KEY = "unsupportedText"; - private final String UNSUPPORTED_TEXT_COLOR_KEY = "unsupportedTextColor"; - private final String SUPPORTED_TYPES_KEY = "supportedFileTypes"; - private final String UNSUPPORTED_OVERLAY_KEY = "unsupportedOverlayColor"; - private final String CUSTOM_BUTTON_IMAGE_KEY = "image"; - private final String CUSTOM_BUTTON_BCK_COLOR_KEY = "backgroundColor"; - private final String SELECTION_SELECTED_IMAGE_KEY = "selectedImage"; - private final String SELECTION_UNSELECTED_IMAGE_KEY = "unselectedImage"; - private final String SELECTION_POSITION_KEY = "imagePosition"; - private final String SELECTION_SIZE_KEY = "imageSizeAndroid"; - private final String SELECTION_ENABLED_KEY = "enable"; - private final String SELECTION_OVERLAY_KEY = "overlayColor"; - - /** - * A handler is required in order to sync configurations made to the adapter - some must run off the UI thread (e.g. drawables - * fetching), so that the finalizing call to refreshData() (from within {@link #onAfterUpdateTransaction(View)}) will be made - * strictly after all configurations have settled in. - * - *

Note: It is not mandatory to invoke all config set-ups via the handler, but we do so anyway so as to avoid - * races between multiple threads.

- */ - private Handler adapterConfigHandler; - - @Override - public String getName() { - return "GalleryView"; - } - - @Override - protected GalleryView createViewInstance(ThemedReactContext reactContext) { - final HandlerThread handlerThread = new HandlerThread("GalleryViewManager.configThread"); - handlerThread.start(); - adapterConfigHandler = new Handler(handlerThread.getLooper()); - - GalleryView view = new GalleryView(reactContext); - view.setAdapter(new GalleryAdapter(reactContext, view)); - return view; - } - - @Override - protected void onAfterUpdateTransaction(final GalleryView view) { - dispatchRefreshDataOnJobQueue(view, false); - super.onAfterUpdateTransaction(view); - } - - @ReactProp(name = "minimumInteritemSpacing") - public void setItemSpacing(GalleryView view, int itemSpacing) { - view.setItemSpacing(itemSpacing/2); - } - - @ReactProp(name = "minimumLineSpacing") - public void setLineSpacing(GalleryView view, int lineSpacing) { - view.setLineSpacing(lineSpacing/2); - } - - @ReactProp(name = "albumName") - public void setAlbumName(final GalleryView view, final String albumName) { - dispatchOnConfigJobQueue(new Runnable() { - @Override - public void run() { - getViewAdapter(view).setAlbum(albumName); - } - }); - } - - @ReactProp(name = "columnCount") - public void setColumnCount(GalleryView view, int columnCount) { - view.setColumnCount(columnCount); - } - - @ReactProp(name = "selectedImages") - public void setSelectedUris(final GalleryView view, final ReadableArray uris) { - dispatchOnConfigJobQueue(new Runnable() { - @Override - public void run() { - getViewAdapter(view).setSelectedUris(readableArrayToList(uris)); - } - }); - } - - @ReactProp(name = "dirtyImages") - public void setDirtyImages(final GalleryView view, final ReadableArray uris) { - dispatchOnConfigJobQueue(new Runnable() { - @Override - public void run() { - getViewAdapter(view).setDirtyUris(readableArrayToList(uris)); - } - }); - } - - @ReactProp(name = "selectedImageIcon") - public void setSelectedImage(final GalleryView view, final String imageSource) { - dispatchOnConfigJobQueue(new Runnable() { - @Override - public void run() { - final Drawable drawable = ResourceDrawableIdHelper.getIcon(view.getContext(), imageSource); - getViewAdapter(view).setSelectedDrawable(drawable); - } - }); - } - - @ReactProp(name = "unSelectedImageIcon") - public void setUnselectedImage(final GalleryView view, final String imageSource) { - dispatchOnConfigJobQueue(new Runnable() { - @Override - public void run() { - final Drawable drawable = ResourceDrawableIdHelper.getIcon(view.getContext(), imageSource); - getViewAdapter(view).setUnselectedDrawable(drawable); - } - }); - } - - @ReactProp(name = "selection") - public void setSelectionProperties(final GalleryView view, final ReadableMap selectionProps) { - final String selectedImage = getStringSafe(selectionProps, SELECTION_SELECTED_IMAGE_KEY); - final String unselectedImage = getStringSafe(selectionProps, SELECTION_UNSELECTED_IMAGE_KEY); - final Integer position = getIntSafe(selectionProps, SELECTION_POSITION_KEY); - final String size = getStringSafe(selectionProps, SELECTION_SIZE_KEY); - final Boolean enabled = getBooleanSafe(selectionProps, SELECTION_ENABLED_KEY); - final Integer selectionOverlayColor = getIntSafe(selectionProps, SELECTION_OVERLAY_KEY); - dispatchOnConfigJobQueue(new Runnable() { - @Override - public void run() { - final GalleryAdapter viewAdapter = getViewAdapter(view); - - if (selectedImage != null) { - final Drawable selectedDrawable = ResourceDrawableIdHelper.getIcon(view.getContext(), selectedImage); - viewAdapter.setSelectedDrawable(selectedDrawable); - } - - if (unselectedImage != null) { - final Drawable unselectedDrawable = ResourceDrawableIdHelper.getIcon(view.getContext(), unselectedImage); - viewAdapter.setUnselectedDrawable(unselectedDrawable); - } - - if (position != null) { - viewAdapter.setSelectionDrawablePosition(position); - } - - if (size != null) { - final int sizeCode = size.equalsIgnoreCase("large") ? GalleryAdapter.SELECTED_IMAGE_SIZE_LARGE : GalleryAdapter.SELECTED_IMAGE_SIZE_NORMAL; - viewAdapter.setSelectedDrawableSize(sizeCode); - } - - viewAdapter.setShouldEnabledSelection(enabled != null ? enabled : true); - viewAdapter.setSelectionOverlayColor(selectionOverlayColor); - } - }); - } - - @ReactProp(name = "fileTypeSupport") - public void setFileTypeSupport(final GalleryView view, final ReadableMap fileTypeSupport) { - final ReadableArray supportedFileTypes = fileTypeSupport.getArray(SUPPORTED_TYPES_KEY); - final String unsupportedOverlayColor = getStringSafe(fileTypeSupport, UNSUPPORTED_OVERLAY_KEY); - final String unsupportedImageSource = getStringSafe(fileTypeSupport, UNSUPPORTED_IMAGE_KEY); - final String unsupportedText = getStringSafe(fileTypeSupport, UNSUPPORTED_TEXT_KEY); - final String unsupportedTextColor = getStringSafe(fileTypeSupport, UNSUPPORTED_TEXT_COLOR_KEY); - - dispatchOnConfigJobQueue(new Runnable() { - @Override - public void run() { - Drawable unsupportedImage = null; - if(unsupportedImageSource != null) { - unsupportedImage = ResourceDrawableIdHelper.getIcon(view.getContext(), unsupportedImageSource); - } - final Drawable unsupportedFinalImage = unsupportedImage; - final ArrayList supportedFileTypesList = new ArrayList(); - if(supportedFileTypes != null && supportedFileTypes.size() != 0) { - for (int i = 0; i < supportedFileTypes.size(); i++) { - supportedFileTypesList.add(supportedFileTypes.getString(i)); - } - } - - getViewAdapter(view) - .setUnsupportedUIParams( - unsupportedOverlayColor, - unsupportedFinalImage, - unsupportedText, - unsupportedTextColor); - getViewAdapter(view).setSupportedFileTypes(supportedFileTypesList); - } - }); - } - - @ReactProp(name = "customButtonStyle") - public void setCustomButton(final GalleryView view, final ReadableMap props) { - dispatchOnConfigJobQueue(new Runnable() { - @Override - public void run() { - final String imageResource = getStringSafe(props, CUSTOM_BUTTON_IMAGE_KEY); - final Integer backgroundColor = getIntSafe(props, CUSTOM_BUTTON_BCK_COLOR_KEY); - final Drawable drawable = ResourceDrawableIdHelper.getIcon(view.getContext(), imageResource); - - getViewAdapter(view).setCustomButtonImage(drawable); - if (backgroundColor != null) { - getViewAdapter(view).setCustomButtonBackgroundColor(backgroundColor); - } - } - }); - } - - @Nullable - @Override - public Map getExportedCustomDirectEventTypeConstants() { - return MapBuilder.builder() - .put("onTapImage", MapBuilder.of("registrationName", "onTapImage")) - .put("onCustomButtonPress", MapBuilder.of("registrationName", "onCustomButtonPress")) - .build(); - } - - @Nullable - @Override - public Map getCommandsMap() { - return MapBuilder.of("refreshGalleryView", COMMAND_REFRESH_GALLERY); - } - - @Override - public void receiveCommand(GalleryView view, int commandId, @Nullable ReadableArray args) { - if (commandId == COMMAND_REFRESH_GALLERY) { - dispatchRefreshDataOnJobQueue(view, true); - } - } - - private void dispatchOnConfigJobQueue(Runnable runnable) { - adapterConfigHandler.post(runnable); - } - - private void dispatchRefreshDataOnJobQueue(final GalleryView view, final boolean force) { - dispatchOnConfigJobQueue(new Runnable() { - @Override - public void run() { - getViewAdapter(view).refreshData(force); - } - }); - } - - private GalleryAdapter getViewAdapter(GalleryView view) { - return ((GalleryAdapter) view.getAdapter()); - } -} diff --git a/android/src/main/java/com/wix/RNCameraKit/gallery/NativeGalleryModule.java b/android/src/main/java/com/wix/RNCameraKit/gallery/NativeGalleryModule.java deleted file mode 100644 index 48829f473e..0000000000 --- a/android/src/main/java/com/wix/RNCameraKit/gallery/NativeGalleryModule.java +++ /dev/null @@ -1,329 +0,0 @@ -package com.wix.RNCameraKit.gallery; - -import android.content.ContentResolver; -import android.content.Context; -import android.database.Cursor; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.net.Uri; -import android.provider.MediaStore; -import android.support.annotation.NonNull; -import android.util.Log; - -import com.facebook.react.bridge.Arguments; -import com.facebook.react.bridge.LifecycleEventListener; -import com.facebook.react.bridge.Promise; -import com.facebook.react.bridge.ReactApplicationContext; -import com.facebook.react.bridge.ReactContextBaseJavaModule; -import com.facebook.react.bridge.ReactMethod; -import com.facebook.react.bridge.ReadableArray; -import com.facebook.react.bridge.ReadableMap; -import com.facebook.react.bridge.WritableArray; -import com.facebook.react.bridge.WritableMap; -import com.wix.RNCameraKit.SaveImageTask; -import com.wix.RNCameraKit.Utils; -import com.wix.RNCameraKit.gallery.permission.StoragePermission; - -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.util.Collection; -import java.util.Date; -import java.util.HashMap; - -import static com.wix.RNCameraKit.Utils.getStringSafe; - -/** - * Created by yedidyak on 29/06/2016. - */ -public class NativeGalleryModule extends ReactContextBaseJavaModule { - - - private final String IMAGE_URI_KEY = "uri"; - private final String IMAGE_NAME_KEY = "name"; - - private final int HIGHE_DIMANTION = 1200; - private final int MEDIUM_DIMANTION = 800; - private final int LOW_DIMANTION = 600; - - - public static final int MEDIUM_COMPRESSION_QUALITY = 85; - public static final int HIGH_COMPRESSION_QUALITY = 92; - - private final String HIGH_QUALITY = "high"; - private final String MEDIUM_QUALITY = "medium"; - private final String LOW_QUALITY = "low"; - - - public static final String[] ALBUMS_PROJECTION = new String[]{ - MediaStore.Images.Media.DATA, - MediaStore.Images.Media.BUCKET_DISPLAY_NAME - }; - public static final String[] IMAGES_PROJECTION = new String[]{ - MediaStore.Images.Media._ID, - MediaStore.Images.Media.SIZE, - MediaStore.Images.Media.MIME_TYPE, - MediaStore.Images.Media.TITLE, - MediaStore.Images.Media.WIDTH, - MediaStore.Images.Media.HEIGHT, - MediaStore.Images.Media.DATA - }; - public static final String ALL_PHOTOS = "All Photos"; - private Promise checkPermissionStatusPromise; - - private class Album { - String name; - String imageUri = null; - int count = 1; - - public Album(String name, String uri) { - this.name = name; - this.imageUri = uri; - } - } - - private class AlbumList { - HashMap albums = new HashMap<>(); - - public void addAlbum(String name, String uri) { - if (!albums.containsKey(name)) { - albums.put(name, new Album(name, uri)); - } else { - albums.get(name).count++; - } - } - - public Collection getAlbums() { - return albums.values(); - } - } - - private final StoragePermission storagePermission; - - public NativeGalleryModule(ReactApplicationContext reactContext) { - super(reactContext); - storagePermission = new StoragePermission(); - checkPermissionWhenActivityIsAvailable(); - } - - private void checkPermissionWhenActivityIsAvailable() { - getReactApplicationContext().addLifecycleEventListener(new LifecycleEventListener() { - @Override - public void onHostResume() { - if (checkPermissionStatusPromise != null && getCurrentActivity() != null) { - getCurrentActivity().runOnUiThread(new Runnable() { - @Override - public void run() { - checkPermissionStatusPromise.resolve(storagePermission.checkAuthorizationStatus(getCurrentActivity())); - checkPermissionStatusPromise = null; - } - }); - } - } - - @Override - public void onHostPause() { - - } - - @Override - public void onHostDestroy() { - - } - }); - } - - @Override - public String getName() { - return "NativeGalleryModule"; - } - - @NonNull - private WritableMap albumToMap(Album album) { - WritableMap map = Arguments.createMap(); - map.putInt("imagesCount", album.count); - map.putString("albumName", album.name); - map.putString("thumbUri", album.imageUri); - return map; - } - - @NonNull - private AlbumList getAlbumListFromCursor(Cursor imagesCursor) { - AlbumList albums = new AlbumList(); - - if (imagesCursor.moveToFirst()) { - int bucketColumn = imagesCursor.getColumnIndex(MediaStore.Images.Media.BUCKET_DISPLAY_NAME); - int uriColumn = imagesCursor.getColumnIndex(MediaStore.Images.Media.DATA); - do { - String name = imagesCursor.getString(bucketColumn); - String uri = imagesCursor.getString(uriColumn); - albums.addAlbum(name, uri); - albums.addAlbum(ALL_PHOTOS, uri); - } while (imagesCursor.moveToNext()); - } - imagesCursor.close(); - return albums; - } - - private Bitmap getThumbnail(int thumbId) { - return MediaStore.Images.Thumbnails.getThumbnail( - getReactApplicationContext().getContentResolver(), - thumbId, - MediaStore.Images.Thumbnails.MINI_KIND, - null); - } - - public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { - storagePermission.onRequestPermissionsResult(requestCode, permissions, grantResults); - } - - @ReactMethod - public void checkDeviceStorageAuthorizationStatus(final Promise promise) { - if (getCurrentActivity() == null) { - checkPermissionStatusPromise = promise; - } else { - getCurrentActivity().runOnUiThread(new Runnable() { - @Override - public void run() { - promise.resolve(storagePermission.checkAuthorizationStatus(getCurrentActivity())); - } - }); - } - } - - @ReactMethod - public void requestDeviceStorageAuthorization(Promise promise) { - storagePermission.requestAccess(getCurrentActivity(), promise); - } - - @ReactMethod - public void getAlbumsWithThumbnails(Promise promise) { - Cursor imagesCursor = getReactApplicationContext().getContentResolver().query( - MediaStore.Images.Media.EXTERNAL_CONTENT_URI, ALBUMS_PROJECTION, null, null, null); - AlbumList albums = getAlbumListFromCursor(imagesCursor); - WritableArray arr = Arguments.createArray(); - - for (Album album : albums.getAlbums()) { - arr.pushMap(albumToMap(album)); - } - - WritableMap ret = Arguments.createMap(); - ret.putArray("albums", arr); - - promise.resolve(ret); - } - - - @ReactMethod - public void resizeImage(ReadableMap image, String quality, Promise promise) throws IOException { - try { - String imageUrlString = getStringSafe(image, IMAGE_URI_KEY); - if (imageUrlString.startsWith(Utils.FILE_PREFIX)) { - imageUrlString = imageUrlString.replaceFirst(Utils.FILE_PREFIX, ""); - } - - // decide what is the wanted compression & resolution - int maxResolution; - int compressionQuality; - switch(quality) { - case HIGH_QUALITY: - maxResolution = HIGHE_DIMANTION; - compressionQuality = MEDIUM_COMPRESSION_QUALITY; - break; - case MEDIUM_QUALITY: - maxResolution = MEDIUM_DIMANTION; - compressionQuality = MEDIUM_COMPRESSION_QUALITY; - break; - case LOW_QUALITY: - maxResolution = LOW_DIMANTION; - compressionQuality = MEDIUM_COMPRESSION_QUALITY; - break; - default: - maxResolution = HIGHE_DIMANTION; - compressionQuality = HIGH_COMPRESSION_QUALITY; - } - - WritableMap ans = Utils.resizeImage(getReactApplicationContext(), image, imageUrlString, maxResolution, compressionQuality); - - promise.resolve(ans); - } catch (IOException e) { - Log.d("","Failed resize image e: "+e.getMessage()); - } - } - - - @ReactMethod - public void getImagesForUris(ReadableArray uris, Promise promise) { - StringBuilder builder = new StringBuilder(); - builder.append(MediaStore.Images.Media.DATA + " IN ("); - for (int i = 0; i < uris.size(); i++) { - builder.append("\""); - builder.append(uris.getString(i)); - builder.append("\""); - if (i != uris.size() - 1) { - builder.append(", "); - } - } - builder.append(")"); - String selection = builder.toString(); - - Cursor cursor = getReactApplicationContext().getContentResolver().query( - MediaStore.Images.Media.EXTERNAL_CONTENT_URI, - IMAGES_PROJECTION, - selection, - null, - null - ); - - WritableArray arr = Arguments.createArray(); - - if (cursor != null) { - if (cursor.moveToFirst()) { - int dataIndex = cursor.getColumnIndex(MediaStore.Images.Media.DATA); - int sizeIndex = cursor.getColumnIndex(MediaStore.Images.Media.SIZE); - int nameIndex = cursor.getColumnIndex(MediaStore.Images.Media.TITLE); - int mimeIndex = cursor.getColumnIndex(MediaStore.Images.Media.MIME_TYPE); - int widthIndex = cursor.getColumnIndex(MediaStore.Images.Media.WIDTH); - int heightIndex = cursor.getColumnIndex(MediaStore.Images.Media.HEIGHT); - do { - WritableMap map = Arguments.createMap(); - map.putString("uri", "file://" + cursor.getString(dataIndex)); - map.putInt("size", cursor.getInt(sizeIndex)); - map.putInt("width", cursor.getInt(widthIndex)); - map.putInt("height", cursor.getInt(heightIndex)); - map.putString("mime_type", cursor.getString(mimeIndex)); - map.putString("name", cursor.getString(nameIndex)); - arr.pushMap(map); - } while (cursor.moveToNext()); - } - cursor.close(); - } - WritableMap ret = Arguments.createMap(); - ret.putArray("images", arr); - promise.resolve(ret); - } - - @ReactMethod - public void saveImageURLToCameraRoll(String imageUrl, final Promise promise) { - new SaveImageTask(imageUrl, getReactApplicationContext(), promise, true).execute(); - } - - @ReactMethod - public void deleteTempImage(String imageUrl, final Promise promise) { - boolean success = true; - String imagePath = imageUrl.replace("file://", ""); - File imageFile = new File(imagePath); - if (imageFile.exists()) { - success = imageFile.delete(); - } - - if (promise != null) { - WritableMap result = Arguments.createMap(); - result.putBoolean("success", success); - promise.resolve(result); - } - } -} diff --git a/android/src/main/java/com/wix/RNCameraKit/gallery/ResourceDrawableIdHelper.java b/android/src/main/java/com/wix/RNCameraKit/gallery/ResourceDrawableIdHelper.java deleted file mode 100644 index c629a88390..0000000000 --- a/android/src/main/java/com/wix/RNCameraKit/gallery/ResourceDrawableIdHelper.java +++ /dev/null @@ -1,123 +0,0 @@ -package com.wix.RNCameraKit.gallery; - -/** - * Created by yedidyak on 18/07/2016. - */ -import android.content.Context; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.graphics.drawable.BitmapDrawable; -import android.graphics.drawable.Drawable; -import android.net.Uri; -import android.os.StrictMode; - -import com.facebook.common.util.UriUtil; - -import java.net.URL; -import java.util.HashMap; -import java.util.Map; - -import javax.annotation.Nullable; - -/** - * Helper class for obtaining information about local images. - */ -public class ResourceDrawableIdHelper { - - private Map mResourceDrawableIdMap; - - public ResourceDrawableIdHelper() { - mResourceDrawableIdMap = new HashMap<>(); - } - - public int getResourceDrawableId(Context context, @Nullable String name) { - if (name == null || name.isEmpty()) { - return 0; - } - name = name.toLowerCase().replace("-", "_"); - if (mResourceDrawableIdMap.containsKey(name)) { - return mResourceDrawableIdMap.get(name); - } - int id = context.getResources().getIdentifier( - name, - "drawable", - context.getPackageName()); - mResourceDrawableIdMap.put(name, id); - return id; - } - - @Nullable - public Drawable getResourceDrawable(Context context, @Nullable String name) { - int resId = getResourceDrawableId(context, name); - return resId > 0 ? context.getResources().getDrawable(resId) : null; - } - - public Uri getResourceDrawableUri(Context context, @Nullable String name) { - int resId = getResourceDrawableId(context, name); - return resId > 0 ? new Uri.Builder() - .scheme(UriUtil.LOCAL_RESOURCE_SCHEME) - .path(String.valueOf(resId)) - .build() : Uri.EMPTY; - } - - public static final String LOCAL_RESOURCE_URI_SCHEME = "res"; - private static ResourceDrawableIdHelper sResDrawableIdHelper = new ResourceDrawableIdHelper(); - - public static Drawable getIcon(Context ctx, String iconSource) { - return getIcon(ctx, iconSource, -1); - } - - /** - * @param iconSource Icon source. In release builds this would be a path in assets, In debug it's - * a url and the image needs to be decoded from input stream. - * @param dimensions The requested icon dimensions - */ - public static Drawable getIcon(Context ctx, String iconSource, int dimensions) { - if (iconSource == null) { - return null; - } - - try { - Drawable icon; - Uri iconUri = getIconUri(ctx, iconSource); - - if (LOCAL_RESOURCE_URI_SCHEME.equals(iconUri.getScheme())) { - icon = sResDrawableIdHelper.getResourceDrawable(ctx, iconSource); - } else { - URL url = new URL(iconUri.toString()); - - StrictMode.ThreadPolicy oldPolicy = StrictMode.getThreadPolicy(); - StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build(); - StrictMode.setThreadPolicy(policy); - Bitmap bitmap = BitmapFactory.decodeStream(url.openStream()); - StrictMode.setThreadPolicy(oldPolicy); - bitmap = dimensions > 0 ? - Bitmap.createScaledBitmap(bitmap, dimensions, dimensions, false) : bitmap; - icon = new BitmapDrawable(ctx.getResources(), bitmap); - } - return icon; - } catch (Exception e) { - e.printStackTrace(); - } - return null; - } - - private static Uri getIconUri(Context context, String iconSource) { - Uri ret = null; - if (iconSource != null) { - try { - ret = Uri.parse(iconSource); - // Verify scheme is set, so that relative uri (used by static resources) are not handled. - if (ret.getScheme() == null) { - ret = null; - } - } catch (Exception e) { - // Ignore malformed uri, then attempt to extract resource ID. - } - if (ret == null) { - ret = sResDrawableIdHelper.getResourceDrawableUri(context, iconSource); - } - } - return ret; - } -} \ No newline at end of file diff --git a/android/src/main/java/com/wix/RNCameraKit/gallery/SelectableImage.java b/android/src/main/java/com/wix/RNCameraKit/gallery/SelectableImage.java deleted file mode 100644 index 253ce8d0a1..0000000000 --- a/android/src/main/java/com/wix/RNCameraKit/gallery/SelectableImage.java +++ /dev/null @@ -1,191 +0,0 @@ -package com.wix.RNCameraKit.gallery; - -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.graphics.Color; -import android.graphics.Matrix; -import android.graphics.drawable.Drawable; -import android.provider.MediaStore; -import android.util.TypedValue; -import android.view.Gravity; -import android.view.View; -import android.widget.FrameLayout; -import android.widget.ImageView; -import android.widget.LinearLayout; -import android.widget.TextView; - -import com.facebook.react.bridge.ReactContext; -import com.wix.RNCameraKit.Utils; - -import java.util.concurrent.ThreadPoolExecutor; - -import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; -import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; - -public class SelectableImage extends FrameLayout { - private static final int MINI_THUMB_HEIGHT = 512; - private static final int MINI_THUMB_WIDTH = 384; - - private static final int DEFAULT_SELECTED_IMAGE_GRAVITY = Gravity.TOP | Gravity.RIGHT; - - public static final int SELECTED_IMAGE_NORMAL_SIZE_DP = 22; - public static final int SELECTED_IMAGE_LARGE_SIZE_DP = 36; - - private final ImageView imageView; - private final ImageView selectedView; - private final ReactContext reactContext; - private final View selectedOverlay; - - private int id = -1; - private Runnable currentLoader; - private Drawable selectedDrawable; - private Drawable unselectedDrawable; - private LinearLayout unsupportedLayout; - private ImageView unsupportedImage; - private TextView unsupportedTextView; - private int selectedOverlayColor = Color.parseColor("#80FFFFFF"); - private boolean selected; - private int inSampleSize; - - public SelectableImage(ReactContext reactContext, Integer selectedImageGravity, Integer selectedImageSize) { - super(reactContext.getApplicationContext()); - this.reactContext = reactContext; - - setPadding(1, 1, 1, 1); - setBackgroundColor(0xedeff0); - imageView = new ImageView(reactContext); - addView(imageView, MATCH_PARENT, MATCH_PARENT); - - selectedOverlay = new View(reactContext); - addView(selectedOverlay, MATCH_PARENT, MATCH_PARENT); - - selectedView = new ImageView(reactContext); - addView(selectedView, createSelectedImageParams(selectedImageGravity, selectedImageSize)); - - createUnsupportedView(); - } - - public void setUnsupportedUIParams(String overlayColor, Drawable unsupportedFinalImage, String unsupportedText, String unsupportedTextColor) { - unsupportedLayout.setBackgroundColor(overlayColor != null ? Color.parseColor(overlayColor) : Color.TRANSPARENT); - unsupportedImage.setImageDrawable(unsupportedFinalImage); - unsupportedTextView.setTextColor(unsupportedTextColor != null ? Color.parseColor(unsupportedTextColor) : Color.WHITE); - unsupportedTextView.setText(unsupportedText); - - unsupportedImage.setVisibility(unsupportedFinalImage != null ? VISIBLE : GONE); - unsupportedTextView.setVisibility(unsupportedText != null && !unsupportedText.isEmpty() ? VISIBLE : GONE); - } - - private void createUnsupportedView() { - unsupportedLayout = new LinearLayout(getContext()); - unsupportedLayout.setBackgroundColor(Color.RED); - addView(unsupportedLayout, MATCH_PARENT, MATCH_PARENT); - unsupportedLayout.setOrientation(LinearLayout.VERTICAL); - unsupportedLayout.setGravity(Gravity.CENTER); - unsupportedLayout.setPadding(10, 10, 10, 10); - - unsupportedImage = new ImageView(getContext()); - unsupportedImage.setScaleType(ImageView.ScaleType.FIT_CENTER); - unsupportedLayout.addView(unsupportedImage, new LinearLayout.LayoutParams(MATCH_PARENT, 0, 1)); - - unsupportedTextView = new TextView(getContext()); - unsupportedTextView.setGravity(Gravity.CENTER); - unsupportedLayout.addView(unsupportedTextView, WRAP_CONTENT, WRAP_CONTENT); - } - - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - super.onMeasure(widthMeasureSpec, widthMeasureSpec); - } - - @Override - protected void onSizeChanged(int w, int h, int oldw, int oldh) { - super.onSizeChanged(w, h, oldw, oldh); - this.inSampleSize = Utils.calculateInSampleSize(MINI_THUMB_WIDTH,MINI_THUMB_HEIGHT,w, h); - } - - - public void setScaleType(ImageView.ScaleType scaleType) { - imageView.setScaleType(scaleType); - } - - public void bind(ThreadPoolExecutor executor, boolean selected, boolean forceBind, final Integer id, boolean supported,final Integer orientation) { - this.selected = selected; - selectedView.setImageDrawable(selected ? selectedDrawable : unselectedDrawable); - if (this.id != id || forceBind) { - this.id = id; - imageView.setImageBitmap(null); - imageView.setBackgroundColor(Color.LTGRAY); - if (currentLoader != null) { - executor.remove(currentLoader); - } - - currentLoader = new Runnable() { - - public Bitmap orient(final Bitmap bmp,final Integer orientation){ - if (orientation != 0) { - Matrix matrix = new Matrix(); - matrix.postRotate(orientation); - return Bitmap.createBitmap(bmp, 0, 0, bmp.getWidth(), bmp.getHeight(), matrix, true); - } - return bmp; - } - @Override - public void run() { - BitmapFactory.Options options = new BitmapFactory.Options(); - if (inSampleSize == 0) { - inSampleSize = Utils.calculateInSampleSize(MINI_THUMB_WIDTH,MINI_THUMB_HEIGHT, getWidth(), getHeight()); - } - options.inSampleSize = inSampleSize; - - final Bitmap bmp = orient(MediaStore.Images.Thumbnails.getThumbnail( - getContext().getContentResolver(), - id, - MediaStore.Images.Thumbnails.MINI_KIND, - options), orientation); - - if (SelectableImage.this.id == id) { - reactContext.runOnUiQueueThread(new Runnable() { - @Override - public void run() { - imageView.setImageBitmap(bmp); - } - }); - } - } - }; - executor.execute(currentLoader); - } - unsupportedLayout.setVisibility(supported ? GONE : VISIBLE); - selectedView.setVisibility(supported ? VISIBLE : GONE); - } - - @Override - public boolean isSelected() { - return selected; - } - - @Override - public void setSelected(boolean selected) { - this.selected = selected; - selectedView.setImageDrawable(selected ? selectedDrawable : unselectedDrawable); - selectedOverlay.setBackgroundColor(selected ? this.selectedOverlayColor : Color.TRANSPARENT); - } - - public void setDrawables(Drawable selectedDrawable, Drawable unselectedDrawable, Integer overlayColor) { - this.selectedDrawable = selectedDrawable; - this.unselectedDrawable = unselectedDrawable; - this.selectedOverlayColor = overlayColor != null ? overlayColor : Color.parseColor("#80FFFFFF"); - } - - - private LayoutParams createSelectedImageParams(Integer gravity, Integer sizeDp) { - gravity = gravity != null ? gravity : DEFAULT_SELECTED_IMAGE_GRAVITY; - sizeDp = sizeDp != null ? sizeDp : SELECTED_IMAGE_NORMAL_SIZE_DP; - - final int sizePx = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, sizeDp, getResources().getDisplayMetrics()); - - final LayoutParams params = new FrameLayout.LayoutParams(sizePx, sizePx, gravity); - params.setMargins(30, 30, 30, 30); - return params; - } -} diff --git a/android/src/main/java/com/wix/RNCameraKit/gallery/TapCustomButtonEvent.java b/android/src/main/java/com/wix/RNCameraKit/gallery/TapCustomButtonEvent.java deleted file mode 100644 index 8a1a56531d..0000000000 --- a/android/src/main/java/com/wix/RNCameraKit/gallery/TapCustomButtonEvent.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.wix.RNCameraKit.gallery; - -import com.facebook.react.bridge.Arguments; -import com.facebook.react.bridge.WritableMap; -import com.facebook.react.uimanager.events.Event; -import com.facebook.react.uimanager.events.RCTEventEmitter; - -public class TapCustomButtonEvent extends Event { - - private final int targetTag; - private WritableMap event; - - TapCustomButtonEvent(int targetTag) { - this.targetTag = targetTag; - event = Arguments.createMap(); - event.putString("id", "onCustomButtonPress"); - init(0); - } - - @Override - public String getEventName() { - return "onCustomButtonPress"; - } - - @Override - public void dispatch(RCTEventEmitter rctEventEmitter) { - rctEventEmitter.receiveEvent(targetTag, "onCustomButtonPress", event); - } -} diff --git a/android/src/main/java/com/wix/RNCameraKit/gallery/TapImageEvent.java b/android/src/main/java/com/wix/RNCameraKit/gallery/TapImageEvent.java deleted file mode 100644 index bd51a4499a..0000000000 --- a/android/src/main/java/com/wix/RNCameraKit/gallery/TapImageEvent.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.wix.RNCameraKit.gallery; - -import com.facebook.react.bridge.Arguments; -import com.facebook.react.bridge.WritableMap; -import com.facebook.react.uimanager.events.Event; -import com.facebook.react.uimanager.events.RCTEventEmitter; - -public class TapImageEvent extends Event { - - private final int targetTag; - private WritableMap event; - - TapImageEvent(int targetTag, String uri, Integer width, Integer height) { - this.targetTag = targetTag; - event = Arguments.createMap(); - event.putString("selected", uri); - event.putString("id", "onTapImage"); - event.putInt("width", width); - event.putInt("height", height); - init(0); - } - - @Override - public String getEventName() { - return "onTapImage"; - } - - @Override - public void dispatch(RCTEventEmitter rctEventEmitter) { - rctEventEmitter.receiveEvent(targetTag, "onTapImage", event); - } -} - diff --git a/android/src/main/java/com/wix/RNCameraKit/gallery/permission/GalleryViewWrapper.java b/android/src/main/java/com/wix/RNCameraKit/gallery/permission/GalleryViewWrapper.java deleted file mode 100644 index 0e271c14b7..0000000000 --- a/android/src/main/java/com/wix/RNCameraKit/gallery/permission/GalleryViewWrapper.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.wix.RNCameraKit.gallery.permission; - -import android.graphics.Color; -import android.view.ViewGroup; -import android.widget.FrameLayout; - -import com.wix.RNCameraKit.gallery.GalleryView; - -public class GalleryViewWrapper extends FrameLayout { - - GalleryView view; - - public GalleryViewWrapper(GalleryView galleryView) { - super(galleryView.getContext()); - view = galleryView; - addView(view); - setLayoutParams(new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); - setBackgroundColor(Color.GREEN); - } - - public void replaceGalleryView(GalleryView newGalleryView) { - removeView(view); - view = newGalleryView; - addView(newGalleryView); - setLayoutParams(new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); - } - - public GalleryView getGalleryView() { - return view; - } -} diff --git a/android/src/main/java/com/wix/RNCameraKit/gallery/permission/StoragePermission.java b/android/src/main/java/com/wix/RNCameraKit/gallery/permission/StoragePermission.java deleted file mode 100644 index 63e4050858..0000000000 --- a/android/src/main/java/com/wix/RNCameraKit/gallery/permission/StoragePermission.java +++ /dev/null @@ -1,80 +0,0 @@ -package com.wix.RNCameraKit.gallery.permission; - -import android.Manifest; -import android.app.Activity; -import android.support.v4.app.ActivityCompat; -import android.support.v4.content.PermissionChecker; - -import com.facebook.react.bridge.Promise; -import com.wix.RNCameraKit.SharedPrefs; - -public class StoragePermission { - private static final int STORAGE_PERMISSION_REQUEST_CODE = 1001; - private static final int PERMISSION_GRANTED = 1; - private static final int PERMISSION_NOT_DETERMINED = -1; - private static final int PERMISSION_DENIED = 0; - private Promise requestAccessPromise; - - public void requestAccess(Activity activity, Promise promise) { - if (isReadWritePermissionsGranted(activity)) { - promise.resolve(true); - return; - } - requestAccessPromise = promise; - permissionRequested(activity, Manifest.permission.READ_EXTERNAL_STORAGE); - permissionRequested(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE); - ActivityCompat.requestPermissions(activity, - new String[]{Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE}, - STORAGE_PERMISSION_REQUEST_CODE); - } - - public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { - if (isStoragePermission(requestCode, permissions)) { - if (requestAccessPromise != null) { - requestAccessPromise.resolve(grantResults[0] == PermissionChecker.PERMISSION_GRANTED && grantResults[1] == PermissionChecker.PERMISSION_GRANTED); - requestAccessPromise = null; - } - } - } - - private boolean isStoragePermission(int requestCode, String[] permissions) { - return requestCode == STORAGE_PERMISSION_REQUEST_CODE && - Manifest.permission.READ_EXTERNAL_STORAGE.equals(permissions[0]) && - Manifest.permission.WRITE_EXTERNAL_STORAGE.equals(permissions[1]); - } - - public int checkAuthorizationStatus(Activity activity) { - final int readStatus = checkPermission(activity, Manifest.permission.READ_EXTERNAL_STORAGE); - final int writeStatus = checkPermission(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE); - if (readStatus == PERMISSION_GRANTED && writeStatus == PERMISSION_GRANTED) { - return PERMISSION_GRANTED; - } - if (readStatus == PERMISSION_NOT_DETERMINED && writeStatus == PERMISSION_NOT_DETERMINED) { - return PERMISSION_NOT_DETERMINED; - } - return PERMISSION_DENIED; - } - - private int checkPermission(Activity activity, String permissionName) { - final int statusCode = PermissionChecker.checkCallingOrSelfPermission(activity, permissionName); - if (statusCode == PermissionChecker.PERMISSION_GRANTED) { - return PERMISSION_GRANTED; - } - if (requestingPermissionForFirstTime(activity, permissionName)) { - return PERMISSION_NOT_DETERMINED; - } - return PERMISSION_DENIED; - } - - private boolean requestingPermissionForFirstTime(Activity activity, String permissionName) { - return !SharedPrefs.getBoolean(activity, permissionName); - } - - private void permissionRequested(Activity activity, String permissionName) { - SharedPrefs.putBoolean(activity, permissionName, true); - } - - private boolean isReadWritePermissionsGranted(Activity activity) { - return checkAuthorizationStatus(activity) == PERMISSION_GRANTED; - } -} diff --git a/android/src/main/java/com/wix/RNCameraKit/gallery/permission/StoragePermissionRequestCallback.java b/android/src/main/java/com/wix/RNCameraKit/gallery/permission/StoragePermissionRequestCallback.java deleted file mode 100644 index 4ce2e22b10..0000000000 --- a/android/src/main/java/com/wix/RNCameraKit/gallery/permission/StoragePermissionRequestCallback.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.wix.RNCameraKit.gallery.permission; - -import com.wix.RNCameraKit.gallery.NativeGalleryModule; - -public class StoragePermissionRequestCallback { - private NativeGalleryModule galleryModule; - - public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { - galleryModule.onRequestPermissionsResult(requestCode, permissions, grantResults); - } - - public void setGalleryModule(NativeGalleryModule galleryModule) { - this.galleryModule = galleryModule; - } -} diff --git a/android/src/paper/java/com/facebook/react/viewmanagers/CKCameraManagerDelegate.java b/android/src/paper/java/com/facebook/react/viewmanagers/CKCameraManagerDelegate.java new file mode 100644 index 0000000000..96c9b840e8 --- /dev/null +++ b/android/src/paper/java/com/facebook/react/viewmanagers/CKCameraManagerDelegate.java @@ -0,0 +1,89 @@ +/** +* This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). +* +* Do not edit this file as changes may cause incorrect behavior and will be lost +* once the code is regenerated. +* +* @generated by codegen project: GeneratePropsJavaDelegate.js +*/ + +package com.facebook.react.viewmanagers; + +import android.view.View; +import androidx.annotation.Nullable; +import com.facebook.react.bridge.ColorPropConverter; +import com.facebook.react.uimanager.BaseViewManagerDelegate; +import com.facebook.react.uimanager.BaseViewManagerInterface; + +public class CKCameraManagerDelegate & CKCameraManagerInterface> extends BaseViewManagerDelegate { + public CKCameraManagerDelegate(U viewManager) { + super(viewManager); + } + @Override + public void setProperty(T view, String propName, @Nullable Object value) { + switch (propName) { + case "flashMode": + mViewManager.setFlashMode(view, value == null ? null : (String) value); + break; + case "focusMode": + mViewManager.setFocusMode(view, value == null ? null : (String) value); + break; + case "zoomMode": + mViewManager.setZoomMode(view, value == null ? null : (String) value); + break; + case "zoom": + mViewManager.setZoom(view, value == null ? 0f : ((Double) value).doubleValue()); + break; + case "maxZoom": + mViewManager.setMaxZoom(view, value == null ? 0f : ((Double) value).doubleValue()); + break; + case "torchMode": + mViewManager.setTorchMode(view, value == null ? null : (String) value); + break; + case "cameraType": + mViewManager.setCameraType(view, value == null ? null : (String) value); + break; + case "scanBarcode": + mViewManager.setScanBarcode(view, value == null ? false : (boolean) value); + break; + case "showFrame": + mViewManager.setShowFrame(view, value == null ? false : (boolean) value); + break; + case "laserColor": + mViewManager.setLaserColor(view, ColorPropConverter.getColor(value, view.getContext())); + break; + case "frameColor": + mViewManager.setFrameColor(view, ColorPropConverter.getColor(value, view.getContext())); + break; + case "ratioOverlay": + mViewManager.setRatioOverlay(view, value == null ? null : (String) value); + break; + case "ratioOverlayColor": + mViewManager.setRatioOverlayColor(view, ColorPropConverter.getColor(value, view.getContext())); + break; + case "resetFocusTimeout": + mViewManager.setResetFocusTimeout(view, value == null ? 0 : ((Double) value).intValue()); + break; + case "resetFocusWhenMotionDetected": + mViewManager.setResetFocusWhenMotionDetected(view, value == null ? false : (boolean) value); + break; + case "resizeMode": + mViewManager.setResizeMode(view, value == null ? null : (String) value); + break; + case "scanThrottleDelay": + mViewManager.setScanThrottleDelay(view, value == null ? 0 : ((Double) value).intValue()); + break; + case "shutterPhotoSound": + mViewManager.setShutterPhotoSound(view, value == null ? false : (boolean) value); + break; + case "shutterAnimationDuration": + mViewManager.setShutterAnimationDuration(view, value == null ? 0 : ((Double) value).intValue()); + break; + case "outputPath": + mViewManager.setOutputPath(view, value == null ? null : (String) value); + break; + default: + super.setProperty(view, propName, value); + } + } +} diff --git a/android/src/paper/java/com/facebook/react/viewmanagers/CKCameraManagerInterface.java b/android/src/paper/java/com/facebook/react/viewmanagers/CKCameraManagerInterface.java new file mode 100644 index 0000000000..25cd980c3f --- /dev/null +++ b/android/src/paper/java/com/facebook/react/viewmanagers/CKCameraManagerInterface.java @@ -0,0 +1,36 @@ +/** +* This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). +* +* Do not edit this file as changes may cause incorrect behavior and will be lost +* once the code is regenerated. +* +* @generated by codegen project: GeneratePropsJavaInterface.js +*/ + +package com.facebook.react.viewmanagers; + +import android.view.View; +import androidx.annotation.Nullable; + +public interface CKCameraManagerInterface { + void setFlashMode(T view, @Nullable String value); + void setFocusMode(T view, @Nullable String value); + void setZoomMode(T view, @Nullable String value); + void setZoom(T view, double value); + void setMaxZoom(T view, double value); + void setTorchMode(T view, @Nullable String value); + void setCameraType(T view, @Nullable String value); + void setScanBarcode(T view, boolean value); + void setShowFrame(T view, boolean value); + void setLaserColor(T view, @Nullable Integer value); + void setFrameColor(T view, @Nullable Integer value); + void setRatioOverlay(T view, @Nullable String value); + void setRatioOverlayColor(T view, @Nullable Integer value); + void setResetFocusTimeout(T view, int value); + void setResetFocusWhenMotionDetected(T view, boolean value); + void setResizeMode(T view, @Nullable String value); + void setScanThrottleDelay(T view, int value); + void setShutterPhotoSound(T view, boolean value); + void setShutterAnimationDuration(T view, int value); + void setOutputPath(T view, @Nullable String value); +} diff --git a/android/src/paper/java/com/rncamerakit/NativeCameraKitModuleSpec.java b/android/src/paper/java/com/rncamerakit/NativeCameraKitModuleSpec.java new file mode 100644 index 0000000000..7f1a03e8c2 --- /dev/null +++ b/android/src/paper/java/com/rncamerakit/NativeCameraKitModuleSpec.java @@ -0,0 +1,48 @@ + +/** + * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). + * + * Do not edit this file as changes may cause incorrect behavior and will be lost + * once the code is regenerated. + * + * @generated by codegen project: GenerateModuleJavaSpec.js + * + * @nolint + */ + +package com.rncamerakit; + +import com.facebook.proguard.annotations.DoNotStrip; +import com.facebook.react.bridge.Promise; +import com.facebook.react.bridge.ReactApplicationContext; +import com.facebook.react.bridge.ReactContextBaseJavaModule; +import com.facebook.react.bridge.ReactMethod; +import com.facebook.react.bridge.ReadableMap; +import com.facebook.react.turbomodule.core.interfaces.TurboModule; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +public abstract class NativeCameraKitModuleSpec extends ReactContextBaseJavaModule implements TurboModule { + public static final String NAME = "RNCameraKitModule"; + + public NativeCameraKitModuleSpec(ReactApplicationContext reactContext) { + super(reactContext); + } + + @Override + public @Nonnull String getName() { + return NAME; + } + + @ReactMethod + @DoNotStrip + public abstract void capture(@Nullable ReadableMap options, @Nullable Double tag, Promise promise); + + @ReactMethod + @DoNotStrip + public abstract void requestDeviceCameraAuthorization(Promise promise); + + @ReactMethod + @DoNotStrip + public abstract void checkDeviceCameraAuthorizationStatus(Promise promise); +} diff --git a/babel.config.js b/babel.config.js new file mode 100644 index 0000000000..f7b3da3b33 --- /dev/null +++ b/babel.config.js @@ -0,0 +1,3 @@ +module.exports = { + presets: ['module:@react-native/babel-preset'], +}; diff --git a/docs/kotlin.md b/docs/kotlin.md new file mode 100644 index 0000000000..dbcbc5bd9c --- /dev/null +++ b/docs/kotlin.md @@ -0,0 +1,52 @@ +# Add Kotlin Support for Android + +1. Open and edit android/build.gradle + +Add the `kotlin_version` to `buildscript.ext`. If you are using React Native `0.73` or higher, you should already have a variable called `kotlinVersion` defined inside of here, so remember you can reference this instead of repeating the version number twice: + +``` +buildscript { + ext { + ... + kotlinVersion = '1.7.20' // Variable now included for React Native core + kotlin_version = kotlinVersion // Used by react-native-camera-kit + } +} +``` + +Add `google()` to the `buildscript.repositories` and `allprojects.repositories` + +``` +buildscript { + repositories { + ... + google() + } +} + +allprojects { + repositories { + ... + google() + } +} +``` + +Add the Kotlin classpath to `buildscript.dependencies` + +``` +dependencies { + ... + classpath("com.android.tools.build:gradle:7.0.2") // or recent + classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version") +} +``` + +2. Open and edit android/app/build.gradle + +Add Kotlin imports + +``` +apply plugin: "kotlin-android" +apply plugin: "kotlin-android-extensions" +``` \ No newline at end of file diff --git a/example-android/app/BUCK b/example-android/app/BUCK deleted file mode 100644 index 13beceff25..0000000000 --- a/example-android/app/BUCK +++ /dev/null @@ -1,65 +0,0 @@ -# To learn about Buck see [Docs](https://buckbuild.com/). -# To run your application with Buck: -# - install Buck -# - `npm start` - to start the packager -# - `cd android` -# - `keytool -genkey -v -keystore keystores/debug.keystore -storepass android -alias androiddebugkey -keypass android -dname "CN=Android Debug,O=Android,C=US"` -# - `./gradlew :app:copyDownloadableDepsToLibs` - make all Gradle compile dependencies available to Buck -# - `buck install -r android/app` - compile, install and run application -# - -lib_deps = [] - -for jarfile in glob(['libs/*.jar']): - name = 'jars__' + jarfile[jarfile.rindex('/') + 1: jarfile.rindex('.jar')] - lib_deps.append(':' + name) - prebuilt_jar( - name = name, - binary_jar = jarfile, - ) - -for aarfile in glob(['libs/*.aar']): - name = 'aars__' + aarfile[aarfile.rindex('/') + 1: aarfile.rindex('.aar')] - lib_deps.append(':' + name) - android_prebuilt_aar( - name = name, - aar = aarfile, - ) - -android_library( - name = "all-libs", - exported_deps = lib_deps, -) - -android_library( - name = "app-code", - srcs = glob([ - "src/main/java/**/*.java", - ]), - deps = [ - ":all-libs", - ":build_config", - ":res", - ], -) - -android_build_config( - name = "build_config", - package = "com.camerakit", -) - -android_resource( - name = "res", - package = "com.camerakit", - res = "src/main/res", -) - -android_binary( - name = "app", - keystore = "//android/keystores:debug", - manifest = "src/main/AndroidManifest.xml", - package_type = "debug", - deps = [ - ":app-code", - ], -) diff --git a/example-android/app/build.gradle b/example-android/app/build.gradle deleted file mode 100644 index c69a28b744..0000000000 --- a/example-android/app/build.gradle +++ /dev/null @@ -1,95 +0,0 @@ -apply plugin: "com.android.application" - -import com.android.build.OutputFile - - -project.ext.react = [ - entryFile: "index.js" -] - -apply from: "../../node_modules/react-native/react.gradle" - -/** - * Set this to true to create two separate APKs instead of one: - * - An APK that only works on ARM devices - * - An APK that only works on x86 devices - * The advantage is the size of the APK is reduced by about 4MB. - * Upload all the APKs to the Play Store and people will download - * the correct one based on the CPU architecture of their device. - */ -def enableSeparateBuildPerCPUArchitecture = false - -/** - * Run Proguard to shrink the Java bytecode in release builds. - */ -def enableProguardInReleaseBuilds = false - -android { - compileSdkVersion 26 - buildToolsVersion '26.0.2' - - defaultConfig { - applicationId "com.camerakit" - minSdkVersion 21 - targetSdkVersion 25 - versionCode 1 - versionName "1.0" - ndk { - abiFilters "armeabi-v7a", "x86" - } - multiDexEnabled true - } - splits { - abi { - reset() - enable enableSeparateBuildPerCPUArchitecture - universalApk false // If true, also generate a universal APK - include "armeabi-v7a", "x86" - } - } - buildTypes { - release { - 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: - // http://tools.android.com/tech-docs/new-build-system/user-guide/apk-splits - def versionCodes = ["armeabi-v7a":1, "x86":2] - def abi = output.getFilter(OutputFile.ABI) - if (abi != null) { // null for the universal-debug, universal-release variants - output.versionCodeOverride = - versionCodes.get(abi) * 1048576 + defaultConfig.versionCode - } - } - } -} - -configurations.all { - resolutionStrategy.eachDependency { DependencyResolveDetails details -> - def requested = details.requested - if (requested.group == 'com.android.support') { - if (!requested.name.startsWith("multidex")) { - details.useVersion "26.0.1" - } - } - } -} - -dependencies { - compile fileTree(dir: "libs", include: ["*.jar"]) - compile project(":rncamerakit") - compile "com.android.support:appcompat-v7:26.0.1" - compile 'com.android.support:multidex:1.0.3' - compile "com.facebook.react:react-native:+" // From node_modules -} - -// Run this once to be able to run the application with BUCK -// puts all compile dependencies into folder libs for BUCK to use -task copyDownloadableDepsToLibs(type: Copy) { - from configurations.compile - into 'libs' -} diff --git a/example-android/app/proguard-rules.pro b/example-android/app/proguard-rules.pro deleted file mode 100644 index 6e8516c8d6..0000000000 --- a/example-android/app/proguard-rules.pro +++ /dev/null @@ -1,70 +0,0 @@ -# Add project specific ProGuard rules here. -# By default, the flags in this file are appended to flags specified -# in /usr/local/Cellar/android-sdk/24.3.3/tools/proguard/proguard-android.txt -# You can edit the include path and order by changing the proguardFiles -# directive in build.gradle. -# -# For more details, see -# http://developer.android.com/guide/developing/tools/proguard.html - -# Add any project specific keep options here: - -# If your project uses WebView with JS, uncomment the following -# and specify the fully qualified class name to the JavaScript interface -# class: -#-keepclassmembers class fqcn.of.javascript.interface.for.webview { -# public *; -#} - -# Disabling obfuscation is useful if you collect stack traces from production crashes -# (unless you are using a system that supports de-obfuscate the stack traces). --dontobfuscate - -# React Native - -# Keep our interfaces so they can be used by other ProGuard rules. -# See http://sourceforge.net/p/proguard/bugs/466/ --keep,allowobfuscation @interface com.facebook.proguard.annotations.DoNotStrip --keep,allowobfuscation @interface com.facebook.proguard.annotations.KeepGettersAndSetters --keep,allowobfuscation @interface com.facebook.common.internal.DoNotStrip - -# Do not strip any method/class that is annotated with @DoNotStrip --keep @com.facebook.proguard.annotations.DoNotStrip class * --keep @com.facebook.common.internal.DoNotStrip class * --keepclassmembers class * { - @com.facebook.proguard.annotations.DoNotStrip *; - @com.facebook.common.internal.DoNotStrip *; -} - --keepclassmembers @com.facebook.proguard.annotations.KeepGettersAndSetters class * { - void set*(***); - *** get*(); -} - --keep class * extends com.facebook.react.bridge.JavaScriptModule { *; } --keep class * extends com.facebook.react.bridge.NativeModule { *; } --keepclassmembers,includedescriptorclasses class * { native ; } --keepclassmembers class * { @com.facebook.react.uimanager.UIProp ; } --keepclassmembers class * { @com.facebook.react.uimanager.annotations.ReactProp ; } --keepclassmembers class * { @com.facebook.react.uimanager.annotations.ReactPropGroup ; } - --dontwarn com.facebook.react.** - -# TextLayoutBuilder uses a non-public Android constructor within StaticLayout. -# See libs/proxy/src/main/java/com/facebook/fbui/textlayoutbuilder/proxy for details. --dontwarn android.text.StaticLayout - -# okhttp - --keepattributes Signature --keepattributes *Annotation* --keep class okhttp3.** { *; } --keep interface okhttp3.** { *; } --dontwarn okhttp3.** - -# okio - --keep class sun.misc.Unsafe { *; } --dontwarn java.nio.file.* --dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement --dontwarn okio.** diff --git a/example-android/app/src/main/java/com/camerakit/MainActivity.java b/example-android/app/src/main/java/com/camerakit/MainActivity.java deleted file mode 100644 index 3d90d79597..0000000000 --- a/example-android/app/src/main/java/com/camerakit/MainActivity.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.camerakit; - -import com.facebook.react.ReactActivity; - -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 "CameraKit"; - } -} diff --git a/example-android/app/src/main/java/com/camerakit/MainApplication.java b/example-android/app/src/main/java/com/camerakit/MainApplication.java deleted file mode 100644 index f142e8e644..0000000000 --- a/example-android/app/src/main/java/com/camerakit/MainApplication.java +++ /dev/null @@ -1,56 +0,0 @@ -package com.camerakit; - -import android.app.Application; -import android.content.Context; -import android.support.multidex.MultiDex; - -import com.facebook.react.ReactApplication; -import com.facebook.react.ReactNativeHost; -import com.facebook.react.ReactPackage; -import com.facebook.react.shell.MainReactPackage; -import com.facebook.soloader.SoLoader; -import com.wix.RNCameraKit.RNCameraKitPackage; - -import java.util.Arrays; -import java.util.List; - -public class MainApplication extends Application implements ReactApplication { - - private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) { - @Override - public boolean getUseDeveloperSupport() { - return BuildConfig.DEBUG; - } - - @Override - protected List getPackages() { - return Arrays.asList( - new MainReactPackage(), - new RNCameraKitPackage() - - ); - } - - @Override - protected String getJSMainModuleName() { - return "index"; - } - }; - - @Override - protected void attachBaseContext(Context base) { - super.attachBaseContext(base); - MultiDex.install(this); - } - - @Override - public ReactNativeHost getReactNativeHost() { - return mReactNativeHost; - } - - @Override - public void onCreate() { - super.onCreate(); - SoLoader.init(this, /* native exopackage */ false); - } -} diff --git a/example-android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/example-android/app/src/main/res/mipmap-hdpi/ic_launcher.png deleted file mode 100644 index cde69bccce..0000000000 Binary files a/example-android/app/src/main/res/mipmap-hdpi/ic_launcher.png and /dev/null differ diff --git a/example-android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/example-android/app/src/main/res/mipmap-mdpi/ic_launcher.png deleted file mode 100644 index c133a0cbd3..0000000000 Binary files a/example-android/app/src/main/res/mipmap-mdpi/ic_launcher.png and /dev/null differ diff --git a/example-android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/example-android/app/src/main/res/mipmap-xhdpi/ic_launcher.png deleted file mode 100644 index bfa42f0e7b..0000000000 Binary files a/example-android/app/src/main/res/mipmap-xhdpi/ic_launcher.png and /dev/null differ diff --git a/example-android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/example-android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png deleted file mode 100644 index 324e72cdd7..0000000000 Binary files a/example-android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png and /dev/null differ diff --git a/example-android/app/src/main/res/values/strings.xml b/example-android/app/src/main/res/values/strings.xml deleted file mode 100644 index 252d798486..0000000000 --- a/example-android/app/src/main/res/values/strings.xml +++ /dev/null @@ -1,3 +0,0 @@ - - CameraKit - diff --git a/example-android/app/src/main/res/values/styles.xml b/example-android/app/src/main/res/values/styles.xml deleted file mode 100644 index 319eb0ca10..0000000000 --- a/example-android/app/src/main/res/values/styles.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - diff --git a/example-android/build.gradle b/example-android/build.gradle deleted file mode 100644 index 0476390880..0000000000 --- a/example-android/build.gradle +++ /dev/null @@ -1,41 +0,0 @@ -// Top-level build file where you can add configuration options common to all sub-projects/modules. - -buildscript { - repositories { - jcenter() - google() - } - dependencies { - classpath 'com.android.tools.build:gradle:3.3.0' - - // NOTE: Do not place your application dependencies here; they belong - // in the individual module build.gradle files - } -} - -allprojects { - repositories { - mavenLocal() - jcenter() - maven { - // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm - url "$rootDir/../node_modules/react-native/android" - } - google() - } -} - -subprojects { - task allDeps(type: DependencyReportTask) {} - afterEvaluate { - android { - compileSdkVersion 26 - buildToolsVersion "26.0.1" - - defaultConfig { - minSdkVersion 21 - targetSdkVersion 25 - } - } - } -} diff --git a/example-android/gradle.properties b/example-android/gradle.properties deleted file mode 100644 index 1fd964e90b..0000000000 --- a/example-android/gradle.properties +++ /dev/null @@ -1,20 +0,0 @@ -# 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: -Xmx10248m -XX:MaxPermSize=256m -# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 - -# 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 - -android.useDeprecatedNdk=true diff --git a/example-android/gradle/wrapper/gradle-wrapper.jar b/example-android/gradle/wrapper/gradle-wrapper.jar deleted file mode 100644 index b5166dad4d..0000000000 Binary files a/example-android/gradle/wrapper/gradle-wrapper.jar and /dev/null differ diff --git a/example-android/gradlew b/example-android/gradlew deleted file mode 100755 index 91a7e269e1..0000000000 --- a/example-android/gradlew +++ /dev/null @@ -1,164 +0,0 @@ -#!/usr/bin/env bash - -############################################################################## -## -## Gradle start up script for UN*X -## -############################################################################## - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS="" - -APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` - -# Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" - -warn ( ) { - echo "$*" -} - -die ( ) { - echo - echo "$*" - echo - exit 1 -} - -# OS specific support (must be 'true' or 'false'). -cygwin=false -msys=false -darwin=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; -esac - -# For Cygwin, ensure paths are in UNIX format before anything is touched. -if $cygwin ; then - [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` -fi - -# Attempt to set APP_HOME -# Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi -done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >&- -APP_HOME="`pwd -P`" -cd "$SAVED" >&- - -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" = "false" -a "$darwin" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi -fi - -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi - -# For Cygwin, switch paths to Windows format before running java -if $cygwin ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi - # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" - fi - i=$((i+1)) - done - case $i in - (0) set -- ;; - (1) set -- "$args0" ;; - (2) set -- "$args0" "$args1" ;; - (3) set -- "$args0" "$args1" "$args2" ;; - (4) set -- "$args0" "$args1" "$args2" "$args3" ;; - (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac -fi - -# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules -function splitJvmOpts() { - JVM_OPTS=("$@") -} -eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS -JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" - -exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" diff --git a/example-android/gradlew.bat b/example-android/gradlew.bat deleted file mode 100644 index aec99730b4..0000000000 --- a/example-android/gradlew.bat +++ /dev/null @@ -1,90 +0,0 @@ -@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 - -@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= - -set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@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 init - -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 init - -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 - -:init -@rem Get command-line arguments, handling Windowz variants - -if not "%OS%" == "Windows_NT" goto win9xME_args -if "%@eval[2+2]" == "4" goto 4NT_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* -goto execute - -:4NT_args -@rem Get arguments from the 4NT Shell from JP Software -set CMD_LINE_ARGS=%$ - -: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 %CMD_LINE_ARGS% - -: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/example-android/keystores/BUCK b/example-android/keystores/BUCK deleted file mode 100644 index 88e4c31b28..0000000000 --- a/example-android/keystores/BUCK +++ /dev/null @@ -1,8 +0,0 @@ -keystore( - name = "debug", - properties = "debug.keystore.properties", - store = "debug.keystore", - visibility = [ - "PUBLIC", - ], -) diff --git a/example-android/keystores/debug.keystore.properties b/example-android/keystores/debug.keystore.properties deleted file mode 100644 index 121bfb49f0..0000000000 --- a/example-android/keystores/debug.keystore.properties +++ /dev/null @@ -1,4 +0,0 @@ -key.store=debug.keystore -key.alias=androiddebugkey -key.store.password=android -key.alias.password=android diff --git a/example-android/settings.gradle b/example-android/settings.gradle deleted file mode 100644 index 86ab90abe1..0000000000 --- a/example-android/settings.gradle +++ /dev/null @@ -1,5 +0,0 @@ -rootProject.name = 'CameraKit' - -include ':app' -include ':rncamerakit' -project(':rncamerakit').projectDir = new File(rootProject.projectDir, '../android/') \ No newline at end of file diff --git a/example-ios/CameraKit.xcodeproj/project.pbxproj b/example-ios/CameraKit.xcodeproj/project.pbxproj deleted file mode 100644 index aedfbc691f..0000000000 --- a/example-ios/CameraKit.xcodeproj/project.pbxproj +++ /dev/null @@ -1,1109 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 46; - objects = { - -/* Begin PBXBuildFile section */ - 00C302E51ABCBA2D00DB3ED1 /* libRCTActionSheet.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302AC1ABCB8CE00DB3ED1 /* libRCTActionSheet.a */; }; - 00C302E71ABCBA2D00DB3ED1 /* libRCTGeolocation.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302BA1ABCB90400DB3ED1 /* libRCTGeolocation.a */; }; - 00C302E81ABCBA2D00DB3ED1 /* libRCTImage.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302C01ABCB91800DB3ED1 /* libRCTImage.a */; }; - 00C302E91ABCBA2D00DB3ED1 /* libRCTNetwork.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302DC1ABCB9D200DB3ED1 /* libRCTNetwork.a */; }; - 00C302EA1ABCBA2D00DB3ED1 /* libRCTVibration.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302E41ABCB9EE00DB3ED1 /* libRCTVibration.a */; }; - 133E29F31AD74F7200F7D852 /* libRCTLinking.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 78C398B91ACF4ADC00677621 /* libRCTLinking.a */; }; - 139105C61AF99C1200B5F7CC /* libRCTSettings.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 139105C11AF99BAD00B5F7CC /* libRCTSettings.a */; }; - 139FDEF61B0652A700C62182 /* libRCTWebSocket.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 139FDEF41B06529B00C62182 /* libRCTWebSocket.a */; }; - 13B07FBC1A68108700A75B9A /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB01A68108700A75B9A /* AppDelegate.m */; }; - 13B07FBD1A68108700A75B9A /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB11A68108700A75B9A /* LaunchScreen.xib */; }; - 13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; }; - 13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; }; - 146834051AC3E58100842450 /* libReact.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 146834041AC3E56700842450 /* libReact.a */; }; - 26B5A76D226CBBE600A3B2CE /* JavaScriptCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 26B5A746226CBBE600A3B2CE /* JavaScriptCore.framework */; }; - 26E00EA5205AA8530012807E /* libReactNativeCameraKit.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 26E00EA3205AA8440012807E /* libReactNativeCameraKit.a */; }; - 5E9157361DD0AC6A00FF2AA8 /* libRCTAnimation.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E9157331DD0AC6500FF2AA8 /* libRCTAnimation.a */; }; - 832341BD1AAA6AB300B99B32 /* libRCTText.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 832341B51AAA6A8300B99B32 /* libRCTText.a */; }; - ADBDB9381DFEBF1600ED6528 /* libRCTBlob.a in Frameworks */ = {isa = PBXBuildFile; fileRef = ADBDB9271DFEBF0700ED6528 /* libRCTBlob.a */; }; -/* End PBXBuildFile section */ - -/* Begin PBXContainerItemProxy section */ - 00C302AB1ABCB8CE00DB3ED1 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 00C302A71ABCB8CE00DB3ED1 /* RCTActionSheet.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 134814201AA4EA6300B7C361; - remoteInfo = RCTActionSheet; - }; - 00C302B91ABCB90400DB3ED1 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 00C302B51ABCB90400DB3ED1 /* RCTGeolocation.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 134814201AA4EA6300B7C361; - remoteInfo = RCTGeolocation; - }; - 00C302BF1ABCB91800DB3ED1 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 00C302BB1ABCB91800DB3ED1 /* RCTImage.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 58B5115D1A9E6B3D00147676; - remoteInfo = RCTImage; - }; - 00C302DB1ABCB9D200DB3ED1 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 00C302D31ABCB9D200DB3ED1 /* RCTNetwork.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 58B511DB1A9E6C8500147676; - remoteInfo = RCTNetwork; - }; - 00C302E31ABCB9EE00DB3ED1 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 00C302DF1ABCB9EE00DB3ED1 /* RCTVibration.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 832C81801AAF6DEF007FA2F7; - remoteInfo = RCTVibration; - }; - 139105C01AF99BAD00B5F7CC /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 139105B61AF99BAD00B5F7CC /* RCTSettings.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 134814201AA4EA6300B7C361; - remoteInfo = RCTSettings; - }; - 139FDEF31B06529B00C62182 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 3C86DF461ADF2C930047B81A; - remoteInfo = RCTWebSocket; - }; - 146834031AC3E56700842450 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 83CBBA2E1A601D0E00E9B192; - remoteInfo = React; - }; - 265DDC97226C8F8500F1A4E5 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = EBF21BDC1FC498900052F4D5; - remoteInfo = jsinspector; - }; - 265DDC99226C8F8500F1A4E5 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = EBF21BFA1FC4989A0052F4D5; - remoteInfo = "jsinspector-tvOS"; - }; - 265DDC9B226C8F8500F1A4E5 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = EDEBC6D6214B3E7000DD5AC8; - remoteInfo = jsi; - }; - 265DDC9D226C8F8500F1A4E5 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = EDEBC73B214B45A300DD5AC8; - remoteInfo = jsiexecutor; - }; - 265DDC9F226C8F8500F1A4E5 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = ED296FB6214C9A0900B7C4FE; - remoteInfo = "jsi-tvOS"; - }; - 265DDCA1226C8F8500F1A4E5 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = ED296FEE214C9CF800B7C4FE; - remoteInfo = "jsiexecutor-tvOS"; - }; - 268B384C2187149E0054268D /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 139D7ECE1E25DB7D00323FB7; - remoteInfo = "third-party"; - }; - 268B384E2187149E0054268D /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 3D383D3C1EBD27B6005632C8; - remoteInfo = "third-party-tvOS"; - }; - 268B38502187149E0054268D /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 139D7E881E25C6D100323FB7; - remoteInfo = "double-conversion"; - }; - 268B38522187149E0054268D /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 3D383D621EBD27B9005632C8; - remoteInfo = "double-conversion-tvOS"; - }; - 26E00E88205AA5BB0012807E /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = ADBDB91F1DFEBF0600ED6528 /* RCTBlob.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = ADD01A681E09402E00F6D226; - remoteInfo = "RCTBlob-tvOS"; - }; - 26E00E9A205AA5BB0012807E /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 3DBE0D001F3B181A0099AA32; - remoteInfo = fishhook; - }; - 26E00E9C205AA5BB0012807E /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 3DBE0D0D1F3B181C0099AA32; - remoteInfo = "fishhook-tvOS"; - }; - 26E00EA2205AA8440012807E /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 26E00E9E205AA8440012807E /* ReactNativeCameraKit.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 2646934E1CFB2A6B00F3A740; - remoteInfo = ReactNativeCameraKit; - }; - 3DAD3E831DF850E9000B6D8A /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 00C302BB1ABCB91800DB3ED1 /* RCTImage.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 2D2A283A1D9B042B00D4039D; - remoteInfo = "RCTImage-tvOS"; - }; - 3DAD3E871DF850E9000B6D8A /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 78C398B01ACF4ADC00677621 /* RCTLinking.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 2D2A28471D9B043800D4039D; - remoteInfo = "RCTLinking-tvOS"; - }; - 3DAD3E8B1DF850E9000B6D8A /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 00C302D31ABCB9D200DB3ED1 /* RCTNetwork.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 2D2A28541D9B044C00D4039D; - remoteInfo = "RCTNetwork-tvOS"; - }; - 3DAD3E8F1DF850E9000B6D8A /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 139105B61AF99BAD00B5F7CC /* RCTSettings.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 2D2A28611D9B046600D4039D; - remoteInfo = "RCTSettings-tvOS"; - }; - 3DAD3E931DF850E9000B6D8A /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 2D2A287B1D9B048500D4039D; - remoteInfo = "RCTText-tvOS"; - }; - 3DAD3E981DF850E9000B6D8A /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 2D2A28881D9B049200D4039D; - remoteInfo = "RCTWebSocket-tvOS"; - }; - 3DAD3EA21DF850E9000B6D8A /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 2D2A28131D9B038B00D4039D; - remoteInfo = "React-tvOS"; - }; - 3DAD3EA41DF850E9000B6D8A /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 3D3C059A1DE3340900C268FA; - remoteInfo = yoga; - }; - 3DAD3EA61DF850E9000B6D8A /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 3D3C06751DE3340C00C268FA; - remoteInfo = "yoga-tvOS"; - }; - 3DAD3EA81DF850E9000B6D8A /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 3D3CD9251DE5FBEC00167DC4; - remoteInfo = cxxreact; - }; - 3DAD3EAA1DF850E9000B6D8A /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 3D3CD9321DE5FBEE00167DC4; - remoteInfo = "cxxreact-tvOS"; - }; - 5E9157321DD0AC6500FF2AA8 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 5E91572D1DD0AC6500FF2AA8 /* RCTAnimation.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 134814201AA4EA6300B7C361; - remoteInfo = RCTAnimation; - }; - 5E9157341DD0AC6500FF2AA8 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 5E91572D1DD0AC6500FF2AA8 /* RCTAnimation.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 2D2A28201D9B03D100D4039D; - remoteInfo = "RCTAnimation-tvOS"; - }; - 78C398B81ACF4ADC00677621 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 78C398B01ACF4ADC00677621 /* RCTLinking.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 134814201AA4EA6300B7C361; - remoteInfo = RCTLinking; - }; - 832341B41AAA6A8300B99B32 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 58B5119B1A9E6C1200147676; - remoteInfo = RCTText; - }; - ADBDB9261DFEBF0700ED6528 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = ADBDB91F1DFEBF0600ED6528 /* RCTBlob.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 358F4ED71D1E81A9004DF814; - remoteInfo = RCTBlob; - }; -/* End PBXContainerItemProxy section */ - -/* Begin PBXFileReference section */ - 008F07F21AC5B25A0029DE68 /* main.jsbundle */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = main.jsbundle; sourceTree = ""; }; - 00C302A71ABCB8CE00DB3ED1 /* RCTActionSheet.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTActionSheet.xcodeproj; path = "../node_modules/react-native/Libraries/ActionSheetIOS/RCTActionSheet.xcodeproj"; sourceTree = ""; }; - 00C302B51ABCB90400DB3ED1 /* RCTGeolocation.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTGeolocation.xcodeproj; path = "../node_modules/react-native/Libraries/Geolocation/RCTGeolocation.xcodeproj"; sourceTree = ""; }; - 00C302BB1ABCB91800DB3ED1 /* RCTImage.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTImage.xcodeproj; path = "../node_modules/react-native/Libraries/Image/RCTImage.xcodeproj"; sourceTree = ""; }; - 00C302D31ABCB9D200DB3ED1 /* RCTNetwork.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTNetwork.xcodeproj; path = "../node_modules/react-native/Libraries/Network/RCTNetwork.xcodeproj"; sourceTree = ""; }; - 00C302DF1ABCB9EE00DB3ED1 /* RCTVibration.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTVibration.xcodeproj; path = "../node_modules/react-native/Libraries/Vibration/RCTVibration.xcodeproj"; sourceTree = ""; }; - 139105B61AF99BAD00B5F7CC /* RCTSettings.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTSettings.xcodeproj; path = "../node_modules/react-native/Libraries/Settings/RCTSettings.xcodeproj"; sourceTree = ""; }; - 139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTWebSocket.xcodeproj; path = "../node_modules/react-native/Libraries/WebSocket/RCTWebSocket.xcodeproj"; sourceTree = ""; }; - 13B07F961A680F5B00A75B9A /* CameraKit.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = CameraKit.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 13B07FAF1A68108700A75B9A /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = CameraKit/AppDelegate.h; sourceTree = ""; }; - 13B07FB01A68108700A75B9A /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AppDelegate.m; path = CameraKit/AppDelegate.m; sourceTree = ""; }; - 13B07FB21A68108700A75B9A /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = ""; }; - 13B07FB51A68108700A75B9A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = CameraKit/Images.xcassets; sourceTree = ""; }; - 13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = CameraKit/Info.plist; sourceTree = ""; }; - 13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = CameraKit/main.m; sourceTree = ""; }; - 146833FF1AC3E56700842450 /* React.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = React.xcodeproj; path = "../node_modules/react-native/React/React.xcodeproj"; sourceTree = ""; }; - 26B5A746226CBBE600A3B2CE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; }; - 26E00E9E205AA8440012807E /* ReactNativeCameraKit.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = ReactNativeCameraKit.xcodeproj; path = ../ios/lib/ReactNativeCameraKit.xcodeproj; sourceTree = ""; }; - 5E91572D1DD0AC6500FF2AA8 /* RCTAnimation.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTAnimation.xcodeproj; path = "../node_modules/react-native/Libraries/NativeAnimation/RCTAnimation.xcodeproj"; sourceTree = ""; }; - 78C398B01ACF4ADC00677621 /* RCTLinking.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTLinking.xcodeproj; path = "../node_modules/react-native/Libraries/LinkingIOS/RCTLinking.xcodeproj"; sourceTree = ""; }; - 832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTText.xcodeproj; path = "../node_modules/react-native/Libraries/Text/RCTText.xcodeproj"; sourceTree = ""; }; - ADBDB91F1DFEBF0600ED6528 /* RCTBlob.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTBlob.xcodeproj; path = "../node_modules/react-native/Libraries/Blob/RCTBlob.xcodeproj"; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 13B07F8C1A680F5B00A75B9A /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 26B5A76D226CBBE600A3B2CE /* JavaScriptCore.framework in Frameworks */, - 26E00EA5205AA8530012807E /* libReactNativeCameraKit.a in Frameworks */, - ADBDB9381DFEBF1600ED6528 /* libRCTBlob.a in Frameworks */, - 5E9157361DD0AC6A00FF2AA8 /* libRCTAnimation.a in Frameworks */, - 146834051AC3E58100842450 /* libReact.a in Frameworks */, - 5E9157361DD0AC6A00FF2AA8 /* libRCTAnimation.a in Frameworks */, - 00C302E51ABCBA2D00DB3ED1 /* libRCTActionSheet.a in Frameworks */, - 00C302E71ABCBA2D00DB3ED1 /* libRCTGeolocation.a in Frameworks */, - 00C302E81ABCBA2D00DB3ED1 /* libRCTImage.a in Frameworks */, - 133E29F31AD74F7200F7D852 /* libRCTLinking.a in Frameworks */, - 00C302E91ABCBA2D00DB3ED1 /* libRCTNetwork.a in Frameworks */, - 139105C61AF99C1200B5F7CC /* libRCTSettings.a in Frameworks */, - 832341BD1AAA6AB300B99B32 /* libRCTText.a in Frameworks */, - 00C302EA1ABCBA2D00DB3ED1 /* libRCTVibration.a in Frameworks */, - 139FDEF61B0652A700C62182 /* libRCTWebSocket.a in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 00C302A81ABCB8CE00DB3ED1 /* Products */ = { - isa = PBXGroup; - children = ( - 00C302AC1ABCB8CE00DB3ED1 /* libRCTActionSheet.a */, - ); - name = Products; - sourceTree = ""; - }; - 00C302B61ABCB90400DB3ED1 /* Products */ = { - isa = PBXGroup; - children = ( - 00C302BA1ABCB90400DB3ED1 /* libRCTGeolocation.a */, - ); - name = Products; - sourceTree = ""; - }; - 00C302BC1ABCB91800DB3ED1 /* Products */ = { - isa = PBXGroup; - children = ( - 00C302C01ABCB91800DB3ED1 /* libRCTImage.a */, - 3DAD3E841DF850E9000B6D8A /* libRCTImage-tvOS.a */, - ); - name = Products; - sourceTree = ""; - }; - 00C302D41ABCB9D200DB3ED1 /* Products */ = { - isa = PBXGroup; - children = ( - 00C302DC1ABCB9D200DB3ED1 /* libRCTNetwork.a */, - 3DAD3E8C1DF850E9000B6D8A /* libRCTNetwork-tvOS.a */, - ); - name = Products; - sourceTree = ""; - }; - 00C302E01ABCB9EE00DB3ED1 /* Products */ = { - isa = PBXGroup; - children = ( - 00C302E41ABCB9EE00DB3ED1 /* libRCTVibration.a */, - ); - name = Products; - sourceTree = ""; - }; - 139105B71AF99BAD00B5F7CC /* Products */ = { - isa = PBXGroup; - children = ( - 139105C11AF99BAD00B5F7CC /* libRCTSettings.a */, - 3DAD3E901DF850E9000B6D8A /* libRCTSettings-tvOS.a */, - ); - name = Products; - sourceTree = ""; - }; - 139FDEE71B06529A00C62182 /* Products */ = { - isa = PBXGroup; - children = ( - 139FDEF41B06529B00C62182 /* libRCTWebSocket.a */, - 3DAD3E991DF850E9000B6D8A /* libRCTWebSocket-tvOS.a */, - 26E00E9B205AA5BB0012807E /* libfishhook.a */, - 26E00E9D205AA5BB0012807E /* libfishhook-tvOS.a */, - ); - name = Products; - sourceTree = ""; - }; - 13B07FAE1A68108700A75B9A /* CameraKit */ = { - isa = PBXGroup; - children = ( - 008F07F21AC5B25A0029DE68 /* main.jsbundle */, - 13B07FAF1A68108700A75B9A /* AppDelegate.h */, - 13B07FB01A68108700A75B9A /* AppDelegate.m */, - 13B07FB51A68108700A75B9A /* Images.xcassets */, - 13B07FB61A68108700A75B9A /* Info.plist */, - 13B07FB11A68108700A75B9A /* LaunchScreen.xib */, - 13B07FB71A68108700A75B9A /* main.m */, - ); - name = CameraKit; - sourceTree = ""; - }; - 146834001AC3E56700842450 /* Products */ = { - isa = PBXGroup; - children = ( - 146834041AC3E56700842450 /* libReact.a */, - 3DAD3EA31DF850E9000B6D8A /* libReact.a */, - 3DAD3EA51DF850E9000B6D8A /* libyoga.a */, - 3DAD3EA71DF850E9000B6D8A /* libyoga.a */, - 3DAD3EA91DF850E9000B6D8A /* libcxxreact.a */, - 3DAD3EAB1DF850E9000B6D8A /* libcxxreact.a */, - 265DDC98226C8F8500F1A4E5 /* libjsinspector.a */, - 265DDC9A226C8F8500F1A4E5 /* libjsinspector-tvOS.a */, - 268B384D2187149E0054268D /* libthird-party.a */, - 268B384F2187149E0054268D /* libthird-party.a */, - 268B38512187149E0054268D /* libdouble-conversion.a */, - 268B38532187149E0054268D /* libdouble-conversion.a */, - 265DDC9C226C8F8500F1A4E5 /* libjsi.a */, - 265DDC9E226C8F8500F1A4E5 /* libjsiexecutor.a */, - 265DDCA0226C8F8500F1A4E5 /* libjsi-tvOS.a */, - 265DDCA2226C8F8500F1A4E5 /* libjsiexecutor-tvOS.a */, - ); - name = Products; - sourceTree = ""; - }; - 26E00E9F205AA8440012807E /* Products */ = { - isa = PBXGroup; - children = ( - 26E00EA3205AA8440012807E /* libReactNativeCameraKit.a */, - ); - name = Products; - sourceTree = ""; - }; - 26E00EA4205AA8530012807E /* Frameworks */ = { - isa = PBXGroup; - children = ( - 26B5A746226CBBE600A3B2CE /* JavaScriptCore.framework */, - ); - name = Frameworks; - sourceTree = ""; - }; - 5E91572E1DD0AC6500FF2AA8 /* Products */ = { - isa = PBXGroup; - children = ( - 5E9157331DD0AC6500FF2AA8 /* libRCTAnimation.a */, - 5E9157351DD0AC6500FF2AA8 /* libRCTAnimation.a */, - ); - name = Products; - sourceTree = ""; - }; - 78C398B11ACF4ADC00677621 /* Products */ = { - isa = PBXGroup; - children = ( - 78C398B91ACF4ADC00677621 /* libRCTLinking.a */, - 3DAD3E881DF850E9000B6D8A /* libRCTLinking-tvOS.a */, - ); - name = Products; - sourceTree = ""; - }; - 832341AE1AAA6A7D00B99B32 /* Libraries */ = { - isa = PBXGroup; - children = ( - 26E00E9E205AA8440012807E /* ReactNativeCameraKit.xcodeproj */, - 5E91572D1DD0AC6500FF2AA8 /* RCTAnimation.xcodeproj */, - 146833FF1AC3E56700842450 /* React.xcodeproj */, - 00C302A71ABCB8CE00DB3ED1 /* RCTActionSheet.xcodeproj */, - ADBDB91F1DFEBF0600ED6528 /* RCTBlob.xcodeproj */, - 00C302B51ABCB90400DB3ED1 /* RCTGeolocation.xcodeproj */, - 00C302BB1ABCB91800DB3ED1 /* RCTImage.xcodeproj */, - 78C398B01ACF4ADC00677621 /* RCTLinking.xcodeproj */, - 00C302D31ABCB9D200DB3ED1 /* RCTNetwork.xcodeproj */, - 139105B61AF99BAD00B5F7CC /* RCTSettings.xcodeproj */, - 832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */, - 00C302DF1ABCB9EE00DB3ED1 /* RCTVibration.xcodeproj */, - 139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */, - ); - name = Libraries; - sourceTree = ""; - }; - 832341B11AAA6A8300B99B32 /* Products */ = { - isa = PBXGroup; - children = ( - 832341B51AAA6A8300B99B32 /* libRCTText.a */, - 3DAD3E941DF850E9000B6D8A /* libRCTText-tvOS.a */, - ); - name = Products; - sourceTree = ""; - }; - 83CBB9F61A601CBA00E9B192 = { - isa = PBXGroup; - children = ( - 13B07FAE1A68108700A75B9A /* CameraKit */, - 832341AE1AAA6A7D00B99B32 /* Libraries */, - 83CBBA001A601CBA00E9B192 /* Products */, - 26E00EA4205AA8530012807E /* Frameworks */, - ); - indentWidth = 2; - sourceTree = ""; - tabWidth = 2; - usesTabs = 0; - }; - 83CBBA001A601CBA00E9B192 /* Products */ = { - isa = PBXGroup; - children = ( - 13B07F961A680F5B00A75B9A /* CameraKit.app */, - ); - name = Products; - sourceTree = ""; - }; - ADBDB9201DFEBF0600ED6528 /* Products */ = { - isa = PBXGroup; - children = ( - ADBDB9271DFEBF0700ED6528 /* libRCTBlob.a */, - 26E00E89205AA5BB0012807E /* libRCTBlob-tvOS.a */, - ); - name = Products; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - 13B07F861A680F5B00A75B9A /* CameraKit */ = { - isa = PBXNativeTarget; - buildConfigurationList = 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "CameraKit" */; - buildPhases = ( - 13B07F871A680F5B00A75B9A /* Sources */, - 13B07F8C1A680F5B00A75B9A /* Frameworks */, - 13B07F8E1A680F5B00A75B9A /* Resources */, - 00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = CameraKit; - productName = "Hello World"; - productReference = 13B07F961A680F5B00A75B9A /* CameraKit.app */; - productType = "com.apple.product-type.application"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 83CBB9F71A601CBA00E9B192 /* Project object */ = { - isa = PBXProject; - attributes = { - LastUpgradeCheck = 0610; - ORGANIZATIONNAME = Facebook; - TargetAttributes = { - 13B07F861A680F5B00A75B9A = { - DevelopmentTeam = S3GLW74Y8N; - }; - }; - }; - buildConfigurationList = 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "CameraKit" */; - compatibilityVersion = "Xcode 3.2"; - developmentRegion = English; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - ); - mainGroup = 83CBB9F61A601CBA00E9B192; - productRefGroup = 83CBBA001A601CBA00E9B192 /* Products */; - projectDirPath = ""; - projectReferences = ( - { - ProductGroup = 00C302A81ABCB8CE00DB3ED1 /* Products */; - ProjectRef = 00C302A71ABCB8CE00DB3ED1 /* RCTActionSheet.xcodeproj */; - }, - { - ProductGroup = 5E91572E1DD0AC6500FF2AA8 /* Products */; - ProjectRef = 5E91572D1DD0AC6500FF2AA8 /* RCTAnimation.xcodeproj */; - }, - { - ProductGroup = ADBDB9201DFEBF0600ED6528 /* Products */; - ProjectRef = ADBDB91F1DFEBF0600ED6528 /* RCTBlob.xcodeproj */; - }, - { - ProductGroup = 00C302B61ABCB90400DB3ED1 /* Products */; - ProjectRef = 00C302B51ABCB90400DB3ED1 /* RCTGeolocation.xcodeproj */; - }, - { - ProductGroup = 00C302BC1ABCB91800DB3ED1 /* Products */; - ProjectRef = 00C302BB1ABCB91800DB3ED1 /* RCTImage.xcodeproj */; - }, - { - ProductGroup = 78C398B11ACF4ADC00677621 /* Products */; - ProjectRef = 78C398B01ACF4ADC00677621 /* RCTLinking.xcodeproj */; - }, - { - ProductGroup = 00C302D41ABCB9D200DB3ED1 /* Products */; - ProjectRef = 00C302D31ABCB9D200DB3ED1 /* RCTNetwork.xcodeproj */; - }, - { - ProductGroup = 139105B71AF99BAD00B5F7CC /* Products */; - ProjectRef = 139105B61AF99BAD00B5F7CC /* RCTSettings.xcodeproj */; - }, - { - ProductGroup = 832341B11AAA6A8300B99B32 /* Products */; - ProjectRef = 832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */; - }, - { - ProductGroup = 00C302E01ABCB9EE00DB3ED1 /* Products */; - ProjectRef = 00C302DF1ABCB9EE00DB3ED1 /* RCTVibration.xcodeproj */; - }, - { - ProductGroup = 139FDEE71B06529A00C62182 /* Products */; - ProjectRef = 139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */; - }, - { - ProductGroup = 146834001AC3E56700842450 /* Products */; - ProjectRef = 146833FF1AC3E56700842450 /* React.xcodeproj */; - }, - { - ProductGroup = 26E00E9F205AA8440012807E /* Products */; - ProjectRef = 26E00E9E205AA8440012807E /* ReactNativeCameraKit.xcodeproj */; - }, - ); - projectRoot = ""; - targets = ( - 13B07F861A680F5B00A75B9A /* CameraKit */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXReferenceProxy section */ - 00C302AC1ABCB8CE00DB3ED1 /* libRCTActionSheet.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libRCTActionSheet.a; - remoteRef = 00C302AB1ABCB8CE00DB3ED1 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 00C302BA1ABCB90400DB3ED1 /* libRCTGeolocation.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libRCTGeolocation.a; - remoteRef = 00C302B91ABCB90400DB3ED1 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 00C302C01ABCB91800DB3ED1 /* libRCTImage.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libRCTImage.a; - remoteRef = 00C302BF1ABCB91800DB3ED1 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 00C302DC1ABCB9D200DB3ED1 /* libRCTNetwork.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libRCTNetwork.a; - remoteRef = 00C302DB1ABCB9D200DB3ED1 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 00C302E41ABCB9EE00DB3ED1 /* libRCTVibration.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libRCTVibration.a; - remoteRef = 00C302E31ABCB9EE00DB3ED1 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 139105C11AF99BAD00B5F7CC /* libRCTSettings.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libRCTSettings.a; - remoteRef = 139105C01AF99BAD00B5F7CC /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 139FDEF41B06529B00C62182 /* libRCTWebSocket.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libRCTWebSocket.a; - remoteRef = 139FDEF31B06529B00C62182 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 146834041AC3E56700842450 /* libReact.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libReact.a; - remoteRef = 146834031AC3E56700842450 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 265DDC98226C8F8500F1A4E5 /* libjsinspector.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libjsinspector.a; - remoteRef = 265DDC97226C8F8500F1A4E5 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 265DDC9A226C8F8500F1A4E5 /* libjsinspector-tvOS.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = "libjsinspector-tvOS.a"; - remoteRef = 265DDC99226C8F8500F1A4E5 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 265DDC9C226C8F8500F1A4E5 /* libjsi.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libjsi.a; - remoteRef = 265DDC9B226C8F8500F1A4E5 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 265DDC9E226C8F8500F1A4E5 /* libjsiexecutor.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libjsiexecutor.a; - remoteRef = 265DDC9D226C8F8500F1A4E5 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 265DDCA0226C8F8500F1A4E5 /* libjsi-tvOS.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = "libjsi-tvOS.a"; - remoteRef = 265DDC9F226C8F8500F1A4E5 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 265DDCA2226C8F8500F1A4E5 /* libjsiexecutor-tvOS.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = "libjsiexecutor-tvOS.a"; - remoteRef = 265DDCA1226C8F8500F1A4E5 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 268B384D2187149E0054268D /* libthird-party.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = "libthird-party.a"; - remoteRef = 268B384C2187149E0054268D /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 268B384F2187149E0054268D /* libthird-party.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = "libthird-party.a"; - remoteRef = 268B384E2187149E0054268D /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 268B38512187149E0054268D /* libdouble-conversion.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = "libdouble-conversion.a"; - remoteRef = 268B38502187149E0054268D /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 268B38532187149E0054268D /* libdouble-conversion.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = "libdouble-conversion.a"; - remoteRef = 268B38522187149E0054268D /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 26E00E89205AA5BB0012807E /* libRCTBlob-tvOS.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = "libRCTBlob-tvOS.a"; - remoteRef = 26E00E88205AA5BB0012807E /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 26E00E9B205AA5BB0012807E /* libfishhook.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libfishhook.a; - remoteRef = 26E00E9A205AA5BB0012807E /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 26E00E9D205AA5BB0012807E /* libfishhook-tvOS.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = "libfishhook-tvOS.a"; - remoteRef = 26E00E9C205AA5BB0012807E /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 26E00EA3205AA8440012807E /* libReactNativeCameraKit.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libReactNativeCameraKit.a; - remoteRef = 26E00EA2205AA8440012807E /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 3DAD3E841DF850E9000B6D8A /* libRCTImage-tvOS.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = "libRCTImage-tvOS.a"; - remoteRef = 3DAD3E831DF850E9000B6D8A /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 3DAD3E881DF850E9000B6D8A /* libRCTLinking-tvOS.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = "libRCTLinking-tvOS.a"; - remoteRef = 3DAD3E871DF850E9000B6D8A /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 3DAD3E8C1DF850E9000B6D8A /* libRCTNetwork-tvOS.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = "libRCTNetwork-tvOS.a"; - remoteRef = 3DAD3E8B1DF850E9000B6D8A /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 3DAD3E901DF850E9000B6D8A /* libRCTSettings-tvOS.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = "libRCTSettings-tvOS.a"; - remoteRef = 3DAD3E8F1DF850E9000B6D8A /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 3DAD3E941DF850E9000B6D8A /* libRCTText-tvOS.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = "libRCTText-tvOS.a"; - remoteRef = 3DAD3E931DF850E9000B6D8A /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 3DAD3E991DF850E9000B6D8A /* libRCTWebSocket-tvOS.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = "libRCTWebSocket-tvOS.a"; - remoteRef = 3DAD3E981DF850E9000B6D8A /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 3DAD3EA31DF850E9000B6D8A /* libReact.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libReact.a; - remoteRef = 3DAD3EA21DF850E9000B6D8A /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 3DAD3EA51DF850E9000B6D8A /* libyoga.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libyoga.a; - remoteRef = 3DAD3EA41DF850E9000B6D8A /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 3DAD3EA71DF850E9000B6D8A /* libyoga.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libyoga.a; - remoteRef = 3DAD3EA61DF850E9000B6D8A /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 3DAD3EA91DF850E9000B6D8A /* libcxxreact.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libcxxreact.a; - remoteRef = 3DAD3EA81DF850E9000B6D8A /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 3DAD3EAB1DF850E9000B6D8A /* libcxxreact.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libcxxreact.a; - remoteRef = 3DAD3EAA1DF850E9000B6D8A /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 5E9157331DD0AC6500FF2AA8 /* libRCTAnimation.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libRCTAnimation.a; - remoteRef = 5E9157321DD0AC6500FF2AA8 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 5E9157351DD0AC6500FF2AA8 /* libRCTAnimation.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libRCTAnimation.a; - remoteRef = 5E9157341DD0AC6500FF2AA8 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 78C398B91ACF4ADC00677621 /* libRCTLinking.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libRCTLinking.a; - remoteRef = 78C398B81ACF4ADC00677621 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 832341B51AAA6A8300B99B32 /* libRCTText.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libRCTText.a; - remoteRef = 832341B41AAA6A8300B99B32 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - ADBDB9271DFEBF0700ED6528 /* libRCTBlob.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libRCTBlob.a; - remoteRef = ADBDB9261DFEBF0700ED6528 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; -/* End PBXReferenceProxy section */ - -/* Begin PBXResourcesBuildPhase section */ - 13B07F8E1A680F5B00A75B9A /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */, - 13B07FBD1A68108700A75B9A /* LaunchScreen.xib in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXShellScriptBuildPhase section */ - 00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "Bundle React Native code and images"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "export NODE_BINARY=node\n../node_modules/react-native/scripts/react-native-xcode.sh"; - }; -/* End PBXShellScriptBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 13B07F871A680F5B00A75B9A /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 13B07FBC1A68108700A75B9A /* AppDelegate.m in Sources */, - 13B07FC11A68108700A75B9A /* main.m in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXVariantGroup section */ - 13B07FB11A68108700A75B9A /* LaunchScreen.xib */ = { - isa = PBXVariantGroup; - children = ( - 13B07FB21A68108700A75B9A /* Base */, - ); - name = LaunchScreen.xib; - path = CameraKit; - sourceTree = ""; - }; -/* End PBXVariantGroup section */ - -/* Begin XCBuildConfiguration section */ - 13B07F941A680F5B00A75B9A /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CURRENT_PROJECT_VERSION = 1; - DEAD_CODE_STRIPPING = NO; - DEVELOPMENT_TEAM = S3GLW74Y8N; - INFOPLIST_FILE = CameraKit/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - OTHER_LDFLAGS = ( - "$(inherited)", - "-ObjC", - "-lc++", - ); - PRODUCT_NAME = CameraKit; - VERSIONING_SYSTEM = "apple-generic"; - }; - name = Debug; - }; - 13B07F951A680F5B00A75B9A /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = S3GLW74Y8N; - INFOPLIST_FILE = CameraKit/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - OTHER_LDFLAGS = ( - "$(inherited)", - "-ObjC", - "-lc++", - ); - PRODUCT_NAME = CameraKit; - VERSIONING_SYSTEM = "apple-generic"; - }; - name = Release; - }; - 83CBBA201A601CBA00E9B192 /* 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_BOOL_CONVERSION = 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_INT_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - 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; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_DYNAMIC_NO_PIC = NO; - 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 = 10.0; - MTL_ENABLE_DEBUG_INFO = YES; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = iphoneos; - }; - name = Debug; - }; - 83CBBA211A601CBA00E9B192 /* 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_BOOL_CONVERSION = 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_INT_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - 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; - GCC_C_LANGUAGE_STANDARD = gnu99; - 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 = 10.0; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = iphoneos; - VALIDATE_PRODUCT = YES; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "CameraKit" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 13B07F941A680F5B00A75B9A /* Debug */, - 13B07F951A680F5B00A75B9A /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "CameraKit" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 83CBBA201A601CBA00E9B192 /* Debug */, - 83CBBA211A601CBA00E9B192 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = 83CBB9F71A601CBA00E9B192 /* Project object */; -} diff --git a/example-ios/CameraKit.xcodeproj/xcshareddata/xcschemes/CameraKit-tvOS.xcscheme b/example-ios/CameraKit.xcodeproj/xcshareddata/xcschemes/CameraKit-tvOS.xcscheme deleted file mode 100644 index a27b97fa22..0000000000 --- a/example-ios/CameraKit.xcodeproj/xcshareddata/xcschemes/CameraKit-tvOS.xcscheme +++ /dev/null @@ -1,129 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/example-ios/CameraKit/AppDelegate.h b/example-ios/CameraKit/AppDelegate.h deleted file mode 100644 index a9654d5e01..0000000000 --- a/example-ios/CameraKit/AppDelegate.h +++ /dev/null @@ -1,16 +0,0 @@ -/** - * Copyright (c) 2015-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - */ - -#import - -@interface AppDelegate : UIResponder - -@property (nonatomic, strong) UIWindow *window; - -@end diff --git a/example-ios/CameraKit/AppDelegate.m b/example-ios/CameraKit/AppDelegate.m deleted file mode 100644 index f4920e2a28..0000000000 --- a/example-ios/CameraKit/AppDelegate.m +++ /dev/null @@ -1,37 +0,0 @@ -/** - * Copyright (c) 2015-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - */ - -#import "AppDelegate.h" - -#import -#import - -@implementation AppDelegate - -- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions -{ - NSURL *jsCodeLocation; - - jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil]; - - RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation - moduleName:@"CameraKit" - initialProperties:nil - launchOptions:launchOptions]; - rootView.backgroundColor = [[UIColor alloc] initWithRed:1.0f green:1.0f blue:1.0f alpha:1]; - - self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; - UIViewController *rootViewController = [UIViewController new]; - rootViewController.view = rootView; - self.window.rootViewController = rootViewController; - [self.window makeKeyAndVisible]; - return YES; -} - -@end diff --git a/example-ios/CameraKit/Base.lproj/LaunchScreen.xib b/example-ios/CameraKit/Base.lproj/LaunchScreen.xib deleted file mode 100644 index 4c0d270fd1..0000000000 --- a/example-ios/CameraKit/Base.lproj/LaunchScreen.xib +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/example-ios/CameraKit/Images.xcassets/AppIcon.appiconset/Contents.json b/example-ios/CameraKit/Images.xcassets/AppIcon.appiconset/Contents.json deleted file mode 100644 index 118c98f746..0000000000 --- a/example-ios/CameraKit/Images.xcassets/AppIcon.appiconset/Contents.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "images" : [ - { - "idiom" : "iphone", - "size" : "29x29", - "scale" : "2x" - }, - { - "idiom" : "iphone", - "size" : "29x29", - "scale" : "3x" - }, - { - "idiom" : "iphone", - "size" : "40x40", - "scale" : "2x" - }, - { - "idiom" : "iphone", - "size" : "40x40", - "scale" : "3x" - }, - { - "idiom" : "iphone", - "size" : "60x60", - "scale" : "2x" - }, - { - "idiom" : "iphone", - "size" : "60x60", - "scale" : "3x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/example-ios/CameraKit/Info.plist b/example-ios/CameraKit/Info.plist deleted file mode 100644 index a710ba4052..0000000000 --- a/example-ios/CameraKit/Info.plist +++ /dev/null @@ -1,59 +0,0 @@ - - - - - CFBundleDevelopmentRegion - en - CFBundleDisplayName - CameraKit - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - APPL - CFBundleShortVersionString - 1.0 - CFBundleSignature - ???? - CFBundleVersion - 1 - LSRequiresIPhoneOS - - UILaunchStoryboardName - LaunchScreen - UIRequiredDeviceCapabilities - - armv7 - - UISupportedInterfaceOrientations - - UIInterfaceOrientationPortrait - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UIViewControllerBasedStatusBarAppearance - - NSLocationWhenInUseUsageDescription - - NSCameraUsageDescription - Would like to use the Camera - NSPhotoLibraryUsageDescription - Would like to use the Photos - NSAppTransportSecurity - - NSExceptionDomains - - localhost - - NSExceptionAllowsInsecureHTTPLoads - - - - - - diff --git a/example-ios/CameraKit/main.m b/example-ios/CameraKit/main.m deleted file mode 100644 index 3d767fcbb9..0000000000 --- a/example-ios/CameraKit/main.m +++ /dev/null @@ -1,18 +0,0 @@ -/** - * Copyright (c) 2015-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - */ - -#import - -#import "AppDelegate.h" - -int main(int argc, char * argv[]) { - @autoreleasepool { - return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); - } -} diff --git a/example-js-code/android/app/BUCK b/example-js-code/android/app/BUCK deleted file mode 100644 index 13beceff25..0000000000 --- a/example-js-code/android/app/BUCK +++ /dev/null @@ -1,65 +0,0 @@ -# To learn about Buck see [Docs](https://buckbuild.com/). -# To run your application with Buck: -# - install Buck -# - `npm start` - to start the packager -# - `cd android` -# - `keytool -genkey -v -keystore keystores/debug.keystore -storepass android -alias androiddebugkey -keypass android -dname "CN=Android Debug,O=Android,C=US"` -# - `./gradlew :app:copyDownloadableDepsToLibs` - make all Gradle compile dependencies available to Buck -# - `buck install -r android/app` - compile, install and run application -# - -lib_deps = [] - -for jarfile in glob(['libs/*.jar']): - name = 'jars__' + jarfile[jarfile.rindex('/') + 1: jarfile.rindex('.jar')] - lib_deps.append(':' + name) - prebuilt_jar( - name = name, - binary_jar = jarfile, - ) - -for aarfile in glob(['libs/*.aar']): - name = 'aars__' + aarfile[aarfile.rindex('/') + 1: aarfile.rindex('.aar')] - lib_deps.append(':' + name) - android_prebuilt_aar( - name = name, - aar = aarfile, - ) - -android_library( - name = "all-libs", - exported_deps = lib_deps, -) - -android_library( - name = "app-code", - srcs = glob([ - "src/main/java/**/*.java", - ]), - deps = [ - ":all-libs", - ":build_config", - ":res", - ], -) - -android_build_config( - name = "build_config", - package = "com.camerakit", -) - -android_resource( - name = "res", - package = "com.camerakit", - res = "src/main/res", -) - -android_binary( - name = "app", - keystore = "//android/keystores:debug", - manifest = "src/main/AndroidManifest.xml", - package_type = "debug", - deps = [ - ":app-code", - ], -) diff --git a/example-js-code/android/app/build.gradle b/example-js-code/android/app/build.gradle deleted file mode 100644 index acbbc8feac..0000000000 --- a/example-js-code/android/app/build.gradle +++ /dev/null @@ -1,150 +0,0 @@ -apply plugin: "com.android.application" - -import com.android.build.OutputFile - -/** - * The react.gradle file registers a task for each build variant (e.g. bundleDebugJsAndAssets - * and bundleReleaseJsAndAssets). - * These basically call `react-native bundle` with the correct arguments during the Android build - * cycle. By default, bundleDebugJsAndAssets is skipped, as in debug/dev mode we prefer to load the - * bundle directly from the development server. Below you can see all the possible configurations - * and their defaults. If you decide to add a configuration block, make sure to add it before the - * `apply from: "../../node_modules/react-native/react.gradle"` line. - * - * project.ext.react = [ - * // the name of the generated asset file containing your JS bundle - * bundleAssetName: "index.android.bundle", - * - * // the entry file for bundle generation - * entryFile: "index.android.js", - * - * // whether to bundle JS and assets in debug mode - * bundleInDebug: false, - * - * // whether to bundle JS and assets in release mode - * bundleInRelease: true, - * - * // whether to bundle JS and assets in another build variant (if configured). - * // See http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Build-Variants - * // The configuration property can be in the following formats - * // 'bundleIn${productFlavor}${buildType}' - * // 'bundleIn${buildType}' - * // bundleInFreeDebug: true, - * // bundleInPaidRelease: true, - * // bundleInBeta: true, - * - * // whether to disable dev mode in custom build variants (by default only disabled in release) - * // for example: to disable dev mode in the staging build type (if configured) - * devDisabledInStaging: true, - * // The configuration property can be in the following formats - * // 'devDisabledIn${productFlavor}${buildType}' - * // 'devDisabledIn${buildType}' - * - * // the root of your project, i.e. where "package.json" lives - * root: "../../", - * - * // where to put the JS bundle asset in debug mode - * jsBundleDirDebug: "$buildDir/intermediates/assets/debug", - * - * // where to put the JS bundle asset in release mode - * jsBundleDirRelease: "$buildDir/intermediates/assets/release", - * - * // where to put drawable resources / React Native assets, e.g. the ones you use via - * // require('./image.png')), in debug mode - * resourcesDirDebug: "$buildDir/intermediates/res/merged/debug", - * - * // where to put drawable resources / React Native assets, e.g. the ones you use via - * // require('./image.png')), in release mode - * resourcesDirRelease: "$buildDir/intermediates/res/merged/release", - * - * // by default the gradle tasks are skipped if none of the JS files or assets change; this means - * // that we don't look at files in android/ or ios/ to determine whether the tasks are up to - * // date; if you have any other folders that you want to ignore for performance reasons (gradle - * // indexes the entire tree), add them here. Alternatively, if you have JS files in android/ - * // for example, you might want to remove it from here. - * inputExcludes: ["android/**", "ios/**"], - * - * // override which node gets called and with what additional arguments - * nodeExecutableAndArgs: ["node"], - * - * // supply additional arguments to the packager - * extraPackagerArgs: [] - * ] - */ - -project.ext.react = [ - entryFile: "index.js" -] - -apply from: "../../node_modules/react-native/react.gradle" - -/** - * Set this to true to create two separate APKs instead of one: - * - An APK that only works on ARM devices - * - An APK that only works on x86 devices - * The advantage is the size of the APK is reduced by about 4MB. - * Upload all the APKs to the Play Store and people will download - * the correct one based on the CPU architecture of their device. - */ -def enableSeparateBuildPerCPUArchitecture = false - -/** - * Run Proguard to shrink the Java bytecode in release builds. - */ -def enableProguardInReleaseBuilds = false - -android { - compileSdkVersion 23 - buildToolsVersion "23.0.1" - - defaultConfig { - applicationId "com.camerakit" - minSdkVersion 16 - targetSdkVersion 22 - versionCode 1 - versionName "1.0" - ndk { - abiFilters "armeabi-v7a", "x86" - } - } - splits { - abi { - reset() - enable enableSeparateBuildPerCPUArchitecture - universalApk false // If true, also generate a universal APK - include "armeabi-v7a", "x86" - } - } - buildTypes { - release { - 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: - // http://tools.android.com/tech-docs/new-build-system/user-guide/apk-splits - def versionCodes = ["armeabi-v7a":1, "x86":2] - def abi = output.getFilter(OutputFile.ABI) - if (abi != null) { // null for the universal-debug, universal-release variants - output.versionCodeOverride = - versionCodes.get(abi) * 1048576 + defaultConfig.versionCode - } - } - } -} - -dependencies { - compile fileTree(dir: "libs", include: ["*.jar"]) - compile "com.android.support:appcompat-v7:23.0.1" - compile "com.facebook.react:react-native:+" // From node_modules -} - -// Run this once to be able to run the application with BUCK -// puts all compile dependencies into folder libs for BUCK to use -task copyDownloadableDepsToLibs(type: Copy) { - from configurations.compile - into 'libs' -} diff --git a/example-js-code/android/app/proguard-rules.pro b/example-js-code/android/app/proguard-rules.pro deleted file mode 100644 index 6e8516c8d6..0000000000 --- a/example-js-code/android/app/proguard-rules.pro +++ /dev/null @@ -1,70 +0,0 @@ -# Add project specific ProGuard rules here. -# By default, the flags in this file are appended to flags specified -# in /usr/local/Cellar/android-sdk/24.3.3/tools/proguard/proguard-android.txt -# You can edit the include path and order by changing the proguardFiles -# directive in build.gradle. -# -# For more details, see -# http://developer.android.com/guide/developing/tools/proguard.html - -# Add any project specific keep options here: - -# If your project uses WebView with JS, uncomment the following -# and specify the fully qualified class name to the JavaScript interface -# class: -#-keepclassmembers class fqcn.of.javascript.interface.for.webview { -# public *; -#} - -# Disabling obfuscation is useful if you collect stack traces from production crashes -# (unless you are using a system that supports de-obfuscate the stack traces). --dontobfuscate - -# React Native - -# Keep our interfaces so they can be used by other ProGuard rules. -# See http://sourceforge.net/p/proguard/bugs/466/ --keep,allowobfuscation @interface com.facebook.proguard.annotations.DoNotStrip --keep,allowobfuscation @interface com.facebook.proguard.annotations.KeepGettersAndSetters --keep,allowobfuscation @interface com.facebook.common.internal.DoNotStrip - -# Do not strip any method/class that is annotated with @DoNotStrip --keep @com.facebook.proguard.annotations.DoNotStrip class * --keep @com.facebook.common.internal.DoNotStrip class * --keepclassmembers class * { - @com.facebook.proguard.annotations.DoNotStrip *; - @com.facebook.common.internal.DoNotStrip *; -} - --keepclassmembers @com.facebook.proguard.annotations.KeepGettersAndSetters class * { - void set*(***); - *** get*(); -} - --keep class * extends com.facebook.react.bridge.JavaScriptModule { *; } --keep class * extends com.facebook.react.bridge.NativeModule { *; } --keepclassmembers,includedescriptorclasses class * { native ; } --keepclassmembers class * { @com.facebook.react.uimanager.UIProp ; } --keepclassmembers class * { @com.facebook.react.uimanager.annotations.ReactProp ; } --keepclassmembers class * { @com.facebook.react.uimanager.annotations.ReactPropGroup ; } - --dontwarn com.facebook.react.** - -# TextLayoutBuilder uses a non-public Android constructor within StaticLayout. -# See libs/proxy/src/main/java/com/facebook/fbui/textlayoutbuilder/proxy for details. --dontwarn android.text.StaticLayout - -# okhttp - --keepattributes Signature --keepattributes *Annotation* --keep class okhttp3.** { *; } --keep interface okhttp3.** { *; } --dontwarn okhttp3.** - -# okio - --keep class sun.misc.Unsafe { *; } --dontwarn java.nio.file.* --dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement --dontwarn okio.** diff --git a/example-js-code/android/app/src/main/AndroidManifest.xml b/example-js-code/android/app/src/main/AndroidManifest.xml deleted file mode 100644 index 8d9a3094b0..0000000000 --- a/example-js-code/android/app/src/main/AndroidManifest.xml +++ /dev/null @@ -1,32 +0,0 @@ - - - - - - - - - - - - - - - - - - diff --git a/example-js-code/android/app/src/main/java/com/camerakit/MainActivity.java b/example-js-code/android/app/src/main/java/com/camerakit/MainActivity.java deleted file mode 100644 index 3d90d79597..0000000000 --- a/example-js-code/android/app/src/main/java/com/camerakit/MainActivity.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.camerakit; - -import com.facebook.react.ReactActivity; - -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 "CameraKit"; - } -} diff --git a/example-js-code/android/app/src/main/java/com/camerakit/MainApplication.java b/example-js-code/android/app/src/main/java/com/camerakit/MainApplication.java deleted file mode 100644 index b65cbd9591..0000000000 --- a/example-js-code/android/app/src/main/java/com/camerakit/MainApplication.java +++ /dev/null @@ -1,45 +0,0 @@ -package com.camerakit; - -import android.app.Application; - -import com.facebook.react.ReactApplication; -import com.facebook.react.ReactNativeHost; -import com.facebook.react.ReactPackage; -import com.facebook.react.shell.MainReactPackage; -import com.facebook.soloader.SoLoader; - -import java.util.Arrays; -import java.util.List; - -public class MainApplication extends Application implements ReactApplication { - - private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) { - @Override - public boolean getUseDeveloperSupport() { - return BuildConfig.DEBUG; - } - - @Override - protected List getPackages() { - return Arrays.asList( - new MainReactPackage() - ); - } - - @Override - protected String getJSMainModuleName() { - return "index"; - } - }; - - @Override - public ReactNativeHost getReactNativeHost() { - return mReactNativeHost; - } - - @Override - public void onCreate() { - super.onCreate(); - SoLoader.init(this, /* native exopackage */ false); - } -} diff --git a/example-js-code/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/example-js-code/android/app/src/main/res/mipmap-hdpi/ic_launcher.png deleted file mode 100644 index cde69bccce..0000000000 Binary files a/example-js-code/android/app/src/main/res/mipmap-hdpi/ic_launcher.png and /dev/null differ diff --git a/example-js-code/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/example-js-code/android/app/src/main/res/mipmap-mdpi/ic_launcher.png deleted file mode 100644 index c133a0cbd3..0000000000 Binary files a/example-js-code/android/app/src/main/res/mipmap-mdpi/ic_launcher.png and /dev/null differ diff --git a/example-js-code/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/example-js-code/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png deleted file mode 100644 index bfa42f0e7b..0000000000 Binary files a/example-js-code/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png and /dev/null differ diff --git a/example-js-code/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/example-js-code/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png deleted file mode 100644 index 324e72cdd7..0000000000 Binary files a/example-js-code/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png and /dev/null differ diff --git a/example-js-code/android/app/src/main/res/values/strings.xml b/example-js-code/android/app/src/main/res/values/strings.xml deleted file mode 100644 index 252d798486..0000000000 --- a/example-js-code/android/app/src/main/res/values/strings.xml +++ /dev/null @@ -1,3 +0,0 @@ - - CameraKit - diff --git a/example-js-code/android/app/src/main/res/values/styles.xml b/example-js-code/android/app/src/main/res/values/styles.xml deleted file mode 100644 index 319eb0ca10..0000000000 --- a/example-js-code/android/app/src/main/res/values/styles.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - diff --git a/example-js-code/android/build.gradle b/example-js-code/android/build.gradle deleted file mode 100644 index eed9972b5c..0000000000 --- a/example-js-code/android/build.gradle +++ /dev/null @@ -1,24 +0,0 @@ -// Top-level build file where you can add configuration options common to all sub-projects/modules. - -buildscript { - repositories { - jcenter() - } - dependencies { - classpath 'com.android.tools.build:gradle:2.2.3' - - // NOTE: Do not place your application dependencies here; they belong - // in the individual module build.gradle files - } -} - -allprojects { - repositories { - mavenLocal() - jcenter() - maven { - // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm - url "$rootDir/../node_modules/react-native/android" - } - } -} diff --git a/example-js-code/android/gradle.properties b/example-js-code/android/gradle.properties deleted file mode 100644 index 1fd964e90b..0000000000 --- a/example-js-code/android/gradle.properties +++ /dev/null @@ -1,20 +0,0 @@ -# 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: -Xmx10248m -XX:MaxPermSize=256m -# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 - -# 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 - -android.useDeprecatedNdk=true diff --git a/example-js-code/android/gradle/wrapper/gradle-wrapper.jar b/example-js-code/android/gradle/wrapper/gradle-wrapper.jar deleted file mode 100644 index b5166dad4d..0000000000 Binary files a/example-js-code/android/gradle/wrapper/gradle-wrapper.jar and /dev/null differ diff --git a/example-js-code/android/gradle/wrapper/gradle-wrapper.properties b/example-js-code/android/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index dbdc05d274..0000000000 --- a/example-js-code/android/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,5 +0,0 @@ -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip diff --git a/example-js-code/android/gradlew b/example-js-code/android/gradlew deleted file mode 100755 index 91a7e269e1..0000000000 --- a/example-js-code/android/gradlew +++ /dev/null @@ -1,164 +0,0 @@ -#!/usr/bin/env bash - -############################################################################## -## -## Gradle start up script for UN*X -## -############################################################################## - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS="" - -APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` - -# Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" - -warn ( ) { - echo "$*" -} - -die ( ) { - echo - echo "$*" - echo - exit 1 -} - -# OS specific support (must be 'true' or 'false'). -cygwin=false -msys=false -darwin=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; -esac - -# For Cygwin, ensure paths are in UNIX format before anything is touched. -if $cygwin ; then - [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` -fi - -# Attempt to set APP_HOME -# Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi -done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >&- -APP_HOME="`pwd -P`" -cd "$SAVED" >&- - -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" = "false" -a "$darwin" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi -fi - -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi - -# For Cygwin, switch paths to Windows format before running java -if $cygwin ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi - # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" - fi - i=$((i+1)) - done - case $i in - (0) set -- ;; - (1) set -- "$args0" ;; - (2) set -- "$args0" "$args1" ;; - (3) set -- "$args0" "$args1" "$args2" ;; - (4) set -- "$args0" "$args1" "$args2" "$args3" ;; - (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac -fi - -# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules -function splitJvmOpts() { - JVM_OPTS=("$@") -} -eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS -JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" - -exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" diff --git a/example-js-code/android/gradlew.bat b/example-js-code/android/gradlew.bat deleted file mode 100644 index aec99730b4..0000000000 --- a/example-js-code/android/gradlew.bat +++ /dev/null @@ -1,90 +0,0 @@ -@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 - -@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= - -set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@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 init - -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 init - -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 - -:init -@rem Get command-line arguments, handling Windowz variants - -if not "%OS%" == "Windows_NT" goto win9xME_args -if "%@eval[2+2]" == "4" goto 4NT_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* -goto execute - -:4NT_args -@rem Get arguments from the 4NT Shell from JP Software -set CMD_LINE_ARGS=%$ - -: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 %CMD_LINE_ARGS% - -: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/example-js-code/android/keystores/BUCK b/example-js-code/android/keystores/BUCK deleted file mode 100644 index 88e4c31b28..0000000000 --- a/example-js-code/android/keystores/BUCK +++ /dev/null @@ -1,8 +0,0 @@ -keystore( - name = "debug", - properties = "debug.keystore.properties", - store = "debug.keystore", - visibility = [ - "PUBLIC", - ], -) diff --git a/example-js-code/android/keystores/debug.keystore.properties b/example-js-code/android/keystores/debug.keystore.properties deleted file mode 100644 index 121bfb49f0..0000000000 --- a/example-js-code/android/keystores/debug.keystore.properties +++ /dev/null @@ -1,4 +0,0 @@ -key.store=debug.keystore -key.alias=androiddebugkey -key.store.password=android -key.alias.password=android diff --git a/example-js-code/android/settings.gradle b/example-js-code/android/settings.gradle deleted file mode 100644 index d07aed6d9c..0000000000 --- a/example-js-code/android/settings.gradle +++ /dev/null @@ -1,3 +0,0 @@ -rootProject.name = 'CameraKit' - -include ':app' diff --git a/example-js-code/app.js b/example-js-code/app.js deleted file mode 100644 index 1dfdd82c34..0000000000 --- a/example-js-code/app.js +++ /dev/null @@ -1,132 +0,0 @@ -import React, { Component } from 'react'; -import { - AppRegistry, - StyleSheet, - Text, - View, - TouchableOpacity, - AlertIOS -} from 'react-native'; - -import {CameraKitCamera, CameraKitGallery} from '../src'; - -import CameraScreen from './src/CameraScreen'; -import AlbumsScreen from './src/AlbumsScreen'; -import GalleryScreen from './src/GalleryScreen'; -import BarcodeScreen from './src/BarcodeScreen'; - -class example extends Component { - - constructor(props) { - super(props); - this.state = { - example: undefined - }; - } - - render() { - if (this.state.example) { - const Example = this.state.example; - return ; - } - return ( - - - - Welcome to Camera Kit - - πŸ“· - - - - - this.setState({ example: BarcodeScreen })}> - - Barcode scanner Screen - - - - this.setState({ example: CameraScreen })}> - - Camera Screen - - - - this.setState({ example: AlbumsScreen })}> - - Albums Screen - - - - this.setState({ example: GalleryScreen })}> - - Gallery Screen - - - - this.onCheckCameraAuthoPressed()}> - - Camera Autotization Status - - - - this.onCheckGalleryAuthoPressed()}> - - Photos Autotization Status - - - - - - - ); - } - - async onCheckCameraAuthoPressed() { - const success = await CameraKitCamera.checkDeviceCameraAuthorizationStatus(); - if (success) { - AlertIOS.alert('You have permission πŸ€—') - } - else { - AlertIOS.alert('No permission 😳') - } - } - - async onCheckGalleryAuthoPressed() { - const success = await CameraKitGallery.checkDevicePhotosAuthorizationStatus(); - if (success) { - AlertIOS.alert('You have permission πŸ€—') - } - else { - AlertIOS.alert('No permission 😳') - } - } -} - -const styles = StyleSheet.create({ - container: { - flex: 1, - // justifyContent: 'center', - paddingTop: 60, - alignItems: 'center', - backgroundColor: '#F5FCFF', - }, - headerContainer: { - flexDirection: 'column', - backgroundColor: '#F5FCFF', - justifyContent: 'center', - alignItems: 'center', - paddingTop: 100 - }, - headerText: { - color: 'black', - fontSize: 24 - }, - buttonText: { - color: 'blue', - marginBottom: 20, - fontSize: 20 - } -}); - -AppRegistry.registerComponent('CameraKit', () => example); diff --git a/example-js-code/images/cameraButton@2x.png b/example-js-code/images/cameraButton@2x.png deleted file mode 100644 index b9bb82cf4e..0000000000 Binary files a/example-js-code/images/cameraButton@2x.png and /dev/null differ diff --git a/example-js-code/images/cameraFlipIcon@2x.png b/example-js-code/images/cameraFlipIcon@2x.png deleted file mode 100644 index 18f9f86e54..0000000000 Binary files a/example-js-code/images/cameraFlipIcon@2x.png and /dev/null differ diff --git a/example-js-code/images/hugging.png b/example-js-code/images/hugging.png deleted file mode 100644 index aa96842231..0000000000 Binary files a/example-js-code/images/hugging.png and /dev/null differ diff --git a/example-js-code/images/openCamera.png b/example-js-code/images/openCamera.png deleted file mode 100644 index 73b00fa2c2..0000000000 Binary files a/example-js-code/images/openCamera.png and /dev/null differ diff --git a/example-js-code/images/openCamera@1.5x.png b/example-js-code/images/openCamera@1.5x.png deleted file mode 100644 index a10a32c6bc..0000000000 Binary files a/example-js-code/images/openCamera@1.5x.png and /dev/null differ diff --git a/example-js-code/images/openCamera@2x.png b/example-js-code/images/openCamera@2x.png deleted file mode 100644 index d7bc99e169..0000000000 Binary files a/example-js-code/images/openCamera@2x.png and /dev/null differ diff --git a/example-js-code/images/openCamera@3x.png b/example-js-code/images/openCamera@3x.png deleted file mode 100644 index 502c8a2fd8..0000000000 Binary files a/example-js-code/images/openCamera@3x.png and /dev/null differ diff --git a/example-js-code/images/openCamera@4x.png b/example-js-code/images/openCamera@4x.png deleted file mode 100644 index 9c688634f1..0000000000 Binary files a/example-js-code/images/openCamera@4x.png and /dev/null differ diff --git a/example-js-code/images/selected.png b/example-js-code/images/selected.png deleted file mode 100644 index df23285c1b..0000000000 Binary files a/example-js-code/images/selected.png and /dev/null differ diff --git a/example-js-code/images/unsupportedImage.png b/example-js-code/images/unsupportedImage.png deleted file mode 100644 index a51b5aa69f..0000000000 Binary files a/example-js-code/images/unsupportedImage.png and /dev/null differ diff --git a/example-js-code/index.android.js b/example-js-code/index.android.js deleted file mode 100644 index 3a2083604f..0000000000 --- a/example-js-code/index.android.js +++ /dev/null @@ -1 +0,0 @@ -require('./app'); \ No newline at end of file diff --git a/example-js-code/index.ios.js b/example-js-code/index.ios.js deleted file mode 100644 index 3a2083604f..0000000000 --- a/example-js-code/index.ios.js +++ /dev/null @@ -1 +0,0 @@ -require('./app'); \ No newline at end of file diff --git a/example-js-code/src/AlbumsScreen.android.js b/example-js-code/src/AlbumsScreen.android.js deleted file mode 100644 index 9824bbea94..0000000000 --- a/example-js-code/src/AlbumsScreen.android.js +++ /dev/null @@ -1,87 +0,0 @@ -import React, { Component } from 'react'; -import { - StyleSheet, - Text, - View, - TouchableOpacity, - Image, - FlatList -} from 'react-native'; - -import {CameraKitGallery} from '../../src'; - -import GalleryScreen from './GalleryScreen'; - -export default class AlbumsScreen extends Component { - - constructor(props) { - - super(props); - this.state = { - albums:{}, - albumsDS: [], - albumName: undefined - } - } - - componentDidMount() { - this.onGetAlbumsPressed(); - } - - render() { - if (this.state.albumName) { - const albumName = this.state.albumName; - return ; - } - - return ( - - - - ); - } - - _renderRow(rowData) { - const item = rowData.item; - const image = 'file://' + item.thumbUri; - return ( - - - this.setState({albumName: item.albumName})}> - {item.albumName} - {item.imagesCount} - - - ) - } - async onGetAlbumsPressed() { - let albums = await CameraKitGallery.getAlbumsWithThumbnails(); - albums = albums.albums; - - this.setState({albumsDS: albums, albums:{albums}, shouldShowListView: true}); - } - -} - - -const styles = StyleSheet.create({ - container: { - flex: 1, - backgroundColor: '#F5FCFF', - marginTop: 20 - }, - listView: { - margin: 8, - backgroundColor: '#D6DAC2' - } -}); - - diff --git a/example-js-code/src/AlbumsScreen.ios.js b/example-js-code/src/AlbumsScreen.ios.js deleted file mode 100644 index a9080c0d08..0000000000 --- a/example-js-code/src/AlbumsScreen.ios.js +++ /dev/null @@ -1,187 +0,0 @@ -import React, {Component} from 'react'; -import { - StyleSheet, - Text, - View, - TouchableOpacity, - Image, - Switch -} from 'react-native'; - -import {CameraKitGallery, CameraKitGalleryView} from '../../src'; -import _ from 'lodash'; - -import CameraScreen from './CameraScreen'; - - -export default class AlbumsScreen extends Component { - - constructor(props) { - - super(props); - this.state = { - album: {albumName: 'All Photos'}, - albums: [], - dropdownVisible: false, - images: [], - imagesDetails: undefined, - shouldRenderCameraScreen: false, - tappedImage: undefined, - getUrlOnTapImage: false - } - } - - componentDidMount() { - this.reloadAlbums(); - } - - async reloadAlbums() { - const newAlbums = await CameraKitGallery.getAlbumsWithThumbnails(); - - let albums = []; - - for (let name in newAlbums.albums) { - albums.push(_.get(newAlbums, ['albums', name])); - } - this.setState({albums}) - } - - imageTapped(selected) { - if (this.state.images.indexOf(selected) < 0) { - this.setState({images: _.concat(this.state.images, selected), tappedImage: selected}); - } - else { - this.setState({images: _.without(this.state.images, selected)}) - - } - - } - - render() { - - if (this.state.shouldRenderCameraScreen) { - return ( - - ); - } - - return ( - - { - this.gallery = gallery; - }} - style={{flex: 1, backgroundColor:'green'}} - minimumInteritemSpacing={10} - minimumLineSpacing={10} - columnCount={3} - albumName={'all photos'} - onTapImage={(result) => { - this.imageTapped(result.nativeEvent.selected); - }} - selection={{ - selectedImage: require('../images/selected.png'), - imageSizeAndroid: 'large', - overlayColor: '#ecf0f1aa' - }} - fileTypeSupport={{ - unsupportedOverlayColor: "#00000055", - unsupportedImage: require('../images/unsupportedImage.png'), - unsupportedText: 'Unsupported', - unsupportedTextColor: '#ffffff' - }} - imageStrokeColor={'#edeff0'} - customButtonStyle={{ - image: require('../images/openCamera.png'), - backgroundColor: '#f2f4f5' - }} - onCustomButtonPress={(result) => { - this.onCustomButtonPressed(); - }} - getUrlOnTapImage={this.state.getUrlOnTapImage} - /> - - - {this.renderImagesDetails()} - - this.setState({getUrlOnTapImage: value})} - value={this.state.getUrlOnTapImage} - style={{margin: 10}} - /> - - getUrlOnTapImage - - - - {this.state.getUrlOnTapImage && } - - - this.getImagesForIds()}> - - Get Selected Images - - - - - - ); - } - - renderCameraScreen() { - - return - } - - onCustomButtonPressed() { - this.setState({shouldRenderCameraScreen: true}); - } - - renderImagesDetails() { - if (!this.state.imagesDetails) { - return null; - } - - return ( - - - {JSON.stringify(this.state.imagesDetails)} - - - ) - } - - async getImagesForIds() { - const imagesDict = await CameraKitGallery.getImagesForIds(this.state.images); - this.setState({imagesDetails: imagesDict}); - } - - async onGetAlbumsPressed() { - let albums = await CameraKitGallery.getAlbumsWithThumbnails(); - albums = albums.albums; - - this.setState({albums: {albums}, shouldShowListView: true}); - } - -} - -const styles = StyleSheet.create({ - container: { - flex: 1, - justifyContent: 'center', - backgroundColor: '#aabdc3c7', - marginTop: 20 - }, - buttonText: { - color: 'blue', - marginBottom: 20, - fontSize: 20 - } -}); - - diff --git a/example-js-code/src/BarcodeScreen.js b/example-js-code/src/BarcodeScreen.js deleted file mode 100644 index 4b45ffcf9a..0000000000 --- a/example-js-code/src/BarcodeScreen.js +++ /dev/null @@ -1,60 +0,0 @@ -import React, { Component } from 'react'; -import { - Alert -} from 'react-native'; -import { CameraKitCameraScreen } from '../../src'; -import CheckingScreen from './CheckingScreen'; - - -export default class CameraScreen extends Component { - - constructor(props) { - super(props); - this.state = { - example: undefined - }; - } - - onBottomButtonPressed(event) { - const captureImages = JSON.stringify(event.captureImages); - Alert.alert( - `${event.type} button pressed`, - `${captureImages}`, - [ - { text: 'OK', onPress: () => console.log('OK Pressed') }, - ], - { cancelable: false } - ) - } - - render() { - if (this.state.example) { - const CameraScreen = this.state.example; - return ; - } - return ( - this.onBottomButtonPressed(event)} - flashImages={{ - on: require('./../images/flashOn.png'), - off: require('./../images/flashOff.png'), - auto: require('./../images/flashAuto.png') - }} - showFrame={true} - scanBarcode={true} - laserColor={"blue"} - surfaceColor={"black"} - frameColor={"yellow"} - onReadCode={((event) => this.setState({ example: CheckingScreen }))} - hideControls={true} - // offsetForScannerFrame = {10} - // heightForScannerFrame = {300} - colorForScannerFrame={'blue'} - /> - ); - } -} - - - diff --git a/example-js-code/src/CameraScreen.js b/example-js-code/src/CameraScreen.js deleted file mode 100644 index 861eed44a1..0000000000 --- a/example-js-code/src/CameraScreen.js +++ /dev/null @@ -1,41 +0,0 @@ -import React, { Component } from 'react'; -import { - Alert -} from 'react-native'; -import { CameraKitCameraScreen } from '../../src'; - - -export default class CameraScreen extends Component { - - - onBottomButtonPressed(event) { - const captureImages = JSON.stringify(event.captureImages); - Alert.alert( - `${event.type} button pressed`, - `${captureImages}`, - [ - { text: 'OK', onPress: () => console.log('OK Pressed') }, - ], - { cancelable: false } - ) - } - - render() { - return ( - this.onBottomButtonPressed(event)} - flashImages={{ - on: require('./../images/flashOn.png'), - off: require('./../images/flashOff.png'), - auto: require('./../images/flashAuto.png') - }} - cameraFlipImage={require('./../images/cameraFlipIcon.png')} - captureButtonImage={require('./../images/cameraButton.png')} - /> - ); - } -} - - - diff --git a/example-js-code/src/CheckingScreen.js b/example-js-code/src/CheckingScreen.js deleted file mode 100644 index bbe3a0f9a4..0000000000 --- a/example-js-code/src/CheckingScreen.js +++ /dev/null @@ -1,53 +0,0 @@ -import React, { Component } from 'react'; -import { - View, - TouchableOpacity, - Text, - StyleSheet -} from 'react-native'; -import BarcodeScreen from './BarcodeScreen'; - -export default class ExampleScreen extends Component { - - constructor(props) { - super(props); - this.state = { - example: undefined - }; - } - - render() { - if (this.state.example) { - const ExampleScreen = this.state.example; - return ; - } - return ( - - this.setState({example : BarcodeScreen}))}> - - Back button - - - - ); - } -} - - -const styles = StyleSheet.create({ - container: { - flex: 1, - // justifyContent: 'center', - paddingTop: 60, - alignItems: 'center', - backgroundColor: '#F5FCFF', - }, - buttonText: { - color: 'blue', - marginBottom: 20, - fontSize: 20 - } - }); - - - diff --git a/example-js-code/src/GalleryScreen.android.js b/example-js-code/src/GalleryScreen.android.js deleted file mode 100644 index 6303e06536..0000000000 --- a/example-js-code/src/GalleryScreen.android.js +++ /dev/null @@ -1,70 +0,0 @@ -import React, {Component} from 'react'; - -import {CameraKitGalleryView} from '../../src'; - -import CameraScreen from './CameraScreen'; - -export default class GalleryScreen extends Component { - - constructor(props) { - super(props); - this.state = { - album: this.props.albumName, - images: {}, - shouldRenderCameraScreen: false - } - } - - render() { - if (this.state.shouldRenderCameraScreen) { - return (); - } - - return ( - { - this.gallery = gallery; - }} - style={{flex:1, margin: 0, backgroundColor: '#ffffff', marginTop: 50}} - albumName={this.state.album} - minimumInteritemSpacing={10} - minimumLineSpacing={10} - columnCount={3} - selectedImages={Object.keys(this.state.images)} - onSelected={(result) => { - }} - onTapImage={this.onTapImage.bind(this)} - selection={{ - selectedImage: require('../images/selected.png'), - imagePosition: 'bottom-right', - imageSizeAndroid: 'large', - enable: (Object.keys(this.state.images).length < 3) - }} - fileTypeSupport={{ - supportedFileTypes: ['image/jpeg'], - unsupportedOverlayColor: "#00000055", - unsupportedImage: require('../images/unsupportedImage.png'), - //unsupportedText: 'JPEG!!', - unsupportedTextColor: '#ff0000' - }} - customButtonStyle={{ - image: require('../images/openCamera.png'), - backgroundColor: '#06c4e9' - }} - onCustomButtonPress={() => this.setState({shouldRenderCameraScreen: true})} - /> - ) - } - - onTapImage(event) { - const uri = event.nativeEvent.selected; - console.log('Tapped on an image: ' + uri); - - if (this.state.images[uri]) { - delete this.state.images[uri]; - } else { - this.state.images[uri] = true; - } - this.setState({images: {...this.state.images}}) - } -} diff --git a/example-js-code/src/GalleryScreen.ios.js b/example-js-code/src/GalleryScreen.ios.js deleted file mode 100644 index a8954011ff..0000000000 --- a/example-js-code/src/GalleryScreen.ios.js +++ /dev/null @@ -1,89 +0,0 @@ -import _ from 'lodash'; -import React, {Component} from 'react'; -import { - StyleSheet, - View, - Button, - Image, - Dimensions -} from 'react-native'; - -import {CameraKitGallery, CameraKitGalleryView} from '../../src'; - -const {width, height} = Dimensions.get('window'); -const size = Math.floor((Dimensions.get('window').width) / 3); - -export default class GalleryScreen extends Component { - - constructor(props) { - super(props); - this.state = { - album: this.props.albumName, - presentedImage: undefined, - selectedImages: [], - showPresentedImage: false - } - } - - async onTapImage(event) { - const isSelected = event.nativeEvent.isSelected; - const image = await CameraKitGallery.getImageForTapEvent(event.nativeEvent); - - if (!isSelected || _.get(image, 'selectedImageId') === _.get(this.state, 'presentedImage.selectedImageId')) { - this.setState({presentedImage: undefined, showPresentedImage: false}); - } else if (image) { - this.setState({presentedImage: image, showPresentedImage: true}); - } - } - - renderPresentedImage() { - return ( - - - - -