diff --git a/.flowconfig b/.flowconfig new file mode 100644 index 0000000..66b57e0 --- /dev/null +++ b/.flowconfig @@ -0,0 +1,89 @@ +[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/.gitignore b/.gitignore new file mode 100644 index 0000000..94fc867 --- /dev/null +++ b/.gitignore @@ -0,0 +1,34 @@ +# OSX +# +.DS_Store + +# Xcode +# +build/ +*.pbxuser +!default.pbxuser +*.mode1v3 +!default.mode1v3 +*.mode2v3 +!default.mode2v3 +*.perspectivev3 +!default.perspectivev3 +xcuserdata +*.xccheckout +*.moved-aside +DerivedData +*.hmap +*.ipa +*.xcuserstate +project.xcworkspace + +# Android/IJ +# +.idea +.gradle +local.properties + +# node.js +# +node_modules/ +npm-debug.log diff --git a/.watchmanconfig b/.watchmanconfig new file mode 100644 index 0000000..9e26dfe --- /dev/null +++ b/.watchmanconfig @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..7934101 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,126 @@ +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: "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, + * + * // 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/**"] + * ] + */ + +apply from: "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.reactnativecamerakit" + 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 +} diff --git a/android/app/proguard-rules.pro b/android/app/proguard-rules.pro new file mode 100644 index 0000000..7d72e46 --- /dev/null +++ b/android/app/proguard-rules.pro @@ -0,0 +1,67 @@ +# 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 + +# Do not strip any method/class that is annotated with @DoNotStrip +-keep @com.facebook.proguard.annotations.DoNotStrip class * +-keepclassmembers class * { + @com.facebook.proguard.annotations.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.** + +# okhttp + +-keepattributes Signature +-keepattributes *Annotation* +-keep class com.squareup.okhttp.** { *; } +-keep interface com.squareup.okhttp.** { *; } +-dontwarn com.squareup.okhttp.** + +# okio + +-keep class sun.misc.Unsafe { *; } +-dontwarn java.nio.file.* +-dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement +-dontwarn okio.** + +# stetho + +-dontwarn com.facebook.stetho.** diff --git a/android/app/react.gradle b/android/app/react.gradle new file mode 100644 index 0000000..850e40d --- /dev/null +++ b/android/app/react.gradle @@ -0,0 +1,97 @@ +import org.apache.tools.ant.taskdefs.condition.Os + +def config = project.hasProperty("react") ? project.react : []; + +def bundleAssetName = config.bundleAssetName ?: "index.android.bundle" +def entryFile = config.entryFile ?: "index.android.js" + +// because elvis operator +def elvisFile(thing) { + return thing ? file(thing) : null; +} + +def reactRoot = elvisFile(config.root) ?: file("../../") +def inputExcludes = config.inputExcludes ?: ["android/**", "ios/**"] + +void runBefore(String dependentTaskName, Task task) { + Task dependentTask = tasks.findByPath(dependentTaskName); + if (dependentTask != null) { + dependentTask.dependsOn task + } +} + +gradle.projectsEvaluated { + // Grab all build types and product flavors + def buildTypes = android.buildTypes.collect { type -> type.name } + def productFlavors = android.productFlavors.collect { flavor -> flavor.name } + + // When no product flavors defined, use empty + if (!productFlavors) productFlavors.add('') + + productFlavors.each { productFlavorName -> + buildTypes.each { buildTypeName -> + // Create variant and target names + def targetName = "${productFlavorName.capitalize()}${buildTypeName.capitalize()}" + def targetPath = productFlavorName ? + "${productFlavorName}/${buildTypeName}" : + "${buildTypeName}" + + // React js bundle directories + def jsBundleDirConfigName = "jsBundleDir${targetName}" + def jsBundleDir = elvisFile(config."$jsBundleDirConfigName") ?: + file("$buildDir/intermediates/assets/${targetPath}") + + def resourcesDirConfigName = "resourcesDir${targetName}" + def resourcesDir = elvisFile(config."${resourcesDirConfigName}") ?: + file("$buildDir/intermediates/res/merged/${targetPath}") + def jsBundleFile = file("$jsBundleDir/$bundleAssetName") + + // Bundle task name for variant + def bundleJsAndAssetsTaskName = "bundle${targetName}JsAndAssets" + + def currentBundleTask = tasks.create( + name: bundleJsAndAssetsTaskName, + type: Exec) { + group = "react" + description = "bundle JS and assets for ${targetName}." + + // Create dirs if they are not there (e.g. the "clean" task just ran) + doFirst { + jsBundleDir.mkdirs() + resourcesDir.mkdirs() + } + + // Set up inputs and outputs so gradle can cache the result + inputs.files fileTree(dir: reactRoot, excludes: inputExcludes) + outputs.dir jsBundleDir + outputs.dir resourcesDir + + // Set up the call to the react-native cli + workingDir reactRoot + + // Set up dev mode + def devEnabled = !targetName.toLowerCase().contains("release") + if (Os.isFamily(Os.FAMILY_WINDOWS)) { + commandLine "cmd", "/c", "node", "node_modules/react-native/local-cli/cli.js", "bundle", "--platform", "android", "--dev", "${devEnabled}", + "--entry-file", entryFile, "--bundle-output", jsBundleFile, "--assets-dest", resourcesDir + } else { + commandLine "node", "node_modules/react-native/local-cli/cli.js", "bundle", "--platform", "android", "--dev", "${devEnabled}", + "--entry-file", entryFile, "--bundle-output", jsBundleFile, "--assets-dest", resourcesDir + } + + enabled config."bundleIn${targetName}" || + config."bundleIn${buildTypeName.capitalize()}" ?: + targetName.toLowerCase().contains("release") + } + + // Hook bundle${productFlavor}${buildType}JsAndAssets into the android build process + currentBundleTask.dependsOn("merge${targetName}Resources") + currentBundleTask.dependsOn("merge${targetName}Assets") + + runBefore("processArmeabi-v7a${targetName}Resources", currentBundleTask) + runBefore("processX86${targetName}Resources", currentBundleTask) + runBefore("processUniversal${targetName}Resources", currentBundleTask) + runBefore("process${targetName}Resources", currentBundleTask) + } + } +} diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..6652a54 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + diff --git a/android/app/src/main/java/com/reactnativecamerakit/MainActivity.java b/android/app/src/main/java/com/reactnativecamerakit/MainActivity.java new file mode 100644 index 0000000..68ee5e4 --- /dev/null +++ b/android/app/src/main/java/com/reactnativecamerakit/MainActivity.java @@ -0,0 +1,40 @@ +package com.reactnativecamerakit; + +import com.facebook.react.ReactActivity; +import com.facebook.react.ReactPackage; +import com.facebook.react.shell.MainReactPackage; + +import java.util.Arrays; +import java.util.List; + +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 "ReactNativeCameraKit"; + } + + /** + * Returns whether dev mode should be enabled. + * This enables e.g. the dev menu. + */ + @Override + protected boolean getUseDeveloperSupport() { + return BuildConfig.DEBUG; + } + + /** + * A list of packages used by the app. If the app uses additional views + * or modules besides the default ones, add more packages here. + */ + @Override + protected List getPackages() { + return Arrays.asList( + new MainReactPackage() + ); + } +} diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000..cde69bc Binary files /dev/null and b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 0000000..c133a0c Binary files /dev/null and b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 0000000..bfa42f0 Binary files /dev/null and b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000..324e72c Binary files /dev/null and b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/values/strings.xml b/android/app/src/main/res/values/strings.xml new file mode 100644 index 0000000..e80bed5 --- /dev/null +++ b/android/app/src/main/res/values/strings.xml @@ -0,0 +1,3 @@ + + ReactNativeCameraKit + diff --git a/android/app/src/main/res/values/styles.xml b/android/app/src/main/res/values/styles.xml new file mode 100644 index 0000000..319eb0c --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,8 @@ + + + + + + diff --git a/android/build.gradle b/android/build.gradle new file mode 100644 index 0000000..403a007 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,24 @@ +// 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:1.3.1' + + // 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 "$projectDir/../../node_modules/react-native/android" + } + } +} diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..1fd964e --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,20 @@ +# 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/android/gradle/wrapper/gradle-wrapper.jar b/android/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..b5166da Binary files /dev/null and b/android/gradle/wrapper/gradle-wrapper.jar differ diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..b9fbfab --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-2.4-all.zip diff --git a/android/gradlew b/android/gradlew new file mode 100755 index 0000000..91a7e26 --- /dev/null +++ b/android/gradlew @@ -0,0 +1,164 @@ +#!/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/android/gradlew.bat b/android/gradlew.bat new file mode 100644 index 0000000..aec9973 --- /dev/null +++ b/android/gradlew.bat @@ -0,0 +1,90 @@ +@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/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..9237993 --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,3 @@ +rootProject.name = 'ReactNativeCameraKit' + +include ':app' diff --git a/index.android.js b/index.android.js new file mode 100644 index 0000000..94b42e0 --- /dev/null +++ b/index.android.js @@ -0,0 +1,51 @@ +/** + * Sample React Native App + * https://github.com/facebook/react-native + */ + +import React, { + AppRegistry, + Component, + StyleSheet, + Text, + View +} from 'react-native'; + +class ReactNativeCameraKit extends Component { + render() { + return ( + + + Welcome to React Native! + + + To get started, edit index.android.js + + + Shake or press menu button for dev menu + + + ); + } +} + +const styles = StyleSheet.create({ + container: { + flex: 1, + justifyContent: 'center', + alignItems: 'center', + backgroundColor: '#F5FCFF', + }, + welcome: { + fontSize: 20, + textAlign: 'center', + margin: 10, + }, + instructions: { + textAlign: 'center', + color: '#333333', + marginBottom: 5, + }, +}); + +AppRegistry.registerComponent('ReactNativeCameraKit', () => ReactNativeCameraKit); diff --git a/index.ios.js b/index.ios.js new file mode 100644 index 0000000..6f710cd --- /dev/null +++ b/index.ios.js @@ -0,0 +1,84 @@ +import React from 'react-native'; + +const { + AppRegistry, + Component, + StyleSheet, + Text, + View, + Image, + TouchableOpacity, + PixelRatio, + NativeModules: { + ReactNativeCameraKit + } + } = React; + +class Example extends Component { + state = { + photoSource: null, + error: null + }; + + selectPhotoTapped() { + const options = { + message: 'Recent Images', + takePhotoActionTitle: 'Take a Photo', + pickPhotoActionTitle: 'Gallery', + cancelActionTitle: 'Cancel', + sendSelectedPhotosTitle: 'Send %lu Photo', + aspectRatioInfoMessage: 'Your images look best with 16:9 ratio', + aspectRatios: ["16:9", "1:1", "4:3", "3:2", "2:3", "3:4", "9:16"], + collectionName: 'eCom' + }; + + ReactNativeCameraKit.presentPhotoPicker(options, (response) => { + if (response.images) { + const source = {uri: 'data:image/jpeg;base64,' + response.images[response.images.length -1], isStatic: true}; + this.setState({ + photoSource: source + }); + } + if (response.error) { + this.setState({ + error: response.error + }); + } + }); + } + render() { + return ( + + + +{ this.state.photoSource === null ? Select a Photo : + +} + +{ this.state.error ? this.state.error : null } + + +); +} +} + +const styles = StyleSheet.create({ + container: { + flex: 1, + justifyContent: 'center', + alignItems: 'center', + backgroundColor: '#F5FCFF' + }, + photoContainer: { + borderColor: '#9B9B9B', + justifyContent: 'center', + alignItems: 'center', + borderWidth: 1 / PixelRatio.get() + }, + photo: { + width: 150, + height: 150 + } +}); + +AppRegistry.registerComponent('ReactNativeCameraKit', () => Example); diff --git a/ios/CameraSessionManager.swift b/ios/CameraSessionManager.swift new file mode 100644 index 0000000..d15c94c --- /dev/null +++ b/ios/CameraSessionManager.swift @@ -0,0 +1,183 @@ +// +// CameraSessionManager.swift +// ReactNativeCameraKit +// +// Created by Natalia Grankina on 4/13/16. +// Copyright © 2016 Facebook. All rights reserved. +// + +import UIKit +import AVFoundation + +enum CameraType { + case FrontFacingCamera + case BackFacingCamera +} + +class CameraSessionManager: NSObject { + var captureDevice: AVCaptureDevice! + var previewLayer: AVCaptureVideoPreviewLayer! + var captureSession: AVCaptureSession! + var stillImageOutput: AVCaptureStillImageOutput! + var flashMode: AVCaptureFlashMode = .Auto + + override init() { + super.init() + self.captureSession = AVCaptureSession() + self.captureSession.sessionPreset = AVCaptureSessionPresetHigh + } + + convenience init(cameraType: CameraType) { + self.init() + + captureSession.beginConfiguration() + initiateCaptureSessionForCamera(cameraType) + addStillImageOutput() + addVideoPreviewLayer() + captureSession.commitConfiguration() + } + + internal func addVideoPreviewLayer() { + self.previewLayer = AVCaptureVideoPreviewLayer(session: captureSession) as AVCaptureVideoPreviewLayer + self.previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill + } + + internal func initiateCaptureSessionForCamera(cameraType: CameraType) { + let devices = AVCaptureDevice.devices() + + for device in devices { + if (device.hasMediaType(AVMediaTypeVideo)) { + switch (cameraType) { + case .FrontFacingCamera: + if (device.position == AVCaptureDevicePosition.Front) { + self.captureDevice = device as! AVCaptureDevice + } + break + case .BackFacingCamera: + if (device.position == AVCaptureDevicePosition.Back) { + self.captureDevice = device as! AVCaptureDevice + } + break + } + } + } + + do { + let possibleCameraInput: AnyObject? = try AVCaptureDeviceInput(device: self.captureDevice) + if let cameraInput = possibleCameraInput as? AVCaptureDeviceInput { + if self.captureSession.canAddInput(cameraInput) { + self.captureSession.addInput(cameraInput) + } + } + } catch let error as NSError { + print(error) + } + } + + func assignVideoOrienationForVideoConnection(videoConnection: AVCaptureConnection) { + var newOrientation: AVCaptureVideoOrientation + switch (UIDevice.currentDevice().orientation) { + case .Portrait: + newOrientation = AVCaptureVideoOrientation.Portrait + break + case .PortraitUpsideDown: + newOrientation = AVCaptureVideoOrientation.PortraitUpsideDown + break + case .LandscapeLeft: + newOrientation = AVCaptureVideoOrientation.LandscapeRight + break + case .LandscapeRight: + newOrientation = AVCaptureVideoOrientation.LandscapeLeft + break + default: + newOrientation = AVCaptureVideoOrientation.Portrait + } + + videoConnection.videoOrientation = newOrientation + } + + func getOrientationAdaptedCaptureConnection() -> AVCaptureConnection? + { + var videoConnection: AVCaptureConnection? = nil + for connection in self.stillImageOutput.connections { + for port in connection.inputPorts! { + if (port.mediaType == AVMediaTypeVideo) { + videoConnection = connection as? AVCaptureConnection + self.assignVideoOrienationForVideoConnection(videoConnection!) + break + } + } + if (videoConnection != nil) { + break + } + } + return videoConnection + } + + internal func addStillImageOutput() { + self.stillImageOutput = AVCaptureStillImageOutput() + self.stillImageOutput.outputSettings = NSDictionary(objects: [AVVideoCodecJPEG], forKeys: [AVVideoCodecKey]) as! [NSObject : AnyObject] + self.getOrientationAdaptedCaptureConnection() + if self.captureSession.canAddOutput(self.stillImageOutput) { + self.captureSession.addOutput(self.stillImageOutput) + } + + do { + if (captureDevice.isFocusModeSupported(AVCaptureFocusMode.ContinuousAutoFocus)) { + try captureDevice.lockForConfiguration() + if captureDevice.isFlashModeSupported(self.flashMode) { + captureDevice.flashMode = self.flashMode + } + if captureDevice.isFocusModeSupported(.ContinuousAutoFocus) { + captureDevice.focusMode = AVCaptureFocusMode.ContinuousAutoFocus + } + if captureDevice.isWhiteBalanceModeSupported(.ContinuousAutoWhiteBalance) { + captureDevice.whiteBalanceMode = AVCaptureWhiteBalanceMode.ContinuousAutoWhiteBalance + } + captureDevice.unlockForConfiguration() + } + } catch let error as NSError { + print(error) + } + } + + internal func captureStillImage(completionHandler: ((UIImage) -> Void)!) { + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) { + let videoConnection = self.getOrientationAdaptedCaptureConnection() + if (videoConnection != nil) { + self.stillImageOutput.captureStillImageAsynchronouslyFromConnection(videoConnection, completionHandler: + { (imageSampleBuffer: CMSampleBuffer!, _) -> Void in + let stillImageData = AVCaptureStillImageOutput.jpegStillImageNSDataRepresentation(imageSampleBuffer) + let stillImage = UIImage(data: stillImageData) + + completionHandler(stillImage!) + }) + } + } + } + + func changeFlashMode(mode: AVCaptureFlashMode) { + do { + if (captureDevice.hasFlash && captureDevice.isFlashModeSupported(mode) && captureDevice.flashMode != mode) { + try captureDevice.lockForConfiguration() + captureDevice.flashMode = mode + self.flashMode = mode + captureDevice.unlockForConfiguration() + } + } catch let error as NSError { + print(error) + } + } + + func stopSession() { + self.captureSession.stopRunning() + + for input in self.captureSession.inputs { + self.captureSession.removeInput(input as! AVCaptureInput) + } + + for output in self.captureSession.outputs { + self.captureSession.removeOutput(output as! AVCaptureOutput) + } + } +} \ No newline at end of file diff --git a/ios/CameraViewController.swift b/ios/CameraViewController.swift new file mode 100644 index 0000000..6c55afc --- /dev/null +++ b/ios/CameraViewController.swift @@ -0,0 +1,385 @@ +// +// CameraViewController.swift +// ReactNativeCameraKit +// +// Created by Natalia Grankina on 4/13/16. +// Copyright © 2016 Facebook. All rights reserved. +// + +import UIKit +import AVFoundation +import AssetsLibrary +import Photos + +struct AspectRatio { + let widthRatio: Int + let heightRatio: Int + + init(widthRatio: Int, heightRatio: Int) { + self.widthRatio = widthRatio + self.heightRatio = heightRatio + } +} + +class CameraViewController : UIViewController, PhotoViewControllerDelegate { + var cameraViewControllerDelegate: CameraViewControllerDelegate? + + var cameraManager: CameraSessionManager! + var cameraOptions: [String: AnyObject]! + let topBarHeight: CGFloat = 50 + var topBarButtonSize: CGSize! + let bottomBarHeight: CGFloat = 115 + var flashButton: UIButton! + let flashModes = ["Auto", "On", "Off"] + var flashModeSelector: UISegmentedControl! + var ratioField = UITextField() + let aspectRatios: [String] + var aspectRatio: AspectRatio! + var ratioLayer = UIView() + var infoLabel: UITextField! + + let flashColor = UIColor(colorLiteralRed: 0.95, green: 0.76, blue: 0.2, alpha: 1) + + let assetCollectionName: String! + + init(cameraOptions: [String: AnyObject]) { + self.cameraOptions = cameraOptions + self.aspectRatios = cameraOptions["aspectRatios"] as! [String] + self.assetCollectionName = cameraOptions["collectionName"] as! String; + super.init(nibName: nil, bundle: nil) + + self.aspectRatio = self.extractRatio(aspectRatios[0]) + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func prefersStatusBarHidden() -> Bool { + return true + } + + override func shouldAutorotate() -> Bool { + return false + } + + override func viewDidAppear(animated: Bool) { + super.viewDidAppear(animated) + + self.setupCameraManager(.BackFacingCamera) + + let sessionQueue = dispatch_queue_create("cameraQueue", DISPATCH_QUEUE_SERIAL) + dispatch_async(sessionQueue) { () -> Void in + self.cameraManager.captureSession.startRunning() + } + + self.buildUi() + } + + private func setupCameraManager(cameraType: CameraType) { + self.cameraManager = CameraSessionManager(cameraType: cameraType) + self.cameraManager.previewLayer.frame = CGRect(x: 0, y: topBarHeight, width: self.view.frame.size.width, height: self.view.frame.size.height - (topBarHeight + bottomBarHeight)) + self.view.layer.addSublayer(self.cameraManager.previewLayer) + self.fitAspectRatio(aspectRatio) + } + + private func buildUi() { + topBarButtonSize = CGSizeMake(view.bounds.size.height * 0.04, view.bounds.size.height * 0.04) + + self.addToolbars() + self.addShutterButton() + self.addCloseButton() + self.addFlashButton() + self.addFlashModeSelector() + self.addRatioSelector() + } + + private func addToolbars() { + let topBarView = UIView() + topBarView.frame = CGRect(x: 0, y: 0, width: self.view.frame.size.width, height: topBarHeight) + topBarView.backgroundColor = UIColor.blackColor() + self.view.addSubview(topBarView) + + let bottomBarView = UIView() + bottomBarView.frame = CGRect(x: 0, y: self.view.frame.size.height - bottomBarHeight, width: self.view.frame.size.width, height: bottomBarHeight) + bottomBarView.backgroundColor = UIColor.blackColor() + self.view.addSubview(bottomBarView) + } + + private func addShutterButton() { + let shutterButtonSize = CGSizeMake(self.view.bounds.size.width * 0.23, self.view.bounds.size.width * 0.23) + + let image = UIImage(named: "ShutterIcon") as UIImage? + let button = UIButton(type: UIButtonType.Custom) as UIButton + button.frame = CGRect(origin: CGPoint(x: 0, y: 0), size: shutterButtonSize) + button.center = CGPointMake(self.view.frame.size.width / 2, self.view.frame.size.height - shutterButtonSize.height / 2 - 5) + button.setImage(image, forState: .Normal) + + button.addTarget(self, action: "onTakePhoto:", forControlEvents: UIControlEvents.TouchUpInside) + + self.view.addSubview(button) + } + + private func addCloseButton() { + let image = UIImage(named: "CloseIcon") as UIImage? + let closeButton = UIButton(type: UIButtonType.Custom) as UIButton + closeButton.frame = CGRect(origin: CGPoint(x: 0, y: 0), size: topBarButtonSize) + closeButton.center = CGPointMake(topBarButtonSize.width / 2, topBarHeight / 2) + closeButton.setImage(image, forState: .Normal) + + closeButton.addTarget(self, action: "onClose:", forControlEvents: UIControlEvents.TouchUpInside) + + self.view.addSubview(closeButton) + } + + func addFlashButton() { + let image = UIImage(named: "FlashAutoIcon") as UIImage? + flashButton = UIButton(type: UIButtonType.Custom) as UIButton + flashButton.frame = CGRect(origin: CGPoint(x: self.view.bounds.size.width - topBarButtonSize.width, y: 0), size: topBarButtonSize) + flashButton.center = CGPointMake(self.view.bounds.size.width - topBarButtonSize.width / 2, topBarHeight / 2) + flashButton.setImage(image, forState: .Normal) + + flashButton.addTarget(self, action: "onFlashChange:", forControlEvents: UIControlEvents.TouchUpInside) + + self.view.addSubview(flashButton) + } + + func addFlashModeSelector() { + let controlWidth = 0.6 * self.view.bounds.size.width + flashModeSelector = UISegmentedControl(items: flashModes) + flashModeSelector.selectedSegmentIndex = 0 + flashModeSelector.frame = CGRectMake((self.view.bounds.size.width - controlWidth) / 2, 0, controlWidth, topBarHeight) + flashModeSelector.backgroundColor = UIColor.clearColor() + flashModeSelector.tintColor = UIColor.clearColor() + + flashModeSelector.setTitleTextAttributes([NSForegroundColorAttributeName: UIColor.whiteColor()], forState: UIControlState.Normal) + flashModeSelector.setTitleTextAttributes([NSForegroundColorAttributeName: flashColor], forState: UIControlState.Selected) + + flashModeSelector.addTarget(self, action: "changeFlashMode:", forControlEvents: .ValueChanged) + } + + func addRatioSelector() { + let ratioPicker = UIPickerView() + ratioPicker.showsSelectionIndicator = true + ratioPicker.delegate = self + ratioPicker.dataSource = self + + let toolBar = UIToolbar() + toolBar.barStyle = UIBarStyle.Default + toolBar.tintColor = UIColor.blackColor() + toolBar.translucent = true + toolBar.sizeToFit() + let doneButton = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.Done, target: self, action: "onRatioSelected:") + toolBar.setItems([doneButton], animated: false) + toolBar.userInteractionEnabled = true + + let fieldHeight: CGFloat = 40 + + ratioField.tintColor = UIColor.clearColor() + ratioField.inputView = ratioPicker + ratioField.inputAccessoryView = toolBar + ratioField.text = aspectRatios[0] + ratioField.frame = CGRectMake(self.view.frame.size.width * 0.85, self.view.frame.size.height - bottomBarHeight, self.view.frame.size.width * 0.15, fieldHeight) + ratioField.textAlignment = NSTextAlignment.Right + ratioField.contentVerticalAlignment = UIControlContentVerticalAlignment.Center + ratioField.textColor = flashColor + self.view.addSubview(ratioField) + self.view.addSubview(ratioLayer) + + infoLabel = UITextField() + infoLabel.text = cameraOptions["aspectRatioInfoMessage"] as! String + infoLabel.adjustsFontSizeToFitWidth = true + infoLabel.textColor = UIColor.whiteColor() + infoLabel.textAlignment = NSTextAlignment.Left + infoLabel.frame = CGRectMake(0, self.view.frame.size.height - bottomBarHeight, self.view.frame.size.width * 0.75, fieldHeight) + infoLabel.inputView = ratioPicker + infoLabel.inputAccessoryView = toolBar + self.view.addSubview(infoLabel) + } + + private func fitAspectRatio(aspectRatio: AspectRatio) { + let previewLayerExcess = CropHelper.cropRectangleToFitRatio(self.cameraManager.previewLayer.frame.width, originalRectangleHeight: self.cameraManager.previewLayer.frame.height, widthRatio: aspectRatio.widthRatio, heightRatio: aspectRatio.heightRatio) + + let backgroundColor = UIColor(white: 0, alpha: 0.5) + + self.ratioLayer.removeFromSuperview() + self.ratioLayer = UIView(frame: CGRect(origin: self.cameraManager.previewLayer.frame.origin, size: self.cameraManager.previewLayer.frame.size)) + self.view.addSubview(self.ratioLayer) + + if (previewLayerExcess.verticalExcess != 0.0) { + let topExcess = UIView() + topExcess.frame = CGRect(origin: CGPoint(x: 0, y: 0), size: CGSize(width: self.cameraManager.previewLayer.frame.width, height: previewLayerExcess.verticalExcess / 2)) + topExcess.backgroundColor = backgroundColor + self.ratioLayer.addSubview(topExcess) + + let bottomExcess = UIView() + bottomExcess.frame = CGRect(x: self.cameraManager.previewLayer.frame.origin.x, y: self.cameraManager.previewLayer.frame.height - previewLayerExcess.verticalExcess / 2, width: self.cameraManager.previewLayer.frame.width, height: previewLayerExcess.verticalExcess / 2) + bottomExcess.backgroundColor = backgroundColor + self.ratioLayer.addSubview(bottomExcess) + } else { + let leftExcess = UIView() + leftExcess.frame = CGRect(origin: CGPoint(x: 0, y: 0), size: CGSize(width: previewLayerExcess.horizontalExcess / 2, height: self.cameraManager.previewLayer.frame.height)) + leftExcess.backgroundColor = backgroundColor + self.ratioLayer.addSubview(leftExcess) + + let rightExcess = UIView() + rightExcess.frame = CGRect(x: self.cameraManager.previewLayer.frame.origin.x + self.cameraManager.previewLayer.frame.width - previewLayerExcess.horizontalExcess / 2, y: 0, width: previewLayerExcess.horizontalExcess / 2, height: self.cameraManager.previewLayer.frame.height) + rightExcess.backgroundColor = backgroundColor + self.ratioLayer.addSubview(rightExcess) + } + } + + func onFlashChange(sender: UIButton) { + sender.selected = !sender.selected + if sender.selected { + flashButton.setImage(UIImage(named: "FlashAutoIcon") as UIImage?, forState: .Normal) + self.view.addSubview(flashModeSelector) + } else { + flashModeSelector.removeFromSuperview() + setFlashIcon() + } + } + + func onRatioSelected(sender: UIButton) { + self.ratioField.resignFirstResponder() + self.infoLabel.resignFirstResponder() + } + + func changeFlashMode(_: UISegmentedControl) { + setFlashIcon() + flashButton.selected = false + flashModeSelector.removeFromSuperview() + } + + private func setFlashIcon() { + switch flashModeSelector.selectedSegmentIndex { + case 1: + cameraManager.changeFlashMode(.On) + flashButton.setImage(UIImage(named: "FlashOnIcon") as UIImage?, forState: .Normal) + break + case 2: + cameraManager.changeFlashMode(.Off) + flashButton.setImage(UIImage(named: "FlashOffIcon") as UIImage?, forState: .Normal) + break + default: + cameraManager.changeFlashMode(.Auto) + flashButton.setImage(UIImage(named: "FlashAutoIcon") as UIImage?, forState: .Normal) + break + } + } + + func onTakePhoto(sender: UIButton) { + self.cameraManager.captureStillImage({ (image: UIImage) -> Void in + let croppedImage = self.cropImage(image) + self.showPhotoViewController(croppedImage) + }) + } + + func onClose(sender: UIButton) { + self.cameraManager.stopSession() + //dismissViewControllerAnimated(true, completion: nil) + if let delegate = self.cameraViewControllerDelegate { + delegate.cameraViewControllerDidCancel(self) + } + } + + func showPhotoViewController(image: UIImage) { + let photoViewController = PhotoViewController(image: image) + photoViewController.delegate = self + photoViewController.view.bounds = self.view.bounds + self.addChildViewController(photoViewController) + self.view.addSubview(photoViewController.view) + photoViewController.didMoveToParentViewController(self) + } + + func hidePhotoViewController(controller: PhotoViewController) { + controller.willMoveToParentViewController(nil) + controller.view.removeFromSuperview() + controller.removeFromParentViewController() + } + + //PhotoViewControllerDelegate + + func retakePhoto(controller: PhotoViewController) { + self.hidePhotoViewController(controller) + } + + func usePhoto(controller: PhotoViewController, photo: UIImage) { + dismissViewControllerAnimated(true, completion: nil) + let imageData = UIImageJPEGRepresentation(photo, 1.0) + let base64 = imageData!.base64EncodedStringWithOptions([]) + + var assetCollection: PHAssetCollection? + var assetCollectionPlaceholder: PHObjectPlaceholder? + + let fetchOptions = PHFetchOptions() + fetchOptions.predicate = NSPredicate(format: "title = %@", self.assetCollectionName) + let collection : PHFetchResult = PHAssetCollection.fetchAssetCollectionsWithType(.Album, subtype: .Any, options: fetchOptions) + if let _: AnyObject = collection.firstObject { + assetCollection = collection.firstObject as? PHAssetCollection + savePhoto(base64, photo: photo, assetCollection: assetCollection!) + } else { + PHPhotoLibrary.sharedPhotoLibrary().performChanges({ + let createAlbumRequest : PHAssetCollectionChangeRequest = PHAssetCollectionChangeRequest.creationRequestForAssetCollectionWithTitle(self.assetCollectionName) + assetCollectionPlaceholder = createAlbumRequest.placeholderForCreatedAssetCollection + }, completionHandler: { success, error in + if (success) { + let collectionFetchResult = PHAssetCollection.fetchAssetCollectionsWithLocalIdentifiers([assetCollectionPlaceholder!.localIdentifier], options: nil) + assetCollection = collectionFetchResult.firstObject as? PHAssetCollection + self.savePhoto(base64, photo: photo, assetCollection: assetCollection!) + } + }) + } + } + + private func savePhoto(imageData: String, photo: UIImage, assetCollection: PHAssetCollection) { + PHPhotoLibrary.sharedPhotoLibrary().performChanges({ () -> Void in + let assetRequest = PHAssetChangeRequest.creationRequestForAssetFromImage(photo) + let assetPlaceholder = assetRequest.placeholderForCreatedAsset + let albumChangeRequest = PHAssetCollectionChangeRequest(forAssetCollection: assetCollection) + albumChangeRequest!.addAssets([assetPlaceholder!]) + }, completionHandler: { (success, error) -> Void in + self.cameraManager.stopSession() + if let delegate = self.cameraViewControllerDelegate { + if success { + delegate.imageHasBeenTaken(self, imageData: imageData) + } else { + delegate.onError(self, error: (error?.localizedDescription)!) + } + } + }) + } + + + func cropImage(image: UIImage) -> UIImage { + let barPart: CGFloat = (topBarHeight + bottomBarHeight) / self.view.bounds.size.height + return CropHelper.cropImage(image, widthRatio: aspectRatio.widthRatio, heightRatio: aspectRatio.heightRatio, verticalPartToCrop: barPart) + } + + func extractRatio(ratioString: String) -> AspectRatio { + let ratios = ratioString.characters.split{$0 == ":"}.map(String.init) + return AspectRatio(widthRatio: Int(ratios[0])!, heightRatio: Int(ratios[1])!) + } +} + +extension CameraViewController: UIPickerViewDataSource { + func numberOfComponentsInPickerView(colorPicker: UIPickerView) -> Int { + return 1 + } + + func pickerView(pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int { + return aspectRatios.count + } +} + +extension CameraViewController: UIPickerViewDelegate { + func pickerView(pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? { + return aspectRatios[row] + } + + func pickerView(pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) { + ratioField.text = aspectRatios[row] + self.aspectRatio = self.extractRatio(aspectRatios[row]) + self.fitAspectRatio(self.aspectRatio) + } +} diff --git a/ios/CameraViewControllerDelegate.swift b/ios/CameraViewControllerDelegate.swift new file mode 100644 index 0000000..4d309e0 --- /dev/null +++ b/ios/CameraViewControllerDelegate.swift @@ -0,0 +1,13 @@ +// +// CameraViewControllerDelegate.swift +// ReactNativeCameraKit +// +// Created by Natalia Grankina on 4/13/16. +// Copyright © 2016 Facebook. All rights reserved. +// + +protocol CameraViewControllerDelegate : NSObjectProtocol { + func imageHasBeenTaken(controller: CameraViewController, imageData: String) + func cameraViewControllerDidCancel(controller: CameraViewController) + func onError(controller: CameraViewController, error: String) +} diff --git a/ios/CropHelper.swift b/ios/CropHelper.swift new file mode 100644 index 0000000..0a9629e --- /dev/null +++ b/ios/CropHelper.swift @@ -0,0 +1,58 @@ +// +// CropHelper.swift +// ReactNativeCameraKit +// +// Created by Natalia Grankina on 4/13/16. +// Copyright © 2016 Facebook. All rights reserved. +// + + +import UIKit + +struct CropInfo { + var verticalExcess: CGFloat + var horizontalExcess: CGFloat + + init(verticalExcess: CGFloat, horizontalExcess: CGFloat) { + self.verticalExcess = verticalExcess + self.horizontalExcess = horizontalExcess + } +} + +class CropHelper: NSObject { + static func cropImage(image: UIImage, widthRatio: Int, heightRatio: Int, verticalPartToCrop: CGFloat = 0) -> UIImage { + let contextImage: UIImage = UIImage(CGImage: image.CGImage!) + let contextSize: CGSize = contextImage.size + + let offset = verticalPartToCrop * contextSize.width + let cropInfo = cropRectangleToFitRatio(contextSize.width - offset, originalRectangleHeight: contextSize.height, widthRatio: heightRatio, heightRatio: widthRatio) + + let rect = CGRectMake(offset / 2 + cropInfo.horizontalExcess / 2, cropInfo.verticalExcess / 2, contextSize.width - (offset + cropInfo.horizontalExcess), contextSize.height - cropInfo.verticalExcess) + let imageRef = CGImageCreateWithImageInRect(contextImage.CGImage, rect) + let newImage = UIImage(CGImage: imageRef!, scale: image.scale, orientation: image.imageOrientation) + + return newImage + } + + static func cropRectangleToFitRatio(originalRectangleWidth: CGFloat, originalRectangleHeight: CGFloat, widthRatio: Int, heightRatio: Int) -> CropInfo { + var newHeight = originalRectangleHeight + var newWidth = originalRectangleWidth + + if (widthRatio > heightRatio) { + newHeight = originalRectangleWidth * CGFloat(heightRatio) / CGFloat(widthRatio) + } else { + if (widthRatio < heightRatio) { + newWidth = originalRectangleHeight * CGFloat(widthRatio) / CGFloat(heightRatio) + } else { + if (originalRectangleWidth > originalRectangleHeight) { + newWidth = originalRectangleHeight + } else { + newHeight = originalRectangleWidth + } + } + } + + return CropInfo(verticalExcess: originalRectangleHeight - newHeight, horizontalExcess: originalRectangleWidth - newWidth) + } +} + diff --git a/ios/PhotoViewController.swift b/ios/PhotoViewController.swift new file mode 100644 index 0000000..8e75e68 --- /dev/null +++ b/ios/PhotoViewController.swift @@ -0,0 +1,78 @@ +// +// PhotoViewController.swift +// ReactNativeCameraKit +// +// Created by Natalia Grankina on 4/13/16. +// Copyright © 2016 Facebook. All rights reserved. +// + +class PhotoViewController: UIViewController { + let image: UIImage + var delegate: PhotoViewControllerDelegate? + + let topBarHeight: CGFloat = 50 + let bottomBarHeight: CGFloat = 50 + let buttonMargin: CGFloat = 10 + + init(image: UIImage) { + self.image = image + super.init(nibName: nil, bundle: nil) + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func prefersStatusBarHidden() -> Bool { + return true + } + + override func viewDidAppear(animated: Bool) { + super.viewDidAppear(animated) + + var imageViewWidth, imageViewHeight: CGFloat + let imageView = UIImageView(image: self.image) + if (image.size.width >= image.size.height) { + imageViewWidth = self.view.frame.size.width + imageViewHeight = imageViewWidth * image.size.height / image.size.width + } else { + imageViewHeight = self.view.frame.size.height - (topBarHeight + bottomBarHeight) + imageViewWidth = imageViewHeight * image.size.width / image.size.height + } + imageView.frame = CGRectMake(self.view.frame.size.width / 2 - imageViewWidth / 2, self.view.frame.size.height / 2 - imageViewHeight / 2, imageViewWidth, imageViewHeight) + self.view.backgroundColor = UIColor.blackColor() + self.view.addSubview(imageView) + + let retakePhoto = "Retake" + let retakeButton = UIButton(type: UIButtonType.Custom) as UIButton + retakeButton.setTitle(retakePhoto, forState: .Normal) + retakeButton.setTitleColor(UIColor.whiteColor(), forState: .Normal) + let retakeLabelSize = retakePhoto.sizeWithAttributes([NSFontAttributeName: retakeButton.titleLabel!.font]) + retakeButton.frame = CGRect(origin: CGPoint(x: 0, y: self.view.frame.size.height - bottomBarHeight), size: CGSize(width: retakeLabelSize.width + 2 * buttonMargin, height: bottomBarHeight)) + retakeButton.addTarget(self, action: "onRetakePhoto:", forControlEvents: UIControlEvents.TouchUpInside) + self.view.addSubview(retakeButton) + + let usePhoto = "Use Photo" + let useButton = UIButton(type: UIButtonType.Custom) as UIButton + useButton.setTitle(usePhoto, forState: .Normal) + useButton.setTitleColor(UIColor.whiteColor(), forState: .Normal) + let useLabelSize = usePhoto.sizeWithAttributes([NSFontAttributeName: useButton.titleLabel!.font]) + let useButtonWidth = useLabelSize.width + 2 * buttonMargin + useButton.frame = CGRect(origin: CGPoint(x: self.view.frame.size.width - useButtonWidth, y: self.view.frame.size.height - bottomBarHeight), size: CGSize(width: useButtonWidth, height: bottomBarHeight)) + useButton.addTarget(self, action: "onUsePhoto:", forControlEvents: UIControlEvents.TouchUpInside) + self.view.addSubview(useButton) + } + + func onRetakePhoto(sender: UIButton) { + if let delegate = self.delegate { + delegate.retakePhoto(self) + } + } + + func onUsePhoto(sender: UIButton) { + if let delegate = self.delegate { + delegate.usePhoto(self, photo: image) + } + } +} + diff --git a/ios/PhotoViewControllerDelegate.swift b/ios/PhotoViewControllerDelegate.swift new file mode 100644 index 0000000..acc4ff8 --- /dev/null +++ b/ios/PhotoViewControllerDelegate.swift @@ -0,0 +1,12 @@ +// +// PhotoViewControllerDelegate.swift +// ReactNativeCameraKit +// +// Created by Natalia Grankina on 4/13/16. +// Copyright © 2016 Facebook. All rights reserved. +// + +protocol PhotoViewControllerDelegate : NSObjectProtocol { + func retakePhoto(controller: PhotoViewController) + func usePhoto(controller: PhotoViewController, photo: UIImage) +} diff --git a/ios/Podfile b/ios/Podfile new file mode 100644 index 0000000..06a847d --- /dev/null +++ b/ios/Podfile @@ -0,0 +1,13 @@ +# Uncomment this line to define a global platform for your project +platform :ios, '8.0' +# Uncomment this line if you're using Swift +use_frameworks! + +target 'ReactNativeCameraKit' do +pod "ImagePickerSheetController" +end + +target 'ReactNativeCameraKitTests' do + +end + diff --git a/ios/Podfile.lock b/ios/Podfile.lock new file mode 100644 index 0000000..e6e876b --- /dev/null +++ b/ios/Podfile.lock @@ -0,0 +1,10 @@ +PODS: + - ImagePickerSheetController (0.9.1) + +DEPENDENCIES: + - ImagePickerSheetController + +SPEC CHECKSUMS: + ImagePickerSheetController: 3c58c9fee6dcf36485222358a021f6b734f997ba + +COCOAPODS: 0.39.0 diff --git a/ios/Pods/ImagePickerSheetController/ImagePickerSheetController/ImagePickerSheetController/AnimationController.swift b/ios/Pods/ImagePickerSheetController/ImagePickerSheetController/ImagePickerSheetController/AnimationController.swift new file mode 100644 index 0000000..915a8fb --- /dev/null +++ b/ios/Pods/ImagePickerSheetController/ImagePickerSheetController/ImagePickerSheetController/AnimationController.swift @@ -0,0 +1,80 @@ +// +// AnimationController.swift +// ImagePickerSheet +// +// Created by Laurin Brandner on 25/05/15. +// Copyright (c) 2015 Laurin Brandner. All rights reserved. +// + +import UIKit + +class AnimationController: NSObject { + + let imagePickerSheetController: ImagePickerSheetController + let presenting: Bool + + // MARK: - Initialization + + init(imagePickerSheetController: ImagePickerSheetController, presenting: Bool) { + self.imagePickerSheetController = imagePickerSheetController + self.presenting = presenting + } + + // MARK: - Animation + + private func animatePresentation(context: UIViewControllerContextTransitioning) { + guard let containerView = context.containerView() else { + return + } + + containerView.addSubview(imagePickerSheetController.view) + + let sheetOriginY = imagePickerSheetController.sheetCollectionView.frame.origin.y + imagePickerSheetController.sheetCollectionView.frame.origin.y = containerView.bounds.maxY + imagePickerSheetController.backgroundView.alpha = 0 + + UIView.animateWithDuration(transitionDuration(context), delay: 0, options: .CurveEaseOut, animations: { () -> Void in + self.imagePickerSheetController.sheetCollectionView.frame.origin.y = sheetOriginY + self.imagePickerSheetController.backgroundView.alpha = 1 + }, completion: { _ in + context.completeTransition(true) + }) + } + + private func animateDismissal(context: UIViewControllerContextTransitioning) { + guard let containerView = context.containerView() else { + return + } + + UIView.animateWithDuration(transitionDuration(context), delay: 0, options: .CurveEaseIn, animations: { () -> Void in + self.imagePickerSheetController.sheetCollectionView.frame.origin.y = containerView.bounds.maxY + self.imagePickerSheetController.backgroundView.alpha = 0 + }, completion: { _ in + self.imagePickerSheetController.view.removeFromSuperview() + context.completeTransition(true) + }) + } + +} + +// MARK: - UIViewControllerAnimatedTransitioning +extension AnimationController: UIViewControllerAnimatedTransitioning { + + func transitionDuration(transitionContext: UIViewControllerContextTransitioning?) -> NSTimeInterval { + guard #available(iOS 9, *) else { + return 0.3 + } + + return 0.25 + } + + func animateTransition(transitionContext: UIViewControllerContextTransitioning) { + if presenting { + animatePresentation(transitionContext) + } + else { + animateDismissal(transitionContext) + } + } + +} diff --git a/ios/Pods/ImagePickerSheetController/ImagePickerSheetController/ImagePickerSheetController/ImagePickerAction.swift b/ios/Pods/ImagePickerSheetController/ImagePickerSheetController/ImagePickerSheetController/ImagePickerAction.swift new file mode 100644 index 0000000..7469a86 --- /dev/null +++ b/ios/Pods/ImagePickerSheetController/ImagePickerSheetController/ImagePickerSheetController/ImagePickerAction.swift @@ -0,0 +1,75 @@ +// +// ImagePickerAction.swift +// ImagePickerSheet +// +// Created by Laurin Brandner on 24/05/15. +// Copyright (c) 2015 Laurin Brandner. All rights reserved. +// + +import Foundation + +public enum ImagePickerActionStyle { + case Default + case Cancel +} + +public class ImagePickerAction { + + public typealias Title = Int -> String + public typealias Handler = (ImagePickerAction) -> () + public typealias SecondaryHandler = (ImagePickerAction, Int) -> () + + /// The title of the action's button. + public let title: String + + /// The title of the action's button when more than one image is selected. + public let secondaryTitle: Title + + /// The style of the action. This is used to call a cancel handler when dismissing the controller by tapping the background. + public let style: ImagePickerActionStyle + + let handler: Handler + let secondaryHandler: SecondaryHandler + + /// Initializes a new ImagePickerAction. The secondary title and handler are used when at least 1 image has been selected. + /// Secondary title defaults to title if not specified. + /// Secondary handler defaults to handler if not specified. + public convenience init(title: String, secondaryTitle: String? = nil, style: ImagePickerActionStyle = .Default, handler: Handler, secondaryHandler: SecondaryHandler? = nil) { + self.init(title: title, secondaryTitle: secondaryTitle.map { string in { _ in string }}, style: style, handler: handler, secondaryHandler: secondaryHandler) + } + + /// Initializes a new ImagePickerAction. The secondary title and handler are used when at least 1 image has been selected. + /// Secondary title defaults to title if not specified. Use the closure to format a title according to the selection. + /// Secondary handler defaults to handler if not specified + public init(title: String, secondaryTitle: Title?, style: ImagePickerActionStyle = .Default, handler: Handler, var secondaryHandler: SecondaryHandler? = nil) { + if secondaryHandler == nil { + secondaryHandler = { action, _ in + handler(action) + } + } + + self.title = title + self.secondaryTitle = secondaryTitle ?? { _ in title } + self.style = style + self.handler = handler + self.secondaryHandler = secondaryHandler! + } + + func handle(numberOfImages: Int = 0) { + if numberOfImages > 0 { + secondaryHandler(self, numberOfImages) + } + else { + handler(self) + } + } + +} + +func ?? (left: ImagePickerAction.Title?, right: ImagePickerAction.Title) -> ImagePickerAction.Title { + if let left = left { + return left + } + + return right +} diff --git a/ios/Pods/ImagePickerSheetController/ImagePickerSheetController/ImagePickerSheetController/ImagePickerSheetController.swift b/ios/Pods/ImagePickerSheetController/ImagePickerSheetController/ImagePickerSheetController/ImagePickerSheetController.swift new file mode 100644 index 0000000..5009e74 --- /dev/null +++ b/ios/Pods/ImagePickerSheetController/ImagePickerSheetController/ImagePickerSheetController/ImagePickerSheetController.swift @@ -0,0 +1,482 @@ +// +// ImagePickerController.swift +// ImagePickerSheet +// +// Created by Laurin Brandner on 24/05/15. +// Copyright (c) 2015 Laurin Brandner. All rights reserved. +// + +import Foundation +import Photos + +private let previewCollectionViewInset: CGFloat = 5 + +/// The media type an instance of ImagePickerSheetController can display +public enum ImagePickerMediaType { + case Image + case Video + case ImageAndVideo +} + +@available(iOS 8.0, *) +public class ImagePickerSheetController: UIViewController { + + private lazy var sheetController: SheetController = { + let controller = SheetController(previewCollectionView: self.previewCollectionView) + controller.actionHandlingCallback = { [weak self] in + self?.dismissViewControllerAnimated(true, completion: nil) + } + + return controller + }() + + var sheetCollectionView: UICollectionView { + return sheetController.sheetCollectionView + } + + private(set) lazy var previewCollectionView: PreviewCollectionView = { + let collectionView = PreviewCollectionView() + collectionView.accessibilityIdentifier = "ImagePickerSheetPreview" + collectionView.backgroundColor = .clearColor() + collectionView.allowsMultipleSelection = true + collectionView.imagePreviewLayout.sectionInset = UIEdgeInsetsMake(previewCollectionViewInset, previewCollectionViewInset, previewCollectionViewInset, previewCollectionViewInset) + collectionView.imagePreviewLayout.showsSupplementaryViews = false + collectionView.dataSource = self + collectionView.delegate = self + collectionView.showsHorizontalScrollIndicator = false + collectionView.alwaysBounceHorizontal = true + collectionView.registerClass(PreviewCollectionViewCell.self, forCellWithReuseIdentifier: NSStringFromClass(PreviewCollectionViewCell.self)) + collectionView.registerClass(PreviewSupplementaryView.self, forSupplementaryViewOfKind: UICollectionElementKindSectionHeader, withReuseIdentifier: NSStringFromClass(PreviewSupplementaryView.self)) + + return collectionView + }() + + private var supplementaryViews = [Int: PreviewSupplementaryView]() + + lazy var backgroundView: UIView = { + let view = UIView() + view.accessibilityIdentifier = "ImagePickerSheetBackground" + view.backgroundColor = UIColor(white: 0.0, alpha: 0.3961) + view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: "cancel")) + + return view + }() + + /// All the actions. The first action is shown at the top. + public var actions: [ImagePickerAction] { + return sheetController.actions + } + + /// Maximum selection of images. + public var maximumSelection: Int? + + private var selectedImageIndices = [Int]() { + didSet { + sheetController.numberOfSelectedImages = selectedImageIndices.count + } + } + + /// The selected image assets + public var selectedImageAssets: [PHAsset] { + return selectedImageIndices.map { self.assets[$0] } + } + + /// The media type of the displayed assets + public let mediaType: ImagePickerMediaType + + private var assets = [PHAsset]() + + private lazy var requestOptions: PHImageRequestOptions = { + let options = PHImageRequestOptions() + options.deliveryMode = .HighQualityFormat + options.resizeMode = .Fast + + return options + }() + + private let imageManager = PHCachingImageManager() + + /// Whether the image preview has been elarged. This is the case when at least once + /// image has been selected. + public private(set) var enlargedPreviews = false + + private let minimumPreviewHeight: CGFloat = 129 + private var maximumPreviewHeight: CGFloat = 129 + + private var previewCheckmarkInset: CGFloat { + guard #available(iOS 9, *) else { + return 3.5 + } + + return 12.5 + } + + // MARK: - Initialization + + public init(mediaType: ImagePickerMediaType) { + self.mediaType = mediaType + super.init(nibName: nil, bundle: nil) + initialize() + } + + public required init?(coder aDecoder: NSCoder) { + self.mediaType = .ImageAndVideo + super.init(coder: aDecoder) + initialize() + } + + private func initialize() { + modalPresentationStyle = .Custom + transitioningDelegate = self + + NSNotificationCenter.defaultCenter().addObserver(self, selector: "cancel", name: UIApplicationDidEnterBackgroundNotification, object: nil) + } + + deinit { + NSNotificationCenter.defaultCenter().removeObserver(self) + } + + // MARK: - View Lifecycle + + override public func loadView() { + super.loadView() + + view.addSubview(backgroundView) + view.addSubview(sheetCollectionView) + } + + public override func viewWillAppear(animated: Bool) { + super.viewWillAppear(animated) + + preferredContentSize = CGSize(width: 400, height: view.frame.height) + + if PHPhotoLibrary.authorizationStatus() == .Authorized { + prepareAssets() + } + } + + public override func viewDidAppear(animated: Bool) { + super.viewDidAppear(animated) + + if PHPhotoLibrary.authorizationStatus() == .NotDetermined { + PHPhotoLibrary.requestAuthorization() { status in + if status == .Authorized { + dispatch_async(dispatch_get_main_queue()) { + self.prepareAssets() + self.previewCollectionView.reloadData() + self.sheetCollectionView.reloadData() + self.view.setNeedsLayout() + + // Explicitely disable animations so it wouldn't animate either + // if it was in a popover + CATransaction.begin() + CATransaction.setDisableActions(true) + self.view.layoutIfNeeded() + CATransaction.commit() + } + } + } + } + } + + // MARK: - Actions + + /// Adds an new action. + /// If the passed action is of type Cancel, any pre-existing Cancel actions will be removed. + /// Always arranges the actions so that the Cancel action appears at the bottom. + public func addAction(action: ImagePickerAction) { + sheetController.addAction(action) + view.setNeedsLayout() + } + + @objc private func cancel() { + sheetController.handleCancelAction() + } + + // MARK: - Images + + private func sizeForAsset(asset: PHAsset, scale: CGFloat = 1) -> CGSize { + let proportion = CGFloat(asset.pixelWidth)/CGFloat(asset.pixelHeight) + + let imageHeight = maximumPreviewHeight - 2 * previewCollectionViewInset + let imageWidth = floor(proportion * imageHeight) + + return CGSize(width: imageWidth * scale, height: imageHeight * scale) + } + + private func prepareAssets() { + fetchAssets() + reloadMaximumPreviewHeight() + reloadCurrentPreviewHeight(invalidateLayout: false) + + // Filter out the assets that are too thin. This can't be done before becuase + // we don't know how tall the images should be + let minImageWidth = 2 * previewCheckmarkInset + (PreviewSupplementaryView.checkmarkImage?.size.width ?? 0) + assets = assets.filter { asset in + let size = sizeForAsset(asset) + return size.width >= minImageWidth + } + } + + private func fetchAssets() { + let options = PHFetchOptions() + options.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: false)] + + switch mediaType { + case .Image: + options.predicate = NSPredicate(format: "mediaType = %d", PHAssetMediaType.Image.rawValue) + case .Video: + options.predicate = NSPredicate(format: "mediaType = %d", PHAssetMediaType.Video.rawValue) + case .ImageAndVideo: + options.predicate = NSPredicate(format: "mediaType = %d OR mediaType = %d", PHAssetMediaType.Image.rawValue, PHAssetMediaType.Video.rawValue) + } + + let fetchLimit = 50 + if #available(iOS 9, *) { + options.fetchLimit = fetchLimit + } + + let result = PHAsset.fetchAssetsWithOptions(options) + let requestOptions = PHImageRequestOptions() + requestOptions.synchronous = true + requestOptions.deliveryMode = .FastFormat + + result.enumerateObjectsUsingBlock { asset, _, stop in + defer { + if self.assets.count > fetchLimit { + stop.initialize(true) + } + } + + if let asset = asset as? PHAsset { + self.imageManager.requestImageDataForAsset(asset, options: requestOptions) { data, _, _, info in + if data != nil { + self.assets.append(asset) + } + } + } + } + } + + private func requestImageForAsset(asset: PHAsset, completion: (image: UIImage?) -> ()) { + let targetSize = sizeForAsset(asset, scale: UIScreen.mainScreen().scale) + requestOptions.synchronous = true + + // Workaround because PHImageManager.requestImageForAsset doesn't work for burst images + if asset.representsBurst { + imageManager.requestImageDataForAsset(asset, options: requestOptions) { data, _, _, _ in + let image = data.flatMap { UIImage(data: $0) } + completion(image: image) + } + } + else { + imageManager.requestImageForAsset(asset, targetSize: targetSize, contentMode: .AspectFill, options: requestOptions) { image, _ in + completion(image: image) + } + } + } + + private func prefetchImagesForAsset(asset: PHAsset) { + let targetSize = sizeForAsset(asset, scale: UIScreen.mainScreen().scale) + imageManager.startCachingImagesForAssets([asset], targetSize: targetSize, contentMode: .AspectFill, options: requestOptions) + } + + // MARK: - Layout + + public override func viewDidLayoutSubviews() { + super.viewDidLayoutSubviews() + + backgroundView.frame = view.bounds + + reloadMaximumPreviewHeight() + reloadCurrentPreviewHeight(invalidateLayout: true) + + let sheetHeight = sheetController.preferredSheetHeight + let sheetSize = CGSize(width: view.bounds.width, height: sheetHeight) + + // This particular order is necessary so that the sheet is layed out + // correctly with and without an enclosing popover + preferredContentSize = sheetSize + sheetCollectionView.frame = CGRect(origin: CGPoint(x: view.bounds.minX, y: view.bounds.maxY-sheetHeight), size: sheetSize) + } + + private func reloadCurrentPreviewHeight(invalidateLayout invalidate: Bool) { + if assets.count <= 0 { + sheetController.setPreviewHeight(0, invalidateLayout: invalidate) + } + else if assets.count > 0 && enlargedPreviews { + sheetController.setPreviewHeight(maximumPreviewHeight, invalidateLayout: invalidate) + } + else { + sheetController.setPreviewHeight(minimumPreviewHeight, invalidateLayout: invalidate) + } + } + + private func reloadMaximumPreviewHeight() { + let maxHeight: CGFloat = 400 + let maxImageWidth = sheetController.preferredSheetWidth - 2 * previewCollectionViewInset + + let assetRatios = assets.map { CGSize(width: max($0.pixelHeight, $0.pixelWidth), height: min($0.pixelHeight, $0.pixelWidth)) } + .map { $0.height / $0.width } + + let assetHeights = assetRatios.map { $0 * maxImageWidth } + .filter { $0 < maxImageWidth && $0 < maxHeight } // Make sure the preview isn't too high eg for squares + .sort(>) + let assetHeight = ceil(assetHeights.first ?? 0) + + // Just a sanity check, to make sure this doesn't exceed 400 points + let scaledHeight = max(min(assetHeight, maxHeight), 200) + maximumPreviewHeight = scaledHeight + 2 * previewCollectionViewInset + } + + // MARK: - + + func enlargePreviewsByCenteringToIndexPath(indexPath: NSIndexPath?, completion: (Bool -> ())?) { + enlargedPreviews = true + previewCollectionView.imagePreviewLayout.invalidationCenteredIndexPath = indexPath + reloadCurrentPreviewHeight(invalidateLayout: false) + + view.setNeedsLayout() + + let animationDuration: NSTimeInterval + if #available(iOS 9, *) { + animationDuration = 0.2 + } + else { + animationDuration = 0.3 + } + + UIView.animateWithDuration(animationDuration, animations: { + self.sheetCollectionView.reloadSections(NSIndexSet(index: 0)) + self.view.layoutIfNeeded() + }, completion: completion) + } + +} + +// MARK: - UICollectionViewDataSource + +extension ImagePickerSheetController: UICollectionViewDataSource { + + public func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int { + return assets.count + } + + public func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { + return 1 + } + + public func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell { + let cell = collectionView.dequeueReusableCellWithReuseIdentifier(NSStringFromClass(PreviewCollectionViewCell.self), forIndexPath: indexPath) as! PreviewCollectionViewCell + + let asset = assets[indexPath.section] + cell.videoIndicatorView.hidden = asset.mediaType != .Video + + requestImageForAsset(asset) { image in + cell.imageView.image = image + } + + cell.selected = selectedImageIndices.contains(indexPath.section) + + return cell + } + + public func collectionView(collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, atIndexPath indexPath: + NSIndexPath) -> UICollectionReusableView { + let view = collectionView.dequeueReusableSupplementaryViewOfKind(UICollectionElementKindSectionHeader, withReuseIdentifier: NSStringFromClass(PreviewSupplementaryView.self), forIndexPath: indexPath) as! PreviewSupplementaryView + view.userInteractionEnabled = false + view.buttonInset = UIEdgeInsetsMake(0.0, previewCheckmarkInset, previewCheckmarkInset, 0.0) + view.selected = selectedImageIndices.contains(indexPath.section) + + supplementaryViews[indexPath.section] = view + + return view + } + +} + +// MARK: - UICollectionViewDelegate + +extension ImagePickerSheetController: UICollectionViewDelegate { + + public func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) { + if let maximumSelection = maximumSelection { + if selectedImageIndices.count >= maximumSelection, + let previousItemIndex = selectedImageIndices.first { + supplementaryViews[previousItemIndex]?.selected = false + selectedImageIndices.removeAtIndex(0) + } + } + + // Just to make sure the image is only selected once + selectedImageIndices = selectedImageIndices.filter { $0 != indexPath.section } + selectedImageIndices.append(indexPath.section) + + if !enlargedPreviews { + enlargePreviewsByCenteringToIndexPath(indexPath) { _ in + self.sheetController.reloadActionItems() + self.previewCollectionView.imagePreviewLayout.showsSupplementaryViews = true + } + } + else { + // scrollToItemAtIndexPath doesn't work reliably + if let cell = collectionView.cellForItemAtIndexPath(indexPath) { + var contentOffset = CGPointMake(cell.frame.midX - collectionView.frame.width / 2.0, 0.0) + contentOffset.x = max(contentOffset.x, -collectionView.contentInset.left) + contentOffset.x = min(contentOffset.x, collectionView.contentSize.width - collectionView.frame.width + collectionView.contentInset.right) + + collectionView.setContentOffset(contentOffset, animated: true) + } + + sheetController.reloadActionItems() + } + + supplementaryViews[indexPath.section]?.selected = true + } + + public func collectionView(collectionView: UICollectionView, didDeselectItemAtIndexPath indexPath: NSIndexPath) { + if let index = selectedImageIndices.indexOf(indexPath.section) { + selectedImageIndices.removeAtIndex(index) + sheetController.reloadActionItems() + } + + supplementaryViews[indexPath.section]?.selected = false + } + +} + +// MARK: - UICollectionViewDelegateFlowLayout + +extension ImagePickerSheetController: UICollectionViewDelegateFlowLayout { + + public func collectionView(collectionView: UICollectionView, layout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize { + let asset = assets[indexPath.section] + let size = sizeForAsset(asset) + + // Scale down to the current preview height, sizeForAsset returns the original size + let currentImagePreviewHeight = sheetController.previewHeight - 2 * previewCollectionViewInset + let scale = currentImagePreviewHeight / size.height + + return CGSize(width: size.width * scale, height: currentImagePreviewHeight) + } + + public func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize { + let checkmarkWidth = PreviewSupplementaryView.checkmarkImage?.size.width ?? 0 + return CGSizeMake(checkmarkWidth + 2 * previewCheckmarkInset, sheetController.previewHeight - 2 * previewCollectionViewInset) + } + +} + +// MARK: - UIViewControllerTransitioningDelegate + +extension ImagePickerSheetController: UIViewControllerTransitioningDelegate { + + public func animationControllerForPresentedController(presented: UIViewController, presentingController presenting: UIViewController, sourceController source: UIViewController) -> UIViewControllerAnimatedTransitioning? { + return AnimationController(imagePickerSheetController: self, presenting: true) + } + + public func animationControllerForDismissedController(dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? { + return AnimationController(imagePickerSheetController: self, presenting: false) + } + +} diff --git a/ios/Pods/ImagePickerSheetController/ImagePickerSheetController/ImagePickerSheetController/Images.xcassets/Contents.json b/ios/Pods/ImagePickerSheetController/ImagePickerSheetController/ImagePickerSheetController/Images.xcassets/Contents.json new file mode 100644 index 0000000..da4a164 --- /dev/null +++ b/ios/Pods/ImagePickerSheetController/ImagePickerSheetController/ImagePickerSheetController/Images.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/ios/Pods/ImagePickerSheetController/ImagePickerSheetController/ImagePickerSheetController/Images.xcassets/PreviewCollectionViewCell-video.imageset/Contents.json b/ios/Pods/ImagePickerSheetController/ImagePickerSheetController/ImagePickerSheetController/Images.xcassets/PreviewCollectionViewCell-video.imageset/Contents.json new file mode 100644 index 0000000..673f028 --- /dev/null +++ b/ios/Pods/ImagePickerSheetController/ImagePickerSheetController/ImagePickerSheetController/Images.xcassets/PreviewCollectionViewCell-video.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "PreviewCollectionViewCell-video.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "PreviewCollectionViewCell-video@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "PreviewCollectionViewCell-video@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/ios/Pods/ImagePickerSheetController/ImagePickerSheetController/ImagePickerSheetController/Images.xcassets/PreviewCollectionViewCell-video.imageset/PreviewCollectionViewCell-video.png b/ios/Pods/ImagePickerSheetController/ImagePickerSheetController/ImagePickerSheetController/Images.xcassets/PreviewCollectionViewCell-video.imageset/PreviewCollectionViewCell-video.png new file mode 100644 index 0000000..26332b8 Binary files /dev/null and b/ios/Pods/ImagePickerSheetController/ImagePickerSheetController/ImagePickerSheetController/Images.xcassets/PreviewCollectionViewCell-video.imageset/PreviewCollectionViewCell-video.png differ diff --git a/ios/Pods/ImagePickerSheetController/ImagePickerSheetController/ImagePickerSheetController/Images.xcassets/PreviewCollectionViewCell-video.imageset/PreviewCollectionViewCell-video@2x.png b/ios/Pods/ImagePickerSheetController/ImagePickerSheetController/ImagePickerSheetController/Images.xcassets/PreviewCollectionViewCell-video.imageset/PreviewCollectionViewCell-video@2x.png new file mode 100644 index 0000000..b11ca27 Binary files /dev/null and b/ios/Pods/ImagePickerSheetController/ImagePickerSheetController/ImagePickerSheetController/Images.xcassets/PreviewCollectionViewCell-video.imageset/PreviewCollectionViewCell-video@2x.png differ diff --git a/ios/Pods/ImagePickerSheetController/ImagePickerSheetController/ImagePickerSheetController/Images.xcassets/PreviewCollectionViewCell-video.imageset/PreviewCollectionViewCell-video@3x.png b/ios/Pods/ImagePickerSheetController/ImagePickerSheetController/ImagePickerSheetController/Images.xcassets/PreviewCollectionViewCell-video.imageset/PreviewCollectionViewCell-video@3x.png new file mode 100644 index 0000000..87d0538 Binary files /dev/null and b/ios/Pods/ImagePickerSheetController/ImagePickerSheetController/ImagePickerSheetController/Images.xcassets/PreviewCollectionViewCell-video.imageset/PreviewCollectionViewCell-video@3x.png differ diff --git a/ios/Pods/ImagePickerSheetController/ImagePickerSheetController/ImagePickerSheetController/Images.xcassets/PreviewSupplementaryView-Checkmark-Selected.imageset/Contents.json b/ios/Pods/ImagePickerSheetController/ImagePickerSheetController/ImagePickerSheetController/Images.xcassets/PreviewSupplementaryView-Checkmark-Selected.imageset/Contents.json new file mode 100644 index 0000000..3abba0e --- /dev/null +++ b/ios/Pods/ImagePickerSheetController/ImagePickerSheetController/ImagePickerSheetController/Images.xcassets/PreviewSupplementaryView-Checkmark-Selected.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x", + "filename" : "PreviewSupplementaryView-Checkmark-Selected.png" + }, + { + "idiom" : "universal", + "scale" : "2x", + "filename" : "PreviewSupplementaryView-Checkmark-Selected@2x.png" + }, + { + "idiom" : "universal", + "scale" : "3x", + "filename" : "PreviewSupplementaryView-Checkmark-Selected@3x.png" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/ios/Pods/ImagePickerSheetController/ImagePickerSheetController/ImagePickerSheetController/Images.xcassets/PreviewSupplementaryView-Checkmark-Selected.imageset/PreviewSupplementaryView-Checkmark-Selected.png b/ios/Pods/ImagePickerSheetController/ImagePickerSheetController/ImagePickerSheetController/Images.xcassets/PreviewSupplementaryView-Checkmark-Selected.imageset/PreviewSupplementaryView-Checkmark-Selected.png new file mode 100644 index 0000000..8d3d970 Binary files /dev/null and b/ios/Pods/ImagePickerSheetController/ImagePickerSheetController/ImagePickerSheetController/Images.xcassets/PreviewSupplementaryView-Checkmark-Selected.imageset/PreviewSupplementaryView-Checkmark-Selected.png differ diff --git a/ios/Pods/ImagePickerSheetController/ImagePickerSheetController/ImagePickerSheetController/Images.xcassets/PreviewSupplementaryView-Checkmark-Selected.imageset/PreviewSupplementaryView-Checkmark-Selected@2x.png b/ios/Pods/ImagePickerSheetController/ImagePickerSheetController/ImagePickerSheetController/Images.xcassets/PreviewSupplementaryView-Checkmark-Selected.imageset/PreviewSupplementaryView-Checkmark-Selected@2x.png new file mode 100644 index 0000000..4a09d61 Binary files /dev/null and b/ios/Pods/ImagePickerSheetController/ImagePickerSheetController/ImagePickerSheetController/Images.xcassets/PreviewSupplementaryView-Checkmark-Selected.imageset/PreviewSupplementaryView-Checkmark-Selected@2x.png differ diff --git a/ios/Pods/ImagePickerSheetController/ImagePickerSheetController/ImagePickerSheetController/Images.xcassets/PreviewSupplementaryView-Checkmark-Selected.imageset/PreviewSupplementaryView-Checkmark-Selected@3x.png b/ios/Pods/ImagePickerSheetController/ImagePickerSheetController/ImagePickerSheetController/Images.xcassets/PreviewSupplementaryView-Checkmark-Selected.imageset/PreviewSupplementaryView-Checkmark-Selected@3x.png new file mode 100644 index 0000000..2f42084 Binary files /dev/null and b/ios/Pods/ImagePickerSheetController/ImagePickerSheetController/ImagePickerSheetController/Images.xcassets/PreviewSupplementaryView-Checkmark-Selected.imageset/PreviewSupplementaryView-Checkmark-Selected@3x.png differ diff --git a/ios/Pods/ImagePickerSheetController/ImagePickerSheetController/ImagePickerSheetController/Images.xcassets/PreviewSupplementaryView-Checkmark.imageset/Contents.json b/ios/Pods/ImagePickerSheetController/ImagePickerSheetController/ImagePickerSheetController/Images.xcassets/PreviewSupplementaryView-Checkmark.imageset/Contents.json new file mode 100644 index 0000000..ae5d3ab --- /dev/null +++ b/ios/Pods/ImagePickerSheetController/ImagePickerSheetController/ImagePickerSheetController/Images.xcassets/PreviewSupplementaryView-Checkmark.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x", + "filename" : "PreviewSupplementaryView-Checkmark.png" + }, + { + "idiom" : "universal", + "scale" : "2x", + "filename" : "PreviewSupplementaryView-Checkmark@2x.png" + }, + { + "idiom" : "universal", + "scale" : "3x", + "filename" : "PreviewSupplementaryView-Checkmark@3x.png" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/ios/Pods/ImagePickerSheetController/ImagePickerSheetController/ImagePickerSheetController/Images.xcassets/PreviewSupplementaryView-Checkmark.imageset/PreviewSupplementaryView-Checkmark.png b/ios/Pods/ImagePickerSheetController/ImagePickerSheetController/ImagePickerSheetController/Images.xcassets/PreviewSupplementaryView-Checkmark.imageset/PreviewSupplementaryView-Checkmark.png new file mode 100644 index 0000000..0106c9d Binary files /dev/null and b/ios/Pods/ImagePickerSheetController/ImagePickerSheetController/ImagePickerSheetController/Images.xcassets/PreviewSupplementaryView-Checkmark.imageset/PreviewSupplementaryView-Checkmark.png differ diff --git a/ios/Pods/ImagePickerSheetController/ImagePickerSheetController/ImagePickerSheetController/Images.xcassets/PreviewSupplementaryView-Checkmark.imageset/PreviewSupplementaryView-Checkmark@2x.png b/ios/Pods/ImagePickerSheetController/ImagePickerSheetController/ImagePickerSheetController/Images.xcassets/PreviewSupplementaryView-Checkmark.imageset/PreviewSupplementaryView-Checkmark@2x.png new file mode 100644 index 0000000..020f970 Binary files /dev/null and b/ios/Pods/ImagePickerSheetController/ImagePickerSheetController/ImagePickerSheetController/Images.xcassets/PreviewSupplementaryView-Checkmark.imageset/PreviewSupplementaryView-Checkmark@2x.png differ diff --git a/ios/Pods/ImagePickerSheetController/ImagePickerSheetController/ImagePickerSheetController/Images.xcassets/PreviewSupplementaryView-Checkmark.imageset/PreviewSupplementaryView-Checkmark@3x.png b/ios/Pods/ImagePickerSheetController/ImagePickerSheetController/ImagePickerSheetController/Images.xcassets/PreviewSupplementaryView-Checkmark.imageset/PreviewSupplementaryView-Checkmark@3x.png new file mode 100644 index 0000000..99021d7 Binary files /dev/null and b/ios/Pods/ImagePickerSheetController/ImagePickerSheetController/ImagePickerSheetController/Images.xcassets/PreviewSupplementaryView-Checkmark.imageset/PreviewSupplementaryView-Checkmark@3x.png differ diff --git a/ios/Pods/ImagePickerSheetController/ImagePickerSheetController/ImagePickerSheetController/Sheet/Preview/PreviewCollectionView.swift b/ios/Pods/ImagePickerSheetController/ImagePickerSheetController/ImagePickerSheetController/Sheet/Preview/PreviewCollectionView.swift new file mode 100644 index 0000000..a862c32 --- /dev/null +++ b/ios/Pods/ImagePickerSheetController/ImagePickerSheetController/ImagePickerSheetController/Sheet/Preview/PreviewCollectionView.swift @@ -0,0 +1,56 @@ +// +// PreviewCollectionView.swift +// ImagePickerSheet +// +// Created by Laurin Brandner on 07/09/14. +// Copyright (c) 2014 Laurin Brandner. All rights reserved. +// + +import UIKit + +class PreviewCollectionView: UICollectionView { + + var bouncing: Bool { + return contentOffset.x < -contentInset.left || contentOffset.x + frame.width > contentSize.width + contentInset.right + } + + var imagePreviewLayout: PreviewCollectionViewLayout { + return collectionViewLayout as! PreviewCollectionViewLayout + } + + // MARK: - Initialization + + init() { + super.init(frame: CGRectZero, collectionViewLayout: PreviewCollectionViewLayout()) + + initialize() + } + + required init?(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + + initialize() + } + + private func initialize() { + panGestureRecognizer.addTarget(self, action: "handlePanGesture:") + } + + // MARK: - Panning + + @objc private func handlePanGesture(gestureRecognizer: UIPanGestureRecognizer) { + if gestureRecognizer.state == .Ended { + let translation = gestureRecognizer.translationInView(self) + if translation == CGPoint() { + if !bouncing { + let possibleIndexPath = indexPathForItemAtPoint(gestureRecognizer.locationInView(self)) + if let indexPath = possibleIndexPath { + selectItemAtIndexPath(indexPath, animated: false, scrollPosition: .None) + delegate?.collectionView?(self, didSelectItemAtIndexPath: indexPath) + } + } + } + } + } + +} diff --git a/ios/Pods/ImagePickerSheetController/ImagePickerSheetController/ImagePickerSheetController/Sheet/Preview/PreviewCollectionViewCell.swift b/ios/Pods/ImagePickerSheetController/ImagePickerSheetController/ImagePickerSheetController/Sheet/Preview/PreviewCollectionViewCell.swift new file mode 100644 index 0000000..0ed31e5 --- /dev/null +++ b/ios/Pods/ImagePickerSheetController/ImagePickerSheetController/ImagePickerSheetController/Sheet/Preview/PreviewCollectionViewCell.swift @@ -0,0 +1,75 @@ +// +// PreviewCollectionViewCell.swift +// ImagePickerSheet +// +// Created by Laurin Brandner on 06/09/14. +// Copyright (c) 2014 Laurin Brandner. All rights reserved. +// + +import UIKit + +class PreviewCollectionViewCell: UICollectionViewCell { + + let imageView: UIImageView = { + let imageView = UIImageView() + imageView.contentMode = .ScaleAspectFill + imageView.clipsToBounds = true + + return imageView + }() + + let videoIndicatorView: UIImageView = { + let imageView = UIImageView(image: videoImage) + imageView.hidden = true + + return imageView + }() + + private class var videoImage: UIImage? { + let bundle = NSBundle(forClass: ImagePickerSheetController.self) + let image = UIImage(named: "PreviewCollectionViewCell-video", inBundle: bundle, compatibleWithTraitCollection: nil) + + return image + } + + // MARK: - Initialization + + override init(frame: CGRect) { + super.init(frame: frame) + + initialize() + } + + required init?(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + + initialize() + } + + private func initialize() { + addSubview(imageView) + addSubview(videoIndicatorView) + } + + // MARK: - Other Methods + + override func prepareForReuse() { + super.prepareForReuse() + + imageView.image = nil + videoIndicatorView.hidden = true + } + + // MARK: - Layout + + override func layoutSubviews() { + super.layoutSubviews() + + imageView.frame = bounds + + let videoIndicatViewSize = videoIndicatorView.image?.size ?? CGSize() + let inset: CGFloat = 4 + let videoIndicatorViewOrigin = CGPoint(x: bounds.minX + inset, y: bounds.maxY - inset - videoIndicatViewSize.height) + videoIndicatorView.frame = CGRect(origin: videoIndicatorViewOrigin, size: videoIndicatViewSize) + } +} diff --git a/ios/Pods/ImagePickerSheetController/ImagePickerSheetController/ImagePickerSheetController/Sheet/Preview/PreviewCollectionViewLayout.swift b/ios/Pods/ImagePickerSheetController/ImagePickerSheetController/ImagePickerSheetController/Sheet/Preview/PreviewCollectionViewLayout.swift new file mode 100644 index 0000000..511405a --- /dev/null +++ b/ios/Pods/ImagePickerSheetController/ImagePickerSheetController/ImagePickerSheetController/Sheet/Preview/PreviewCollectionViewLayout.swift @@ -0,0 +1,156 @@ +// +// PreviewCollectionViewLayout.swift +// ImagePickerSheet +// +// Created by Laurin Brandner on 06/09/14. +// Copyright (c) 2014 Laurin Brandner. All rights reserved. +// + +import UIKit + +class PreviewCollectionViewLayout: UICollectionViewFlowLayout { + + var invalidationCenteredIndexPath: NSIndexPath? + + var showsSupplementaryViews: Bool = true { + didSet { + invalidateLayout() + } + } + + private var layoutAttributes = [UICollectionViewLayoutAttributes]() + private var contentSize = CGSizeZero + + // MARK: - Initialization + + override init() { + super.init() + + initialize() + } + + required init?(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + + initialize() + } + + private func initialize() { + scrollDirection = .Horizontal + } + + // MARK: - Layout + + override func prepareLayout() { + super.prepareLayout() + + layoutAttributes.removeAll(keepCapacity: false) + contentSize = CGSizeZero + + if let collectionView = collectionView, + dataSource = collectionView.dataSource, + delegate = collectionView.delegate as? UICollectionViewDelegateFlowLayout { + var origin = CGPoint(x: sectionInset.left, y: sectionInset.top) + let numberOfSections = dataSource.numberOfSectionsInCollectionView?(collectionView) ?? 0 + + for s in 0 ..< numberOfSections { + let indexPath = NSIndexPath(forItem: 0, inSection: s) + let size = delegate.collectionView?(collectionView, layout: self, sizeForItemAtIndexPath: indexPath) ?? CGSizeZero + + let attributes = UICollectionViewLayoutAttributes(forCellWithIndexPath: indexPath) + attributes.frame = CGRect(origin: origin, size: size) + attributes.zIndex = 0 + + layoutAttributes.append(attributes) + + origin.x = attributes.frame.maxX + sectionInset.right + } + + contentSize = CGSize(width: origin.x, height: collectionView.frame.height) + } + } + + override func shouldInvalidateLayoutForBoundsChange(newBounds: CGRect) -> Bool { + return true + } + + override func collectionViewContentSize() -> CGSize { + return contentSize + } + + override func targetContentOffsetForProposedContentOffset(proposedContentOffset: CGPoint) -> CGPoint { + var contentOffset = proposedContentOffset + if let indexPath = invalidationCenteredIndexPath { + if let collectionView = collectionView { + let frame = layoutAttributes[indexPath.section].frame + contentOffset.x = frame.midX - collectionView.frame.width / 2.0 + + contentOffset.x = max(contentOffset.x, -collectionView.contentInset.left) + contentOffset.x = min(contentOffset.x, collectionViewContentSize().width - collectionView.frame.width + collectionView.contentInset.right) + } + invalidationCenteredIndexPath = nil + } + + return super.targetContentOffsetForProposedContentOffset(contentOffset) + } + + override func layoutAttributesForElementsInRect(rect: CGRect) -> [UICollectionViewLayoutAttributes]? { + return layoutAttributes + .filter { CGRectIntersectsRect(rect, $0.frame) } + .reduce([UICollectionViewLayoutAttributes]()) { memo, attributes in + if let supplementaryAttributes = layoutAttributesForSupplementaryViewOfKind(UICollectionElementKindSectionHeader, atIndexPath: attributes.indexPath) { + return memo + [attributes, supplementaryAttributes] + } + return memo + } + } + + override func layoutAttributesForItemAtIndexPath(indexPath: NSIndexPath) -> UICollectionViewLayoutAttributes? { + return layoutAttributes[indexPath.section] + } + + override func layoutAttributesForSupplementaryViewOfKind(elementKind: String, atIndexPath indexPath: NSIndexPath) -> UICollectionViewLayoutAttributes? { + if let collectionView = collectionView, + delegate = collectionView.delegate as? UICollectionViewDelegateFlowLayout, + itemAttributes = layoutAttributesForItemAtIndexPath(indexPath) { + + let inset = collectionView.contentInset + let bounds = collectionView.bounds + let contentOffset: CGPoint = { + var contentOffset = collectionView.contentOffset + contentOffset.x += inset.left + contentOffset.y += inset.top + + return contentOffset + }() + let visibleSize: CGSize = { + var size = bounds.size + size.width -= (inset.left+inset.right) + + return size + }() + let visibleFrame = CGRect(origin: contentOffset, size: visibleSize) + + let size = delegate.collectionView?(collectionView, layout: self, referenceSizeForHeaderInSection: indexPath.section) ?? CGSizeZero + let originX = max(itemAttributes.frame.minX, min(itemAttributes.frame.maxX - size.width, visibleFrame.maxX - size.width)) + + let attributes = UICollectionViewLayoutAttributes(forSupplementaryViewOfKind: elementKind, withIndexPath: indexPath) + attributes.zIndex = 1 + attributes.hidden = !showsSupplementaryViews + attributes.frame = CGRect(origin: CGPoint(x: originX, y: itemAttributes.frame.minY), size: size) + + return attributes + } + + return nil + } + + override func initialLayoutAttributesForAppearingItemAtIndexPath(itemIndexPath: NSIndexPath) -> UICollectionViewLayoutAttributes? { + return layoutAttributesForItemAtIndexPath(itemIndexPath) + } + + override func finalLayoutAttributesForDisappearingItemAtIndexPath(itemIndexPath: NSIndexPath) -> UICollectionViewLayoutAttributes? { + return layoutAttributesForItemAtIndexPath(itemIndexPath) + } + +} diff --git a/ios/Pods/ImagePickerSheetController/ImagePickerSheetController/ImagePickerSheetController/Sheet/Preview/PreviewSupplementaryView.swift b/ios/Pods/ImagePickerSheetController/ImagePickerSheetController/ImagePickerSheetController/Sheet/Preview/PreviewSupplementaryView.swift new file mode 100644 index 0000000..b35fc1b --- /dev/null +++ b/ios/Pods/ImagePickerSheetController/ImagePickerSheetController/ImagePickerSheetController/Sheet/Preview/PreviewSupplementaryView.swift @@ -0,0 +1,92 @@ +// +// PreviewSupplementaryView.swift +// ImagePickerSheet +// +// Created by Laurin Brandner on 06/09/14. +// Copyright (c) 2014 Laurin Brandner. All rights reserved. +// + +import UIKit + +class PreviewSupplementaryView: UICollectionReusableView { + + private let button: UIButton = { + let button = UIButton() + button.tintColor = .whiteColor() + button.userInteractionEnabled = false + button.setImage(PreviewSupplementaryView.checkmarkImage, forState: .Normal) + button.setImage(PreviewSupplementaryView.selectedCheckmarkImage, forState: .Selected) + + return button + }() + + var buttonInset = UIEdgeInsetsZero + + var selected: Bool = false { + didSet { + button.selected = selected + reloadButtonBackgroundColor() + } + } + + class var checkmarkImage: UIImage? { + let bundle = NSBundle(forClass: ImagePickerSheetController.self) + let image = UIImage(named: "PreviewSupplementaryView-Checkmark", inBundle: bundle, compatibleWithTraitCollection: nil) + + return image?.imageWithRenderingMode(.AlwaysTemplate) + } + + class var selectedCheckmarkImage: UIImage? { + let bundle = NSBundle(forClass: ImagePickerSheetController.self) + let image = UIImage(named: "PreviewSupplementaryView-Checkmark-Selected", inBundle: bundle, compatibleWithTraitCollection: nil) + + return image?.imageWithRenderingMode(.AlwaysTemplate) + } + + // MARK: - Initialization + + override init(frame: CGRect) { + super.init(frame: frame) + + initialize() + } + + required init?(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + + initialize() + } + + private func initialize() { + addSubview(button) + } + + // MARK: - Other Methods + + override func prepareForReuse() { + super.prepareForReuse() + + selected = false + } + + override func tintColorDidChange() { + super.tintColorDidChange() + + reloadButtonBackgroundColor() + } + + private func reloadButtonBackgroundColor() { + button.backgroundColor = (selected) ? tintColor : nil + } + + // MARK: - Layout + + override func layoutSubviews() { + super.layoutSubviews() + + button.sizeToFit() + button.frame.origin = CGPointMake(buttonInset.left, CGRectGetHeight(bounds)-CGRectGetHeight(button.frame)-buttonInset.bottom) + button.layer.cornerRadius = CGRectGetHeight(button.frame) / 2.0 + } + +} diff --git a/ios/Pods/ImagePickerSheetController/ImagePickerSheetController/ImagePickerSheetController/Sheet/SheetActionCollectionViewCell.swift b/ios/Pods/ImagePickerSheetController/ImagePickerSheetController/ImagePickerSheetController/Sheet/SheetActionCollectionViewCell.swift new file mode 100644 index 0000000..c5feefc --- /dev/null +++ b/ios/Pods/ImagePickerSheetController/ImagePickerSheetController/ImagePickerSheetController/Sheet/SheetActionCollectionViewCell.swift @@ -0,0 +1,70 @@ +// +// SheetActionCollectionViewCell.swift +// ImagePickerSheetController +// +// Created by Laurin Brandner on 26/08/15. +// Copyright © 2015 Laurin Brandner. All rights reserved. +// + +import UIKit + +let KVOContext = UnsafeMutablePointer<()>() + +class SheetActionCollectionViewCell: SheetCollectionViewCell { + + lazy private(set) var textLabel: UILabel = { + let label = UILabel() + label.textColor = self.tintColor + label.textAlignment = .Center + + self.addSubview(label) + + return label + }() + + // MARK: - Initialization + + override init(frame: CGRect) { + super.init(frame: frame) + initialize() + } + + required init?(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + initialize() + } + + private func initialize() { + textLabel.addObserver(self, forKeyPath: "text", options: NSKeyValueObservingOptions(rawValue: 0), context: KVOContext) + } + + deinit { + textLabel.removeObserver(self, forKeyPath: "text") + } + + // MARK: - Accessibility + + override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer) { + guard context == KVOContext else { + super.observeValueForKeyPath(keyPath, ofObject: object, change: change, context: context) + return + } + + accessibilityLabel = textLabel.text + } + + // MARK: - + + override func tintColorDidChange() { + super.tintColorDidChange() + + textLabel.textColor = tintColor + } + + override func layoutSubviews() { + super.layoutSubviews() + + textLabel.frame = UIEdgeInsetsInsetRect(bounds, backgroundInsets) + } + +} diff --git a/ios/Pods/ImagePickerSheetController/ImagePickerSheetController/ImagePickerSheetController/Sheet/SheetCollectionViewCell.swift b/ios/Pods/ImagePickerSheetController/ImagePickerSheetController/ImagePickerSheetController/Sheet/SheetCollectionViewCell.swift new file mode 100644 index 0000000..a5eeacf --- /dev/null +++ b/ios/Pods/ImagePickerSheetController/ImagePickerSheetController/ImagePickerSheetController/Sheet/SheetCollectionViewCell.swift @@ -0,0 +1,173 @@ +// +// SheetCollectionViewCell.swift +// ImagePickerSheetController +// +// Created by Laurin Brandner on 24/08/15. +// Copyright © 2015 Laurin Brandner. All rights reserved. +// + +import UIKit + +enum RoundedCorner { + case All(CGFloat) + case Top(CGFloat) + case Bottom(CGFloat) + case None +} + +class SheetCollectionViewCell: UICollectionViewCell { + + var backgroundInsets = UIEdgeInsets() { + didSet { + reloadMask() + reloadSeparator() + setNeedsLayout() + } + } + + var roundedCorners = RoundedCorner.None { + didSet { + reloadMask() + } + } + + var separatorVisible = false { + didSet { + reloadSeparator() + } + } + + var separatorColor = UIColor.blackColor() { + didSet { + separatorView?.backgroundColor = separatorColor + } + } + + var separatorHeight: CGFloat = 1 { + didSet { + setNeedsLayout() + } + } + + private var separatorView: UIView? + + override var highlighted: Bool { + didSet { + reloadBackgroundColor() + } + } + + var highlightedBackgroundColor: UIColor = .clearColor() { + didSet { + reloadBackgroundColor() + } + } + + var normalBackgroundColor: UIColor = .clearColor() { + didSet { + reloadBackgroundColor() + } + } + + private var needsMasking: Bool { + guard backgroundInsets == UIEdgeInsets() else { + return true + } + + switch roundedCorners { + case .None: + return false + default: + return true + } + } + + // MARK: - Initialization + + override init(frame: CGRect) { + super.init(frame: frame) + initialize() + } + + required init?(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + initialize() + } + + private func initialize() { + layoutMargins = UIEdgeInsets() + } + + // MARK: - Layout + + override func layoutSubviews() { + super.layoutSubviews() + + reloadMask() + + separatorView?.frame = CGRect(x: bounds.minY, y: bounds.maxY - separatorHeight, width: bounds.width, height: separatorHeight) + } + + // MARK: - Mask + + private func reloadMask() { + if needsMasking && layer.mask == nil { + let maskLayer = CAShapeLayer() + maskLayer.frame = bounds + maskLayer.lineWidth = 0 + maskLayer.fillColor = UIColor.blackColor().CGColor + + layer.mask = maskLayer + } + + let layerMask = layer.mask as? CAShapeLayer + layerMask?.frame = bounds + layerMask?.path = maskPathWithRect(UIEdgeInsetsInsetRect(bounds, backgroundInsets), roundedCorner: roundedCorners) + } + + private func maskPathWithRect(rect: CGRect, roundedCorner: RoundedCorner) -> CGPathRef { + let radii: CGFloat + let corners: UIRectCorner + + switch roundedCorner { + case .All(let value): + corners = .AllCorners + radii = value + case .Top(let value): + corners = [.TopLeft, .TopRight] + radii = value + case .Bottom(let value): + corners = [.BottomLeft, .BottomRight] + radii = value + case .None: + return UIBezierPath(rect: rect).CGPath + } + + return UIBezierPath(roundedRect: rect, byRoundingCorners: corners, cornerRadii: CGSize(width: radii, height: radii)).CGPath + } + + // MARK: - Separator + + private func reloadSeparator() { + if separatorVisible && backgroundInsets.bottom < separatorHeight { + if separatorView == nil { + let view = UIView() + view.backgroundColor = separatorColor + + addSubview(view) + separatorView = view + } + } + else { + separatorView?.removeFromSuperview() + separatorView = nil + } + } + + // MARK - Background + + private func reloadBackgroundColor() { + backgroundColor = highlighted ? highlightedBackgroundColor : normalBackgroundColor + } + +} diff --git a/ios/Pods/ImagePickerSheetController/ImagePickerSheetController/ImagePickerSheetController/Sheet/SheetCollectionViewLayout.swift b/ios/Pods/ImagePickerSheetController/ImagePickerSheetController/ImagePickerSheetController/Sheet/SheetCollectionViewLayout.swift new file mode 100644 index 0000000..49b0041 --- /dev/null +++ b/ios/Pods/ImagePickerSheetController/ImagePickerSheetController/ImagePickerSheetController/Sheet/SheetCollectionViewLayout.swift @@ -0,0 +1,99 @@ +// +// SheetCollectionViewLayout.swift +// ImagePickerSheetController +// +// Created by Laurin Brandner on 26/08/15. +// Copyright © 2015 Laurin Brandner. All rights reserved. +// + +import UIKit + +class SheetCollectionViewLayout: UICollectionViewLayout { + + private var layoutAttributes = [[UICollectionViewLayoutAttributes]]() + private var invalidatedLayoutAttributes: [[UICollectionViewLayoutAttributes]]? + private var contentSize = CGSizeZero + + // MARK: - Layout + + override func prepareLayout() { + super.prepareLayout() + + layoutAttributes.removeAll(keepCapacity: false) + contentSize = CGSizeZero + + if let collectionView = collectionView, + dataSource = collectionView.dataSource, + delegate = collectionView.delegate as? UICollectionViewDelegateFlowLayout { + let sections = dataSource.numberOfSectionsInCollectionView?(collectionView) ?? 0 + var origin = CGPoint() + + for section in 0 ..< sections { + var sectionAttributes = [UICollectionViewLayoutAttributes]() + let items = dataSource.collectionView(collectionView, numberOfItemsInSection: section) + let indexPaths = (0 ..< items).map { NSIndexPath(forItem: $0, inSection: section) } + + for indexPath in indexPaths { + let size = delegate.collectionView?(collectionView, layout: self, sizeForItemAtIndexPath: indexPath) ?? CGSizeZero + + let attributes = UICollectionViewLayoutAttributes(forCellWithIndexPath: indexPath) + attributes.frame = CGRect(origin: origin, size: size) + + sectionAttributes.append(attributes) + origin.y = attributes.frame.maxY + } + + layoutAttributes.append(sectionAttributes) + } + + contentSize = CGSize(width: collectionView.frame.width, height: origin.y) + } + } + + override func shouldInvalidateLayoutForBoundsChange(newBounds: CGRect) -> Bool { + return true + } + + override func invalidateLayout() { + invalidatedLayoutAttributes = layoutAttributes + super.invalidateLayout() + } + + override func collectionViewContentSize() -> CGSize { + return contentSize + } + + override func layoutAttributesForElementsInRect(rect: CGRect) -> [UICollectionViewLayoutAttributes]? { + return layoutAttributes.reduce([], combine: +) + .filter { CGRectIntersectsRect(rect, $0.frame) } + } + + private func layoutAttributesForItemAtIndexPath(indexPath: NSIndexPath, allAttributes: [[UICollectionViewLayoutAttributes]]) -> UICollectionViewLayoutAttributes? { + guard allAttributes.count > indexPath.section && allAttributes[indexPath.section].count > indexPath.item else { + return nil + } + + return allAttributes[indexPath.section][indexPath.item] + } + + private func invalidatedLayoutAttributesForItemAtIndexPath(indexPath: NSIndexPath) -> UICollectionViewLayoutAttributes? { + guard let invalidatedLayoutAttributes = invalidatedLayoutAttributes else { + return nil + } + + return layoutAttributesForItemAtIndexPath(indexPath, allAttributes: invalidatedLayoutAttributes) + } + + override func layoutAttributesForItemAtIndexPath(indexPath: NSIndexPath) -> UICollectionViewLayoutAttributes? { + return layoutAttributesForItemAtIndexPath(indexPath, allAttributes: layoutAttributes) + } + + override func initialLayoutAttributesForAppearingItemAtIndexPath(itemIndexPath: NSIndexPath) -> UICollectionViewLayoutAttributes? { + return invalidatedLayoutAttributesForItemAtIndexPath(itemIndexPath) ?? layoutAttributesForItemAtIndexPath(itemIndexPath) + } + + override func finalLayoutAttributesForDisappearingItemAtIndexPath(itemIndexPath: NSIndexPath) -> UICollectionViewLayoutAttributes? { + return layoutAttributesForItemAtIndexPath(itemIndexPath) + } + +} diff --git a/ios/Pods/ImagePickerSheetController/ImagePickerSheetController/ImagePickerSheetController/Sheet/SheetController.swift b/ios/Pods/ImagePickerSheetController/ImagePickerSheetController/ImagePickerSheetController/Sheet/SheetController.swift new file mode 100644 index 0000000..044a8f5 --- /dev/null +++ b/ios/Pods/ImagePickerSheetController/ImagePickerSheetController/ImagePickerSheetController/Sheet/SheetController.swift @@ -0,0 +1,265 @@ +// +// SheetController.swift +// ImagePickerSheetController +// +// Created by Laurin Brandner on 27/08/15. +// Copyright © 2015 Laurin Brandner. All rights reserved. +// + +import UIKit + +private let defaultInset: CGFloat = 10 + +class SheetController: NSObject { + + private(set) lazy var sheetCollectionView: UICollectionView = { + let layout = SheetCollectionViewLayout() + let collectionView = UICollectionView(frame: CGRect(), collectionViewLayout: layout) + collectionView.dataSource = self + collectionView.delegate = self + collectionView.accessibilityIdentifier = "ImagePickerSheet" + collectionView.backgroundColor = .clearColor() + collectionView.alwaysBounceVertical = false + collectionView.registerClass(SheetPreviewCollectionViewCell.self, forCellWithReuseIdentifier: NSStringFromClass(SheetPreviewCollectionViewCell.self)) + collectionView.registerClass(SheetActionCollectionViewCell.self, forCellWithReuseIdentifier: NSStringFromClass(SheetActionCollectionViewCell.self)) + + return collectionView + }() + + var previewCollectionView: PreviewCollectionView + + private(set) var actions = [ImagePickerAction]() + + var actionHandlingCallback: (() -> ())? + + private(set) var previewHeight: CGFloat = 0 + var numberOfSelectedImages = 0 + + var preferredSheetHeight: CGFloat { + return allIndexPaths().map { self.sizeForSheetItemAtIndexPath($0).height } + .reduce(0, combine: +) + } + + var preferredSheetWidth: CGFloat { + guard #available(iOS 9, *) else { + return sheetCollectionView.bounds.width + } + return sheetCollectionView.bounds.width - 2 * defaultInset + } + + // MARK: - Initialization + + init(previewCollectionView: PreviewCollectionView) { + self.previewCollectionView = previewCollectionView + + super.init() + } + + // MARK: - Data Source + // These methods are necessary so that no call cycles happen when calculating some design attributes + + private func numberOfSections() -> Int { + return 2 + } + + private func numberOfItemsInSection(section: Int) -> Int { + if section == 0 { + return 1 + } + + return actions.count + } + + private func allIndexPaths() -> [NSIndexPath] { + let s = numberOfSections() + return (0 ..< s).map { (self.numberOfItemsInSection($0), $0) } + .flatMap { numberOfItems, section in + (0 ..< numberOfItems).map { NSIndexPath(forItem: $0, inSection: section) } + } + } + + private func sizeForSheetItemAtIndexPath(indexPath: NSIndexPath) -> CGSize { + let height: CGFloat = { + if indexPath.section == 0 { + return previewHeight + } + + let actionItemHeight: CGFloat + + if #available(iOS 9, *) { + actionItemHeight = 57 + } + else { + actionItemHeight = 50 + } + + let insets = attributesForItemAtIndexPath(indexPath).backgroundInsets + return actionItemHeight + insets.top + insets.bottom + }() + + return CGSize(width: sheetCollectionView.bounds.width, height: height) + } + + // MARK: - Design + + private func attributesForItemAtIndexPath(indexPath: NSIndexPath) -> (corners: RoundedCorner, backgroundInsets: UIEdgeInsets) { + guard #available(iOS 9, *) else { + return (.None, UIEdgeInsets()) + } + + let cornerRadius: CGFloat = 13 + let innerInset: CGFloat = 4 + var indexPaths = allIndexPaths() + + guard indexPaths.first != indexPath else { + return (.Top(cornerRadius), UIEdgeInsets(top: 0, left: defaultInset, bottom: 0, right: defaultInset)) + } + + let cancelIndexPath = actions.indexOf { $0.style == ImagePickerActionStyle.Cancel } + .map { NSIndexPath(forItem: $0, inSection: 1) } + + + if let cancelIndexPath = cancelIndexPath { + if cancelIndexPath == indexPath { + return (.All(cornerRadius), UIEdgeInsets(top: innerInset, left: defaultInset, bottom: defaultInset, right: defaultInset)) + } + + indexPaths.removeLast() + + if indexPath == indexPaths.last { + return (.Bottom(cornerRadius), UIEdgeInsets(top: 0, left: defaultInset, bottom: innerInset, right: defaultInset)) + } + } + else if indexPath == indexPaths.last { + return (.Bottom(cornerRadius), UIEdgeInsets(top: 0, left: defaultInset, bottom: defaultInset, right: defaultInset)) + } + + return (.None, UIEdgeInsets(top: 0, left: defaultInset, bottom: 0, right: defaultInset)) + } + + private func fontForAction(action: ImagePickerAction) -> UIFont { + guard #available(iOS 9, *), action.style == .Cancel else { + return UIFont.systemFontOfSize(21) + } + + return UIFont.boldSystemFontOfSize(21) + } + + // MARK: - Actions + + func reloadActionItems() { + sheetCollectionView.reloadSections(NSIndexSet(index: 1)) + } + + func addAction(action: ImagePickerAction) { + if action.style == .Cancel { + actions = actions.filter { $0.style != .Cancel } + } + + actions.append(action) + + if let index = actions.indexOf({ $0.style == .Cancel }) { + let cancelAction = actions.removeAtIndex(index) + actions.append(cancelAction) + } + + reloadActionItems() + } + + private func handleAction(action: ImagePickerAction) { + actionHandlingCallback?() + action.handle(numberOfSelectedImages) + } + + func handleCancelAction() { + let cancelAction = actions.filter { $0.style == ImagePickerActionStyle.Cancel } + .first + + if let cancelAction = cancelAction { + handleAction(cancelAction) + } + else { + actionHandlingCallback?() + } + } + + // MARK: - + + func setPreviewHeight(height: CGFloat, invalidateLayout: Bool) { + previewHeight = height + if invalidateLayout { + sheetCollectionView.collectionViewLayout.invalidateLayout() + } + } + +} + +extension SheetController: UICollectionViewDataSource { + + func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int { + return numberOfSections() + } + + func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { + return numberOfItemsInSection(section) + } + + func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell { + let cell: SheetCollectionViewCell + + if indexPath.section == 0 { + let previewCell = collectionView.dequeueReusableCellWithReuseIdentifier(NSStringFromClass(SheetPreviewCollectionViewCell.self), forIndexPath: indexPath) as! SheetPreviewCollectionViewCell + previewCell.collectionView = previewCollectionView + + cell = previewCell + } + else { + let action = actions[indexPath.item] + let actionCell = collectionView.dequeueReusableCellWithReuseIdentifier(NSStringFromClass(SheetActionCollectionViewCell.self), forIndexPath: indexPath) as! SheetActionCollectionViewCell + actionCell.textLabel.font = fontForAction(action) + actionCell.textLabel.text = numberOfSelectedImages > 0 ? action.secondaryTitle(numberOfSelectedImages) : action.title + + cell = actionCell + } + + cell.separatorVisible = (indexPath.section == 1) + + // iOS specific design + (cell.roundedCorners, cell.backgroundInsets) = attributesForItemAtIndexPath(indexPath) + if #available(iOS 9, *) { + cell.normalBackgroundColor = UIColor(white: 0.97, alpha: 1) + cell.highlightedBackgroundColor = UIColor(white: 0.92, alpha: 1) + cell.separatorColor = UIColor(white: 0.84, alpha: 1) + } + else { + cell.normalBackgroundColor = .whiteColor() + cell.highlightedBackgroundColor = UIColor(white: 0.85, alpha: 1) + cell.separatorColor = UIColor(white: 0.784, alpha: 1) + } + + return cell + } + +} + +extension SheetController: UICollectionViewDelegate { + + func collectionView(collectionView: UICollectionView, shouldHighlightItemAtIndexPath indexPath: NSIndexPath) -> Bool { + return indexPath.section != 0 + } + + func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) { + collectionView.deselectItemAtIndexPath(indexPath, animated: true) + + handleAction(actions[indexPath.item]) + } + +} + +extension SheetController: UICollectionViewDelegateFlowLayout { + + func collectionView(collectionView: UICollectionView, layout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize { + return sizeForSheetItemAtIndexPath(indexPath) + } + +} diff --git a/ios/Pods/ImagePickerSheetController/ImagePickerSheetController/ImagePickerSheetController/Sheet/SheetPreviewCollectionViewCell.swift b/ios/Pods/ImagePickerSheetController/ImagePickerSheetController/ImagePickerSheetController/Sheet/SheetPreviewCollectionViewCell.swift new file mode 100644 index 0000000..e097eb1 --- /dev/null +++ b/ios/Pods/ImagePickerSheetController/ImagePickerSheetController/ImagePickerSheetController/Sheet/SheetPreviewCollectionViewCell.swift @@ -0,0 +1,39 @@ +// +// SheetPreviewCollectionViewCell.swift +// ImagePickerSheetController +// +// Created by Laurin Brandner on 06/09/14. +// Copyright (c) 2014 Laurin Brandner. All rights reserved. +// + +import UIKit + +class SheetPreviewCollectionViewCell: SheetCollectionViewCell { + + var collectionView: PreviewCollectionView? { + willSet { + if let collectionView = collectionView { + collectionView.removeFromSuperview() + } + + if let collectionView = newValue { + addSubview(collectionView) + } + } + } + + // MARK: - Other Methods + + override func prepareForReuse() { + collectionView = nil + } + + // MARK: - Layout + + override func layoutSubviews() { + super.layoutSubviews() + + collectionView?.frame = UIEdgeInsetsInsetRect(bounds, backgroundInsets) + } + +} diff --git a/ios/Pods/ImagePickerSheetController/LICENSE b/ios/Pods/ImagePickerSheetController/LICENSE new file mode 100644 index 0000000..151fa72 --- /dev/null +++ b/ios/Pods/ImagePickerSheetController/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2014 Laurin Brandner + +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 +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/ios/Pods/ImagePickerSheetController/README.md b/ios/Pods/ImagePickerSheetController/README.md new file mode 100644 index 0000000..ffe0949 --- /dev/null +++ b/ios/Pods/ImagePickerSheetController/README.md @@ -0,0 +1,56 @@ +# ImagePickerSheetController + +[![Twitter: @larcus94](https://img.shields.io/badge/contact-@larcus94-blue.svg?style=flat)](https://twitter.com/larcus94) +[![License](http://img.shields.io/badge/license-MIT-green.svg?style=flat)](https://github.com/larcus94/ImagePickerSheetController/blob/master/LICENSE) +[![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage) + +## About +ImagePickerSheetController is a component that replicates the custom photo action sheet in iMessage. It's very similar to UIAlertController which makes its usage simple and concise. + +![Screenshot](https://raw.githubusercontent.com/larcus94/ImagePickerSheetController/master/Screenshots/GoT.gif) + +## Usage +`ImagePickerSheetController` is similar to `UIAlertController` in its usage. + +### Example + +```swift +let controller = ImagePickerSheetController(mediaType: .ImageAndVideo) +controller.addAction(ImagePickerAction(title: NSLocalizedString("Take Photo Or Video", comment: "Action Title"), secondaryTitle: NSLocalizedString("Add comment", comment: "Action Title"), handler: { _ in + presentImagePickerController(.Camera) +}, secondaryHandler: { _, numberOfPhotos in + println("Comment \(numberOfPhotos) photos") +})) +controller.addAction(ImagePickerAction(title: NSLocalizedString("Photo Library", comment: "Action Title"), secondaryTitle: { NSString.localizedStringWithFormat(NSLocalizedString("ImagePickerSheet.button1.Send %lu Photo", comment: "Action Title"), $0) as String}, handler: { _ in + presentImagePickerController(.PhotoLibrary) +}, secondaryHandler: { _, numberOfPhotos in + println("Send \(controller.selectedImageAssets)") +})) +controller.addAction(ImagePickerAction(title: NSLocalizedString("Cancel", comment: "Action Title"), style: .Cancel, handler: { _ in + println("Cancelled") +})) + +presentViewController(controller, animated: true, completion: nil) +``` +It's recommended to use [stringsdict](https://developer.apple.com/library/ios/documentation/MacOSX/Conceptual/BPInternational/StringsdictFileFormat/StringsdictFileFormat.html) to easily translate plural forms in any language. + +## Installation + +### CocoaPods +```ruby +pod "ImagePickerSheetController", "~> 0.9.1" +``` + +###Carthage +```objc +github "larcus94/ImagePickerSheetController" ~> 0.9.1 +``` + +## Requirements +ImagePickerSheetController is written in Swift and links against `Photos.framework`. It therefore requires iOS 8 or later. + +## Author +I'm Laurin Brandner, I'm on [Twitter](https://twitter.com/larcus94). + +## License +ImagePickerSheetController is licensed under the [MIT License](http://opensource.org/licenses/mit-license.php). diff --git a/ios/Pods/Manifest.lock b/ios/Pods/Manifest.lock new file mode 100644 index 0000000..e6e876b --- /dev/null +++ b/ios/Pods/Manifest.lock @@ -0,0 +1,10 @@ +PODS: + - ImagePickerSheetController (0.9.1) + +DEPENDENCIES: + - ImagePickerSheetController + +SPEC CHECKSUMS: + ImagePickerSheetController: 3c58c9fee6dcf36485222358a021f6b734f997ba + +COCOAPODS: 0.39.0 diff --git a/ios/Pods/Pods.xcodeproj/project.pbxproj b/ios/Pods/Pods.xcodeproj/project.pbxproj new file mode 100644 index 0000000..aee5f3c --- /dev/null +++ b/ios/Pods/Pods.xcodeproj/project.pbxproj @@ -0,0 +1,573 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 079630E2D4FDD18DA1148E24A6D9F48C /* ImagePickerAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9DBA2152DC4141AF0EE54E2DB10210B5 /* ImagePickerAction.swift */; }; + 180378212E28F7A112A87A43DF6E5F7F /* PreviewCollectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B67719E721B448F6065B50621081684A /* PreviewCollectionView.swift */; }; + 3343C7EF8FC7413A0A907F6FC5C78C74 /* SheetController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A35A3834BF674B5F1CDB72D9D646658 /* SheetController.swift */; }; + 363134533B7518E26FEB125E29D3BDF5 /* PreviewCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75CE6E7CD62AF49861EC3F12442386C0 /* PreviewCollectionViewCell.swift */; }; + 37A5494E25A4BEB49274FD8644A6D194 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9E36762FF8E4A4E113EEC970F71E699C /* Foundation.framework */; }; + 3BEBBF1BC29E28E275612602AD2CBC58 /* Pods-ReactNativeCameraKit-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 0F3AC07D2E4446CA38B0AFB55935D506 /* Pods-ReactNativeCameraKit-dummy.m */; }; + 5A97CB0EA725BF0EA48A2B3CBF199887 /* ImagePickerSheetController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C525DEF5158DF542A9FAB0874C83A06E /* ImagePickerSheetController.swift */; }; + 5D0DE2F60AE2806F484AC6D0F53362A5 /* AnimationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A2D98780222413EDBBD45C7302EC0BA8 /* AnimationController.swift */; }; + 65DDC4906B56C3C19A03B2EB4257435F /* ImagePickerSheetController-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = 3134E79C0CA7BE51D6DD42575AC4BD78 /* ImagePickerSheetController-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 6700755A206C8136A97B20B9D2FA788C /* Photos.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 697E2FB9C7768EDEA1457A96EDB78BE9 /* Photos.framework */; }; + 6FFF9F6BAB7E459AFFBE5C6B4343372C /* SheetActionCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFFC468480F371982DE65A908A41DA21 /* SheetActionCollectionViewCell.swift */; }; + 884AE123CAC9A5491C23AE729FE4832D /* SheetCollectionViewLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = E06F339EAACD2E9ED6A6119E816DC3AA /* SheetCollectionViewLayout.swift */; }; + 9180B8BA812802D78F860175B02387FF /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = F2C06E2463508844773E3E096A35A47C /* Images.xcassets */; }; + B8912CE08C66BD2B6189745EDB35F33F /* PreviewCollectionViewLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C00EDF48AC63BAA768D0A0B6E20C31B /* PreviewCollectionViewLayout.swift */; }; + CD78C10DADDEC6B5E39D47DFE8975B48 /* Pods-ReactNativeCameraKit-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = 66B38237FA9EF751ED77E239C733829D /* Pods-ReactNativeCameraKit-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D1A2E5C864D0CB49A2E760B345A9852F /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9E36762FF8E4A4E113EEC970F71E699C /* Foundation.framework */; }; + E7B7BAB2FE1730965D067CE994FB7EC2 /* ImagePickerSheetController-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = FD0EAA78B4A44CC82E24ED80A813BFDB /* ImagePickerSheetController-dummy.m */; }; + E8129D7EC7434F22247C35916CBAD0B8 /* PreviewSupplementaryView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C844465AE2EA77CFF17AA3699FFB79CD /* PreviewSupplementaryView.swift */; }; + EE75E9914DE58A76A5460938813EE4DC /* SheetCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 990E4D7FD59799C10E85A6487106B18B /* SheetCollectionViewCell.swift */; }; + F2E2DE1EC6D5DA0477EA29AF543017A2 /* SheetPreviewCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EBE83F6A85A4DEAE74B5AD71A974CAE /* SheetPreviewCollectionViewCell.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + DDFBF28D1A8D92742997C008E7B80ED5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = D41D8CD98F00B204E9800998ECF8427E /* Project object */; + proxyType = 1; + remoteGlobalIDString = 2AAAB9973850C35994DC04473435E1A3; + remoteInfo = ImagePickerSheetController; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXFileReference section */ + 03E2CDD46BB9E1A4A66D0550179FDC2C /* Pods-ReactNativeCameraKit-acknowledgements.markdown */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; path = "Pods-ReactNativeCameraKit-acknowledgements.markdown"; sourceTree = ""; }; + 0F3AC07D2E4446CA38B0AFB55935D506 /* Pods-ReactNativeCameraKit-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "Pods-ReactNativeCameraKit-dummy.m"; sourceTree = ""; }; + 12CE2841A34BEB5906032E3980F43037 /* ImagePickerSheetController-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "ImagePickerSheetController-prefix.pch"; sourceTree = ""; }; + 1E0275907FE8E85889145D3B97263935 /* ImagePickerSheetController.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = ImagePickerSheetController.xcconfig; sourceTree = ""; }; + 2C00EDF48AC63BAA768D0A0B6E20C31B /* PreviewCollectionViewLayout.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = PreviewCollectionViewLayout.swift; path = ImagePickerSheetController/ImagePickerSheetController/Sheet/Preview/PreviewCollectionViewLayout.swift; sourceTree = ""; }; + 3134E79C0CA7BE51D6DD42575AC4BD78 /* ImagePickerSheetController-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "ImagePickerSheetController-umbrella.h"; sourceTree = ""; }; + 3CF582E27F74A69C6F871ED64816F6DE /* Pods-ReactNativeCameraKit.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-ReactNativeCameraKit.release.xcconfig"; sourceTree = ""; }; + 4A35A3834BF674B5F1CDB72D9D646658 /* SheetController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SheetController.swift; path = ImagePickerSheetController/ImagePickerSheetController/Sheet/SheetController.swift; sourceTree = ""; }; + 4EBE83F6A85A4DEAE74B5AD71A974CAE /* SheetPreviewCollectionViewCell.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SheetPreviewCollectionViewCell.swift; path = ImagePickerSheetController/ImagePickerSheetController/Sheet/SheetPreviewCollectionViewCell.swift; sourceTree = ""; }; + 66B38237FA9EF751ED77E239C733829D /* Pods-ReactNativeCameraKit-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "Pods-ReactNativeCameraKit-umbrella.h"; sourceTree = ""; }; + 68DF5BE345BF4A20C242226D8BDFC520 /* Pods-ReactNativeCameraKit-frameworks.sh */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.script.sh; path = "Pods-ReactNativeCameraKit-frameworks.sh"; sourceTree = ""; }; + 697E2FB9C7768EDEA1457A96EDB78BE9 /* Photos.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Photos.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS9.0.sdk/System/Library/Frameworks/Photos.framework; sourceTree = DEVELOPER_DIR; }; + 75CE6E7CD62AF49861EC3F12442386C0 /* PreviewCollectionViewCell.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = PreviewCollectionViewCell.swift; path = ImagePickerSheetController/ImagePickerSheetController/Sheet/Preview/PreviewCollectionViewCell.swift; sourceTree = ""; }; + 7AA7C40F5CD7AC6BF35E1B0065DA72C5 /* Pods-ReactNativeCameraKit.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = "sourcecode.module-map"; path = "Pods-ReactNativeCameraKit.modulemap"; sourceTree = ""; }; + 9480CFCA0F9FB4526A047ED920A554BC /* Pods-ReactNativeCameraKit-acknowledgements.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Pods-ReactNativeCameraKit-acknowledgements.plist"; sourceTree = ""; }; + 990E4D7FD59799C10E85A6487106B18B /* SheetCollectionViewCell.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SheetCollectionViewCell.swift; path = ImagePickerSheetController/ImagePickerSheetController/Sheet/SheetCollectionViewCell.swift; sourceTree = ""; }; + 9DBA2152DC4141AF0EE54E2DB10210B5 /* ImagePickerAction.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ImagePickerAction.swift; path = ImagePickerSheetController/ImagePickerSheetController/ImagePickerAction.swift; sourceTree = ""; }; + 9E36762FF8E4A4E113EEC970F71E699C /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS9.0.sdk/System/Library/Frameworks/Foundation.framework; sourceTree = DEVELOPER_DIR; }; + A2D98780222413EDBBD45C7302EC0BA8 /* AnimationController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = AnimationController.swift; path = ImagePickerSheetController/ImagePickerSheetController/AnimationController.swift; sourceTree = ""; }; + AE1EF0EC94DA87361C0406DA6AC248C3 /* ImagePickerSheetController.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = ImagePickerSheetController.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + B67719E721B448F6065B50621081684A /* PreviewCollectionView.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = PreviewCollectionView.swift; path = ImagePickerSheetController/ImagePickerSheetController/Sheet/Preview/PreviewCollectionView.swift; sourceTree = ""; }; + BA6428E9F66FD5A23C0A2E06ED26CD2F /* Podfile */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; name = Podfile; path = ../Podfile; sourceTree = SOURCE_ROOT; xcLanguageSpecificationIdentifier = xcode.lang.ruby; }; + BA9C090317F3F76F40B0CACF691929EE /* Pods-ReactNativeCameraKit-resources.sh */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.script.sh; path = "Pods-ReactNativeCameraKit-resources.sh"; sourceTree = ""; }; + C525DEF5158DF542A9FAB0874C83A06E /* ImagePickerSheetController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ImagePickerSheetController.swift; path = ImagePickerSheetController/ImagePickerSheetController/ImagePickerSheetController.swift; sourceTree = ""; }; + C844465AE2EA77CFF17AA3699FFB79CD /* PreviewSupplementaryView.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = PreviewSupplementaryView.swift; path = ImagePickerSheetController/ImagePickerSheetController/Sheet/Preview/PreviewSupplementaryView.swift; sourceTree = ""; }; + CAE48460691A7F16DC3E2A8158DA8C1C /* Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + CD097932506E41F66E1BB103B2080A8D /* Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + CDDDD47987996CE6E4F88ACE58031BA9 /* ImagePickerSheetController.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = "sourcecode.module-map"; path = ImagePickerSheetController.modulemap; sourceTree = ""; }; + E06F339EAACD2E9ED6A6119E816DC3AA /* SheetCollectionViewLayout.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SheetCollectionViewLayout.swift; path = ImagePickerSheetController/ImagePickerSheetController/Sheet/SheetCollectionViewLayout.swift; sourceTree = ""; }; + EEF467F3FE90185318D7CC581BB160FA /* Pods-ReactNativeCameraKit.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-ReactNativeCameraKit.debug.xcconfig"; sourceTree = ""; }; + F2C06E2463508844773E3E096A35A47C /* Images.xcassets */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = ImagePickerSheetController/ImagePickerSheetController/Images.xcassets; sourceTree = ""; }; + F831E4A5EFAFD16B864480C9C0F8E1E9 /* Pods_ReactNativeCameraKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_ReactNativeCameraKit.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + FD0EAA78B4A44CC82E24ED80A813BFDB /* ImagePickerSheetController-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "ImagePickerSheetController-dummy.m"; sourceTree = ""; }; + FFFC468480F371982DE65A908A41DA21 /* SheetActionCollectionViewCell.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SheetActionCollectionViewCell.swift; path = ImagePickerSheetController/ImagePickerSheetController/Sheet/SheetActionCollectionViewCell.swift; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 185CDE137F7E9E23F1CE9B518D47E7FB /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + D1A2E5C864D0CB49A2E760B345A9852F /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + B00AEE85F1051CEEC27A8D13F638E23C /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 37A5494E25A4BEB49274FD8644A6D194 /* Foundation.framework in Frameworks */, + 6700755A206C8136A97B20B9D2FA788C /* Photos.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 433CD3331B6C3787F473C941B61FC68F /* Frameworks */ = { + isa = PBXGroup; + children = ( + CF60819FDD9A8A1FDDBE8C01CFDB526F /* iOS */, + ); + name = Frameworks; + sourceTree = ""; + }; + 755C1EE9F7841B918D05512036D6F60D /* Targets Support Files */ = { + isa = PBXGroup; + children = ( + CB688DDE44D693E9312BCCFEF49508F5 /* Pods-ReactNativeCameraKit */, + ); + name = "Targets Support Files"; + sourceTree = ""; + }; + 7DB346D0F39D3F0E887471402A8071AB = { + isa = PBXGroup; + children = ( + BA6428E9F66FD5A23C0A2E06ED26CD2F /* Podfile */, + 433CD3331B6C3787F473C941B61FC68F /* Frameworks */, + EF0BF5064E61294AD74BCC8C19C17E70 /* Pods */, + AF7A76083693DFBE6F6696812B7370A6 /* Products */, + 755C1EE9F7841B918D05512036D6F60D /* Targets Support Files */, + ); + sourceTree = ""; + }; + 9531269308E2BE6B671DDE9564BFE996 /* Resources */ = { + isa = PBXGroup; + children = ( + F2C06E2463508844773E3E096A35A47C /* Images.xcassets */, + ); + name = Resources; + sourceTree = ""; + }; + AF7A76083693DFBE6F6696812B7370A6 /* Products */ = { + isa = PBXGroup; + children = ( + AE1EF0EC94DA87361C0406DA6AC248C3 /* ImagePickerSheetController.framework */, + F831E4A5EFAFD16B864480C9C0F8E1E9 /* Pods_ReactNativeCameraKit.framework */, + ); + name = Products; + sourceTree = ""; + }; + CB688DDE44D693E9312BCCFEF49508F5 /* Pods-ReactNativeCameraKit */ = { + isa = PBXGroup; + children = ( + CD097932506E41F66E1BB103B2080A8D /* Info.plist */, + 7AA7C40F5CD7AC6BF35E1B0065DA72C5 /* Pods-ReactNativeCameraKit.modulemap */, + 03E2CDD46BB9E1A4A66D0550179FDC2C /* Pods-ReactNativeCameraKit-acknowledgements.markdown */, + 9480CFCA0F9FB4526A047ED920A554BC /* Pods-ReactNativeCameraKit-acknowledgements.plist */, + 0F3AC07D2E4446CA38B0AFB55935D506 /* Pods-ReactNativeCameraKit-dummy.m */, + 68DF5BE345BF4A20C242226D8BDFC520 /* Pods-ReactNativeCameraKit-frameworks.sh */, + BA9C090317F3F76F40B0CACF691929EE /* Pods-ReactNativeCameraKit-resources.sh */, + 66B38237FA9EF751ED77E239C733829D /* Pods-ReactNativeCameraKit-umbrella.h */, + EEF467F3FE90185318D7CC581BB160FA /* Pods-ReactNativeCameraKit.debug.xcconfig */, + 3CF582E27F74A69C6F871ED64816F6DE /* Pods-ReactNativeCameraKit.release.xcconfig */, + ); + name = "Pods-ReactNativeCameraKit"; + path = "Target Support Files/Pods-ReactNativeCameraKit"; + sourceTree = ""; + }; + CF60819FDD9A8A1FDDBE8C01CFDB526F /* iOS */ = { + isa = PBXGroup; + children = ( + 9E36762FF8E4A4E113EEC970F71E699C /* Foundation.framework */, + 697E2FB9C7768EDEA1457A96EDB78BE9 /* Photos.framework */, + ); + name = iOS; + sourceTree = ""; + }; + D50700D5541FD756EDCE4782B04829C5 /* ImagePickerSheetController */ = { + isa = PBXGroup; + children = ( + A2D98780222413EDBBD45C7302EC0BA8 /* AnimationController.swift */, + 9DBA2152DC4141AF0EE54E2DB10210B5 /* ImagePickerAction.swift */, + C525DEF5158DF542A9FAB0874C83A06E /* ImagePickerSheetController.swift */, + B67719E721B448F6065B50621081684A /* PreviewCollectionView.swift */, + 75CE6E7CD62AF49861EC3F12442386C0 /* PreviewCollectionViewCell.swift */, + 2C00EDF48AC63BAA768D0A0B6E20C31B /* PreviewCollectionViewLayout.swift */, + C844465AE2EA77CFF17AA3699FFB79CD /* PreviewSupplementaryView.swift */, + FFFC468480F371982DE65A908A41DA21 /* SheetActionCollectionViewCell.swift */, + 990E4D7FD59799C10E85A6487106B18B /* SheetCollectionViewCell.swift */, + E06F339EAACD2E9ED6A6119E816DC3AA /* SheetCollectionViewLayout.swift */, + 4A35A3834BF674B5F1CDB72D9D646658 /* SheetController.swift */, + 4EBE83F6A85A4DEAE74B5AD71A974CAE /* SheetPreviewCollectionViewCell.swift */, + 9531269308E2BE6B671DDE9564BFE996 /* Resources */, + F45EBA593415998AE41C5B6B2974419A /* Support Files */, + ); + path = ImagePickerSheetController; + sourceTree = ""; + }; + EF0BF5064E61294AD74BCC8C19C17E70 /* Pods */ = { + isa = PBXGroup; + children = ( + D50700D5541FD756EDCE4782B04829C5 /* ImagePickerSheetController */, + ); + name = Pods; + sourceTree = ""; + }; + F45EBA593415998AE41C5B6B2974419A /* Support Files */ = { + isa = PBXGroup; + children = ( + CDDDD47987996CE6E4F88ACE58031BA9 /* ImagePickerSheetController.modulemap */, + 1E0275907FE8E85889145D3B97263935 /* ImagePickerSheetController.xcconfig */, + FD0EAA78B4A44CC82E24ED80A813BFDB /* ImagePickerSheetController-dummy.m */, + 12CE2841A34BEB5906032E3980F43037 /* ImagePickerSheetController-prefix.pch */, + 3134E79C0CA7BE51D6DD42575AC4BD78 /* ImagePickerSheetController-umbrella.h */, + CAE48460691A7F16DC3E2A8158DA8C1C /* Info.plist */, + ); + name = "Support Files"; + path = "../Target Support Files/ImagePickerSheetController"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXHeadersBuildPhase section */ + 5E0B6160A5A178C00ED9CD79C7BC1CD4 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 65DDC4906B56C3C19A03B2EB4257435F /* ImagePickerSheetController-umbrella.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 9C4B1C2AFE3CA38462A9D283ED2D3A28 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + CD78C10DADDEC6B5E39D47DFE8975B48 /* Pods-ReactNativeCameraKit-umbrella.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + +/* Begin PBXNativeTarget section */ + 09C554F08A60A36AC2B390B2B0F706AF /* Pods-ReactNativeCameraKit */ = { + isa = PBXNativeTarget; + buildConfigurationList = E15230A1C51A9843BED269A28D1C8D93 /* Build configuration list for PBXNativeTarget "Pods-ReactNativeCameraKit" */; + buildPhases = ( + DF3887247B7FA5F2B9570A1532E8825A /* Sources */, + 185CDE137F7E9E23F1CE9B518D47E7FB /* Frameworks */, + 9C4B1C2AFE3CA38462A9D283ED2D3A28 /* Headers */, + ); + buildRules = ( + ); + dependencies = ( + BBCF5D5AD9006C324C0CCA9B69B2FA27 /* PBXTargetDependency */, + ); + name = "Pods-ReactNativeCameraKit"; + productName = "Pods-ReactNativeCameraKit"; + productReference = F831E4A5EFAFD16B864480C9C0F8E1E9 /* Pods_ReactNativeCameraKit.framework */; + productType = "com.apple.product-type.framework"; + }; + 2AAAB9973850C35994DC04473435E1A3 /* ImagePickerSheetController */ = { + isa = PBXNativeTarget; + buildConfigurationList = 5580ECE611FF697E03DD45816B0B5871 /* Build configuration list for PBXNativeTarget "ImagePickerSheetController" */; + buildPhases = ( + D6EFA694F15215890B83641196A85498 /* Sources */, + B00AEE85F1051CEEC27A8D13F638E23C /* Frameworks */, + 407B72996CFC6B907B5482F8FFBB4443 /* Resources */, + 5E0B6160A5A178C00ED9CD79C7BC1CD4 /* Headers */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = ImagePickerSheetController; + productName = ImagePickerSheetController; + productReference = AE1EF0EC94DA87361C0406DA6AC248C3 /* ImagePickerSheetController.framework */; + productType = "com.apple.product-type.framework"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + D41D8CD98F00B204E9800998ECF8427E /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 0700; + LastUpgradeCheck = 0700; + }; + buildConfigurationList = 2D8E8EC45A3A1A1D94AE762CB5028504 /* Build configuration list for PBXProject "Pods" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + ); + mainGroup = 7DB346D0F39D3F0E887471402A8071AB; + productRefGroup = AF7A76083693DFBE6F6696812B7370A6 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 2AAAB9973850C35994DC04473435E1A3 /* ImagePickerSheetController */, + 09C554F08A60A36AC2B390B2B0F706AF /* Pods-ReactNativeCameraKit */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 407B72996CFC6B907B5482F8FFBB4443 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 9180B8BA812802D78F860175B02387FF /* Images.xcassets in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + D6EFA694F15215890B83641196A85498 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5D0DE2F60AE2806F484AC6D0F53362A5 /* AnimationController.swift in Sources */, + 079630E2D4FDD18DA1148E24A6D9F48C /* ImagePickerAction.swift in Sources */, + E7B7BAB2FE1730965D067CE994FB7EC2 /* ImagePickerSheetController-dummy.m in Sources */, + 5A97CB0EA725BF0EA48A2B3CBF199887 /* ImagePickerSheetController.swift in Sources */, + 180378212E28F7A112A87A43DF6E5F7F /* PreviewCollectionView.swift in Sources */, + 363134533B7518E26FEB125E29D3BDF5 /* PreviewCollectionViewCell.swift in Sources */, + B8912CE08C66BD2B6189745EDB35F33F /* PreviewCollectionViewLayout.swift in Sources */, + E8129D7EC7434F22247C35916CBAD0B8 /* PreviewSupplementaryView.swift in Sources */, + 6FFF9F6BAB7E459AFFBE5C6B4343372C /* SheetActionCollectionViewCell.swift in Sources */, + EE75E9914DE58A76A5460938813EE4DC /* SheetCollectionViewCell.swift in Sources */, + 884AE123CAC9A5491C23AE729FE4832D /* SheetCollectionViewLayout.swift in Sources */, + 3343C7EF8FC7413A0A907F6FC5C78C74 /* SheetController.swift in Sources */, + F2E2DE1EC6D5DA0477EA29AF543017A2 /* SheetPreviewCollectionViewCell.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + DF3887247B7FA5F2B9570A1532E8825A /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 3BEBBF1BC29E28E275612602AD2CBC58 /* Pods-ReactNativeCameraKit-dummy.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + BBCF5D5AD9006C324C0CCA9B69B2FA27 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = ImagePickerSheetController; + target = 2AAAB9973850C35994DC04473435E1A3 /* ImagePickerSheetController */; + targetProxy = DDFBF28D1A8D92742997C008E7B80ED5 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin XCBuildConfiguration section */ + 8861DB452DF06013FA92AD2062B9FB19 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 3CF582E27F74A69C6F871ED64816F6DE /* Pods-ReactNativeCameraKit.release.xcconfig */; + buildSettings = { + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + INFOPLIST_FILE = "Target Support Files/Pods-ReactNativeCameraKit/Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MACH_O_TYPE = staticlib; + MODULEMAP_FILE = "Target Support Files/Pods-ReactNativeCameraKit/Pods-ReactNativeCameraKit.modulemap"; + MTL_ENABLE_DEBUG_INFO = NO; + OTHER_LDFLAGS = ""; + OTHER_LIBTOOLFLAGS = ""; + PODS_ROOT = "$(SRCROOT)"; + PRODUCT_NAME = Pods_ReactNativeCameraKit; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; + 94547D0F14ABE31A6C5C38D3A12D793D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 1E0275907FE8E85889145D3B97263935 /* ImagePickerSheetController.xcconfig */; + buildSettings = { + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_PREFIX_HEADER = "Target Support Files/ImagePickerSheetController/ImagePickerSheetController-prefix.pch"; + INFOPLIST_FILE = "Target Support Files/ImagePickerSheetController/Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MODULEMAP_FILE = "Target Support Files/ImagePickerSheetController/ImagePickerSheetController.modulemap"; + MTL_ENABLE_DEBUG_INFO = NO; + PRODUCT_NAME = ImagePickerSheetController; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; + A70CDAD61F90AC503C7D04CC22DA2923 /* 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; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + 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; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + ONLY_ACTIVE_ARCH = YES; + STRIP_INSTALLED_PRODUCT = NO; + SYMROOT = "${SRCROOT}/../build"; + }; + name = Debug; + }; + CA05C723B40F3F3B1C4184E935ED6B83 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 1E0275907FE8E85889145D3B97263935 /* ImagePickerSheetController.xcconfig */; + buildSettings = { + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_PREFIX_HEADER = "Target Support Files/ImagePickerSheetController/ImagePickerSheetController-prefix.pch"; + INFOPLIST_FILE = "Target Support Files/ImagePickerSheetController/Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MODULEMAP_FILE = "Target Support Files/ImagePickerSheetController/ImagePickerSheetController.modulemap"; + MTL_ENABLE_DEBUG_INFO = YES; + PRODUCT_NAME = ImagePickerSheetController; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + F21EF67338BE2D05560FDBD505F6847C /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = EEF467F3FE90185318D7CC581BB160FA /* Pods-ReactNativeCameraKit.debug.xcconfig */; + buildSettings = { + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + INFOPLIST_FILE = "Target Support Files/Pods-ReactNativeCameraKit/Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MACH_O_TYPE = staticlib; + MODULEMAP_FILE = "Target Support Files/Pods-ReactNativeCameraKit/Pods-ReactNativeCameraKit.modulemap"; + MTL_ENABLE_DEBUG_INFO = YES; + OTHER_LDFLAGS = ""; + OTHER_LIBTOOLFLAGS = ""; + PODS_ROOT = "$(SRCROOT)"; + PRODUCT_NAME = Pods_ReactNativeCameraKit; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + FB45FFD90572718D82AB9092B750F0CA /* 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; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = YES; + ENABLE_NS_ASSERTIONS = NO; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_PREPROCESSOR_DEFINITIONS = "RELEASE=1"; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + STRIP_INSTALLED_PRODUCT = NO; + SYMROOT = "${SRCROOT}/../build"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 2D8E8EC45A3A1A1D94AE762CB5028504 /* Build configuration list for PBXProject "Pods" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + A70CDAD61F90AC503C7D04CC22DA2923 /* Debug */, + FB45FFD90572718D82AB9092B750F0CA /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 5580ECE611FF697E03DD45816B0B5871 /* Build configuration list for PBXNativeTarget "ImagePickerSheetController" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + CA05C723B40F3F3B1C4184E935ED6B83 /* Debug */, + 94547D0F14ABE31A6C5C38D3A12D793D /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + E15230A1C51A9843BED269A28D1C8D93 /* Build configuration list for PBXNativeTarget "Pods-ReactNativeCameraKit" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + F21EF67338BE2D05560FDBD505F6847C /* Debug */, + 8861DB452DF06013FA92AD2062B9FB19 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = D41D8CD98F00B204E9800998ECF8427E /* Project object */; +} diff --git a/ios/Pods/Target Support Files/ImagePickerSheetController/ImagePickerSheetController-dummy.m b/ios/Pods/Target Support Files/ImagePickerSheetController/ImagePickerSheetController-dummy.m new file mode 100644 index 0000000..aa038f5 --- /dev/null +++ b/ios/Pods/Target Support Files/ImagePickerSheetController/ImagePickerSheetController-dummy.m @@ -0,0 +1,5 @@ +#import +@interface PodsDummy_ImagePickerSheetController : NSObject +@end +@implementation PodsDummy_ImagePickerSheetController +@end diff --git a/ios/Pods/Target Support Files/ImagePickerSheetController/ImagePickerSheetController-prefix.pch b/ios/Pods/Target Support Files/ImagePickerSheetController/ImagePickerSheetController-prefix.pch new file mode 100644 index 0000000..aa992a4 --- /dev/null +++ b/ios/Pods/Target Support Files/ImagePickerSheetController/ImagePickerSheetController-prefix.pch @@ -0,0 +1,4 @@ +#ifdef __OBJC__ +#import +#endif + diff --git a/ios/Pods/Target Support Files/ImagePickerSheetController/ImagePickerSheetController-umbrella.h b/ios/Pods/Target Support Files/ImagePickerSheetController/ImagePickerSheetController-umbrella.h new file mode 100644 index 0000000..b198a65 --- /dev/null +++ b/ios/Pods/Target Support Files/ImagePickerSheetController/ImagePickerSheetController-umbrella.h @@ -0,0 +1,6 @@ +#import + + +FOUNDATION_EXPORT double ImagePickerSheetControllerVersionNumber; +FOUNDATION_EXPORT const unsigned char ImagePickerSheetControllerVersionString[]; + diff --git a/ios/Pods/Target Support Files/ImagePickerSheetController/ImagePickerSheetController.modulemap b/ios/Pods/Target Support Files/ImagePickerSheetController/ImagePickerSheetController.modulemap new file mode 100644 index 0000000..09a9b1b --- /dev/null +++ b/ios/Pods/Target Support Files/ImagePickerSheetController/ImagePickerSheetController.modulemap @@ -0,0 +1,6 @@ +framework module ImagePickerSheetController { + umbrella header "ImagePickerSheetController-umbrella.h" + + export * + module * { export * } +} diff --git a/ios/Pods/Target Support Files/ImagePickerSheetController/ImagePickerSheetController.xcconfig b/ios/Pods/Target Support Files/ImagePickerSheetController/ImagePickerSheetController.xcconfig new file mode 100644 index 0000000..6b6267e --- /dev/null +++ b/ios/Pods/Target Support Files/ImagePickerSheetController/ImagePickerSheetController.xcconfig @@ -0,0 +1,6 @@ +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Private/ImagePickerSheetController" "${PODS_ROOT}/Headers/Public" +OTHER_LDFLAGS = -framework "Photos" +OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS" +PODS_ROOT = ${SRCROOT} +SKIP_INSTALL = YES \ No newline at end of file diff --git a/ios/Pods/Target Support Files/ImagePickerSheetController/Info.plist b/ios/Pods/Target Support Files/ImagePickerSheetController/Info.plist new file mode 100644 index 0000000..8dd5fc5 --- /dev/null +++ b/ios/Pods/Target Support Files/ImagePickerSheetController/Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + org.cocoapods.${PRODUCT_NAME:rfc1034identifier} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + FMWK + CFBundleShortVersionString + 0.9.1 + CFBundleSignature + ???? + CFBundleVersion + ${CURRENT_PROJECT_VERSION} + NSPrincipalClass + + + diff --git a/ios/Pods/Target Support Files/Pods-ReactNativeCameraKit/Info.plist b/ios/Pods/Target Support Files/Pods-ReactNativeCameraKit/Info.plist new file mode 100644 index 0000000..6974542 --- /dev/null +++ b/ios/Pods/Target Support Files/Pods-ReactNativeCameraKit/Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + org.cocoapods.${PRODUCT_NAME:rfc1034identifier} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0.0 + CFBundleSignature + ???? + CFBundleVersion + ${CURRENT_PROJECT_VERSION} + NSPrincipalClass + + + diff --git a/ios/Pods/Target Support Files/Pods-ReactNativeCameraKit/Pods-ReactNativeCameraKit-acknowledgements.markdown b/ios/Pods/Target Support Files/Pods-ReactNativeCameraKit/Pods-ReactNativeCameraKit-acknowledgements.markdown new file mode 100644 index 0000000..b0c35a0 --- /dev/null +++ b/ios/Pods/Target Support Files/Pods-ReactNativeCameraKit/Pods-ReactNativeCameraKit-acknowledgements.markdown @@ -0,0 +1,28 @@ +# Acknowledgements +This application makes use of the following third party libraries: + +## ImagePickerSheetController + +The MIT License (MIT) + +Copyright (c) 2014 Laurin Brandner + +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 +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +Generated by CocoaPods - http://cocoapods.org diff --git a/ios/Pods/Target Support Files/Pods-ReactNativeCameraKit/Pods-ReactNativeCameraKit-acknowledgements.plist b/ios/Pods/Target Support Files/Pods-ReactNativeCameraKit/Pods-ReactNativeCameraKit-acknowledgements.plist new file mode 100644 index 0000000..54d0a87 --- /dev/null +++ b/ios/Pods/Target Support Files/Pods-ReactNativeCameraKit/Pods-ReactNativeCameraKit-acknowledgements.plist @@ -0,0 +1,58 @@ + + + + + PreferenceSpecifiers + + + FooterText + This application makes use of the following third party libraries: + Title + Acknowledgements + Type + PSGroupSpecifier + + + FooterText + The MIT License (MIT) + +Copyright (c) 2014 Laurin Brandner + +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 +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + Title + ImagePickerSheetController + Type + PSGroupSpecifier + + + FooterText + Generated by CocoaPods - http://cocoapods.org + Title + + Type + PSGroupSpecifier + + + StringsTable + Acknowledgements + Title + Acknowledgements + + diff --git a/ios/Pods/Target Support Files/Pods-ReactNativeCameraKit/Pods-ReactNativeCameraKit-dummy.m b/ios/Pods/Target Support Files/Pods-ReactNativeCameraKit/Pods-ReactNativeCameraKit-dummy.m new file mode 100644 index 0000000..7031172 --- /dev/null +++ b/ios/Pods/Target Support Files/Pods-ReactNativeCameraKit/Pods-ReactNativeCameraKit-dummy.m @@ -0,0 +1,5 @@ +#import +@interface PodsDummy_Pods_ReactNativeCameraKit : NSObject +@end +@implementation PodsDummy_Pods_ReactNativeCameraKit +@end diff --git a/ios/Pods/Target Support Files/Pods-ReactNativeCameraKit/Pods-ReactNativeCameraKit-frameworks.sh b/ios/Pods/Target Support Files/Pods-ReactNativeCameraKit/Pods-ReactNativeCameraKit-frameworks.sh new file mode 100755 index 0000000..8132e7e --- /dev/null +++ b/ios/Pods/Target Support Files/Pods-ReactNativeCameraKit/Pods-ReactNativeCameraKit-frameworks.sh @@ -0,0 +1,91 @@ +#!/bin/sh +set -e + +echo "mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" +mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" + +SWIFT_STDLIB_PATH="${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" + +install_framework() +{ + if [ -r "${BUILT_PRODUCTS_DIR}/$1" ]; then + local source="${BUILT_PRODUCTS_DIR}/$1" + elif [ -r "${BUILT_PRODUCTS_DIR}/$(basename "$1")" ]; then + local source="${BUILT_PRODUCTS_DIR}/$(basename "$1")" + elif [ -r "$1" ]; then + local source="$1" + fi + + local destination="${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" + + if [ -L "${source}" ]; then + echo "Symlinked..." + source="$(readlink "${source}")" + fi + + # use filter instead of exclude so missing patterns dont' throw errors + echo "rsync -av --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${destination}\"" + rsync -av --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${destination}" + + local basename + basename="$(basename -s .framework "$1")" + binary="${destination}/${basename}.framework/${basename}" + if ! [ -r "$binary" ]; then + binary="${destination}/${basename}" + fi + + # Strip invalid architectures so "fat" simulator / device frameworks work on device + if [[ "$(file "$binary")" == *"dynamically linked shared library"* ]]; then + strip_invalid_archs "$binary" + fi + + # Resign the code if required by the build settings to avoid unstable apps + code_sign_if_enabled "${destination}/$(basename "$1")" + + # Embed linked Swift runtime libraries. No longer necessary as of Xcode 7. + if [ "${XCODE_VERSION_MAJOR}" -lt 7 ]; then + local swift_runtime_libs + swift_runtime_libs=$(xcrun otool -LX "$binary" | grep --color=never @rpath/libswift | sed -E s/@rpath\\/\(.+dylib\).*/\\1/g | uniq -u && exit ${PIPESTATUS[0]}) + for lib in $swift_runtime_libs; do + echo "rsync -auv \"${SWIFT_STDLIB_PATH}/${lib}\" \"${destination}\"" + rsync -auv "${SWIFT_STDLIB_PATH}/${lib}" "${destination}" + code_sign_if_enabled "${destination}/${lib}" + done + fi +} + +# Signs a framework with the provided identity +code_sign_if_enabled() { + if [ -n "${EXPANDED_CODE_SIGN_IDENTITY}" -a "${CODE_SIGNING_REQUIRED}" != "NO" -a "${CODE_SIGNING_ALLOWED}" != "NO" ]; then + # Use the current code_sign_identitiy + echo "Code Signing $1 with Identity ${EXPANDED_CODE_SIGN_IDENTITY_NAME}" + echo "/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} --preserve-metadata=identifier,entitlements \"$1\"" + /usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} --preserve-metadata=identifier,entitlements "$1" + fi +} + +# Strip invalid architectures +strip_invalid_archs() { + binary="$1" + # Get architectures for current file + archs="$(lipo -info "$binary" | rev | cut -d ':' -f1 | rev)" + stripped="" + for arch in $archs; do + if ! [[ "${VALID_ARCHS}" == *"$arch"* ]]; then + # Strip non-valid architectures in-place + lipo -remove "$arch" -output "$binary" "$binary" || exit 1 + stripped="$stripped $arch" + fi + done + if [[ "$stripped" ]]; then + echo "Stripped $binary of architectures:$stripped" + fi +} + + +if [[ "$CONFIGURATION" == "Debug" ]]; then + install_framework "Pods-ReactNativeCameraKit/ImagePickerSheetController.framework" +fi +if [[ "$CONFIGURATION" == "Release" ]]; then + install_framework "Pods-ReactNativeCameraKit/ImagePickerSheetController.framework" +fi diff --git a/ios/Pods/Target Support Files/Pods-ReactNativeCameraKit/Pods-ReactNativeCameraKit-resources.sh b/ios/Pods/Target Support Files/Pods-ReactNativeCameraKit/Pods-ReactNativeCameraKit-resources.sh new file mode 100755 index 0000000..16774fb --- /dev/null +++ b/ios/Pods/Target Support Files/Pods-ReactNativeCameraKit/Pods-ReactNativeCameraKit-resources.sh @@ -0,0 +1,95 @@ +#!/bin/sh +set -e + +mkdir -p "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" + +RESOURCES_TO_COPY=${PODS_ROOT}/resources-to-copy-${TARGETNAME}.txt +> "$RESOURCES_TO_COPY" + +XCASSET_FILES=() + +realpath() { + DIRECTORY="$(cd "${1%/*}" && pwd)" + FILENAME="${1##*/}" + echo "$DIRECTORY/$FILENAME" +} + +install_resource() +{ + case $1 in + *.storyboard) + echo "ibtool --reference-external-strings-file --errors --warnings --notices --output-format human-readable-text --compile ${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$1\" .storyboard`.storyboardc ${PODS_ROOT}/$1 --sdk ${SDKROOT}" + ibtool --reference-external-strings-file --errors --warnings --notices --output-format human-readable-text --compile "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$1\" .storyboard`.storyboardc" "${PODS_ROOT}/$1" --sdk "${SDKROOT}" + ;; + *.xib) + echo "ibtool --reference-external-strings-file --errors --warnings --notices --output-format human-readable-text --compile ${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$1\" .xib`.nib ${PODS_ROOT}/$1 --sdk ${SDKROOT}" + ibtool --reference-external-strings-file --errors --warnings --notices --output-format human-readable-text --compile "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$1\" .xib`.nib" "${PODS_ROOT}/$1" --sdk "${SDKROOT}" + ;; + *.framework) + echo "mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" + mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" + echo "rsync -av ${PODS_ROOT}/$1 ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" + rsync -av "${PODS_ROOT}/$1" "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" + ;; + *.xcdatamodel) + echo "xcrun momc \"${PODS_ROOT}/$1\" \"${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1"`.mom\"" + xcrun momc "${PODS_ROOT}/$1" "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1" .xcdatamodel`.mom" + ;; + *.xcdatamodeld) + echo "xcrun momc \"${PODS_ROOT}/$1\" \"${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1" .xcdatamodeld`.momd\"" + xcrun momc "${PODS_ROOT}/$1" "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1" .xcdatamodeld`.momd" + ;; + *.xcmappingmodel) + echo "xcrun mapc \"${PODS_ROOT}/$1\" \"${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1" .xcmappingmodel`.cdm\"" + xcrun mapc "${PODS_ROOT}/$1" "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1" .xcmappingmodel`.cdm" + ;; + *.xcassets) + ABSOLUTE_XCASSET_FILE=$(realpath "${PODS_ROOT}/$1") + XCASSET_FILES+=("$ABSOLUTE_XCASSET_FILE") + ;; + /*) + echo "$1" + echo "$1" >> "$RESOURCES_TO_COPY" + ;; + *) + echo "${PODS_ROOT}/$1" + echo "${PODS_ROOT}/$1" >> "$RESOURCES_TO_COPY" + ;; + esac +} + +mkdir -p "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" +rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" +if [[ "${ACTION}" == "install" ]] && [[ "${SKIP_INSTALL}" == "NO" ]]; then + mkdir -p "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" + rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" +fi +rm -f "$RESOURCES_TO_COPY" + +if [[ -n "${WRAPPER_EXTENSION}" ]] && [ "`xcrun --find actool`" ] && [ -n "$XCASSET_FILES" ] +then + case "${TARGETED_DEVICE_FAMILY}" in + 1,2) + TARGET_DEVICE_ARGS="--target-device ipad --target-device iphone" + ;; + 1) + TARGET_DEVICE_ARGS="--target-device iphone" + ;; + 2) + TARGET_DEVICE_ARGS="--target-device ipad" + ;; + *) + TARGET_DEVICE_ARGS="--target-device mac" + ;; + esac + + # Find all other xcassets (this unfortunately includes those of path pods and other targets). + OTHER_XCASSETS=$(find "$PWD" -iname "*.xcassets" -type d) + while read line; do + if [[ $line != "`realpath $PODS_ROOT`*" ]]; then + XCASSET_FILES+=("$line") + fi + done <<<"$OTHER_XCASSETS" + + printf "%s\0" "${XCASSET_FILES[@]}" | xargs -0 xcrun actool --output-format human-readable-text --notices --warnings --platform "${PLATFORM_NAME}" --minimum-deployment-target "${IPHONEOS_DEPLOYMENT_TARGET}" ${TARGET_DEVICE_ARGS} --compress-pngs --compile "${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" +fi diff --git a/ios/Pods/Target Support Files/Pods-ReactNativeCameraKit/Pods-ReactNativeCameraKit-umbrella.h b/ios/Pods/Target Support Files/Pods-ReactNativeCameraKit/Pods-ReactNativeCameraKit-umbrella.h new file mode 100644 index 0000000..384665a --- /dev/null +++ b/ios/Pods/Target Support Files/Pods-ReactNativeCameraKit/Pods-ReactNativeCameraKit-umbrella.h @@ -0,0 +1,6 @@ +#import + + +FOUNDATION_EXPORT double Pods_ReactNativeCameraKitVersionNumber; +FOUNDATION_EXPORT const unsigned char Pods_ReactNativeCameraKitVersionString[]; + diff --git a/ios/Pods/Target Support Files/Pods-ReactNativeCameraKit/Pods-ReactNativeCameraKit.debug.xcconfig b/ios/Pods/Target Support Files/Pods-ReactNativeCameraKit/Pods-ReactNativeCameraKit.debug.xcconfig new file mode 100644 index 0000000..95e505c --- /dev/null +++ b/ios/Pods/Target Support Files/Pods-ReactNativeCameraKit/Pods-ReactNativeCameraKit.debug.xcconfig @@ -0,0 +1,8 @@ +EMBEDDED_CONTENT_CONTAINS_SWIFT = YES +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' +OTHER_CFLAGS = $(inherited) -iquote "$CONFIGURATION_BUILD_DIR/ImagePickerSheetController.framework/Headers" +OTHER_LDFLAGS = $(inherited) -framework "ImagePickerSheetController" +OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS" +PODS_FRAMEWORK_BUILD_PATH = $(BUILD_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)/Pods-ReactNativeCameraKit +PODS_ROOT = ${SRCROOT}/Pods \ No newline at end of file diff --git a/ios/Pods/Target Support Files/Pods-ReactNativeCameraKit/Pods-ReactNativeCameraKit.modulemap b/ios/Pods/Target Support Files/Pods-ReactNativeCameraKit/Pods-ReactNativeCameraKit.modulemap new file mode 100644 index 0000000..097554e --- /dev/null +++ b/ios/Pods/Target Support Files/Pods-ReactNativeCameraKit/Pods-ReactNativeCameraKit.modulemap @@ -0,0 +1,6 @@ +framework module Pods_ReactNativeCameraKit { + umbrella header "Pods-ReactNativeCameraKit-umbrella.h" + + export * + module * { export * } +} diff --git a/ios/Pods/Target Support Files/Pods-ReactNativeCameraKit/Pods-ReactNativeCameraKit.release.xcconfig b/ios/Pods/Target Support Files/Pods-ReactNativeCameraKit/Pods-ReactNativeCameraKit.release.xcconfig new file mode 100644 index 0000000..95e505c --- /dev/null +++ b/ios/Pods/Target Support Files/Pods-ReactNativeCameraKit/Pods-ReactNativeCameraKit.release.xcconfig @@ -0,0 +1,8 @@ +EMBEDDED_CONTENT_CONTAINS_SWIFT = YES +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' +OTHER_CFLAGS = $(inherited) -iquote "$CONFIGURATION_BUILD_DIR/ImagePickerSheetController.framework/Headers" +OTHER_LDFLAGS = $(inherited) -framework "ImagePickerSheetController" +OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS" +PODS_FRAMEWORK_BUILD_PATH = $(BUILD_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)/Pods-ReactNativeCameraKit +PODS_ROOT = ${SRCROOT}/Pods \ No newline at end of file diff --git a/ios/ReactNativeCameraKit-Bridging-Header.h b/ios/ReactNativeCameraKit-Bridging-Header.h new file mode 100644 index 0000000..4f813e3 --- /dev/null +++ b/ios/ReactNativeCameraKit-Bridging-Header.h @@ -0,0 +1,4 @@ +#import "RCTBridgeModule.h" +#import "AppDelegate.h" + + diff --git a/ios/ReactNativeCameraKit.m b/ios/ReactNativeCameraKit.m new file mode 100644 index 0000000..5f2d737 --- /dev/null +++ b/ios/ReactNativeCameraKit.m @@ -0,0 +1,16 @@ +// +// RCTCameraKitManager.m +// ReactNativeCameraKit +// +// Created by Natalia Grankina on 4/13/16. +// Copyright © 2016 Facebook. All rights reserved. +// + +#import "RCTBridgeModule.h" +#import "AppDelegate.h" + +@interface RCT_EXTERN_MODULE(ReactNativeCameraKit, NSObject) + +RCT_EXTERN_METHOD(presentPhotoPicker:(NSDictionary *)options callback:(RCTResponseSenderBlock)callback) + +@end diff --git a/ios/ReactNativeCameraKit.swift b/ios/ReactNativeCameraKit.swift new file mode 100644 index 0000000..54fd139 --- /dev/null +++ b/ios/ReactNativeCameraKit.swift @@ -0,0 +1,170 @@ +// +// RCTCameraKitManager.swift +// ReactNativeCameraKit +// +// Created by Natalia Grankina on 4/13/16. +// Copyright © 2016 Facebook. All rights reserved. +// + +import UIKit +import MobileCoreServices +import Photos +import ImagePickerSheetController + +@objc(ReactNativeCameraKit) + +class ReactNativeCameraKit: NSObject, UIImagePickerControllerDelegate, UINavigationControllerDelegate, CameraViewControllerDelegate { + var defaultOptions: [String: AnyObject] + var callback: RCTResponseSenderBlock? = nil + + override init() { + defaultOptions = [String: AnyObject]() + defaultOptions["takePhotoActionTitle"] = "Take a Photo" + defaultOptions["pickPhotoActionTitle"] = "Gallery" + defaultOptions["cancelActionTitle"] = "Cancel" + defaultOptions["sendSelectedPhotosTitle"] = "Send %lu Photo" + defaultOptions["aspectRatioInfoMessage"] = "Your images look best with 16:9 ratio" + defaultOptions["aspectRatios"] = ["16:9", "1:1", "4:3", "3:2", "2:3", "3:4", "9:16"] + defaultOptions["collectionName"] = "eCom" + + super.init() + } + + + func presentPhotoPicker(options: [String: AnyObject], callback: RCTResponseSenderBlock) -> Void { + var computedOptions = [String: AnyObject]() + self.callback = callback + + for (key, value) in defaultOptions { + computedOptions[key] = value + } + for (key, value) in options { + computedOptions[key] = value; + } + + dispatch_async(dispatch_get_main_queue(), { + let controller = ImagePickerSheetController(mediaType: .Image) + + let takePhotoAction = ImagePickerAction( + title: computedOptions["takePhotoActionTitle"] as! String, + handler: { _ in + self.launchCamera(["aspectRatioInfoMessage": computedOptions["aspectRatioInfoMessage"]!, "aspectRatios": computedOptions["aspectRatios"]!, "collectionName": computedOptions["collectionName"]!]) + } + ) + controller.addAction(takePhotoAction) + + let pickPhotoAction = ImagePickerAction( + title: computedOptions["pickPhotoActionTitle"] as! String, + secondaryTitle: { NSString.localizedStringWithFormat(computedOptions["sendSelectedPhotosTitle"] as! String, $0) as String}, + handler: { _ in + self.presentImagePickerController(.PhotoLibrary) + }, + secondaryHandler: { _, numberOfPhotos in + var selectedImages = [String]() + for imageAsset in controller.selectedImageAssets { + PHImageManager.defaultManager().requestImageDataForAsset(imageAsset, + options: PHImageRequestOptions(), + resultHandler: { (imageData, _, orientation, info) -> Void in + selectedImages.append(imageData!.base64EncodedStringWithOptions([])) + if (selectedImages.count == controller.selectedImageAssets.count) { + self.executeCallback(["images": selectedImages]) + } + }) + } + }) + controller.addAction(pickPhotoAction) + + let cancelAction = ImagePickerAction( + title: computedOptions["cancelActionTitle"] as! String, + style: .Cancel, + handler: { _ in + self.notifyAboutCancel() + } + ) + controller.addAction(cancelAction) + + self.presentViewControllerAnimated(controller) + }) + } + + private func presentImagePickerController(source: UIImagePickerControllerSourceType) { + dispatch_async(dispatch_get_main_queue(), { + let controller = UIImagePickerController() + controller.delegate = self + var sourceType = source + if (!UIImagePickerController.isSourceTypeAvailable(sourceType)) { + sourceType = .PhotoLibrary + } + controller.sourceType = sourceType + + controller.delegate = self + self.presentViewControllerAnimated(controller) + }) + } + + private func presentViewControllerAnimated(controller: UIViewController) { + let delegate = UIApplication.sharedApplication().delegate as? AppDelegate + delegate!.window.rootViewController!.presentViewController(controller, animated: true, completion: nil) + } + + private func hideViewControler() { + let delegate = UIApplication.sharedApplication().delegate as? AppDelegate + delegate!.window.rootViewController!.dismissViewControllerAnimated(true, completion: nil) + } + + private func executeCallback(result: [String: AnyObject]) { + if (callback != nil) { + callback!([result]) + callback = nil + } + } + + private func notifyAboutCancel() { + executeCallback(["didCancel": true]) + } + + private func launchCamera(cameraOptions: [String: AnyObject]) { + dispatch_async(dispatch_get_main_queue(), { + let cameraViewController = CameraViewController(cameraOptions: cameraOptions) + cameraViewController.cameraViewControllerDelegate = self + + let delegate = UIApplication.sharedApplication().delegate as? AppDelegate + delegate!.window.rootViewController!.presentViewController(cameraViewController, animated: true, completion: nil) + }) + } + + // UIImagePickerControllerDelegate + + func imagePickerControllerDidCancel(picker: UIImagePickerController) { + notifyAboutCancel() + hideViewControler() + } + + func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]) { + let mediaType = info[UIImagePickerControllerMediaType] as! NSString + if !mediaType.isEqualToString(kUTTypeImage as String) { + fatalError("Video is not supported") + } else { + let image = info[UIImagePickerControllerOriginalImage] as! UIImage + let imageData = UIImageJPEGRepresentation(image, 1.0)!.base64EncodedStringWithOptions([]) + executeCallback(["images": [imageData]]) + } + hideViewControler() + } + + // CameraViewControllerDelegate + + func imageHasBeenTaken(controller: CameraViewController, imageData: String) { + executeCallback(["images": [imageData]]) + hideViewControler() + } + + func cameraViewControllerDidCancel(controller: CameraViewController) { + hideViewControler() + } + + func onError(controller: CameraViewController, error: String) { + executeCallback(["error": [error]]) + hideViewControler() + } +} diff --git a/ios/ReactNativeCameraKit.xcodeproj/project.pbxproj b/ios/ReactNativeCameraKit.xcodeproj/project.pbxproj new file mode 100644 index 0000000..e8a2364 --- /dev/null +++ b/ios/ReactNativeCameraKit.xcodeproj/project.pbxproj @@ -0,0 +1,901 @@ +// !$*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 */; }; + 00E356F31AD99517003FC87E /* ReactNativeCameraKitTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 00E356F21AD99517003FC87E /* ReactNativeCameraKitTests.m */; }; + 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 */; }; + 832341BD1AAA6AB300B99B32 /* libRCTText.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 832341B51AAA6A8300B99B32 /* libRCTText.a */; }; + 8F0E60179CBB773063C32C2F /* Pods_ReactNativeCameraKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CD2DB716F7216B9BD5AF69BF /* Pods_ReactNativeCameraKit.framework */; }; + D1D310CF1CBE9FD9006019A8 /* ReactNativeCameraKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = D1D310CE1CBE9FD9006019A8 /* ReactNativeCameraKit.swift */; }; + D1D310DC1CBEA062006019A8 /* ReactNativeCameraKit.m in Sources */ = {isa = PBXBuildFile; fileRef = D1D310DB1CBEA062006019A8 /* ReactNativeCameraKit.m */; }; + D1D310DF1CBEA0D0006019A8 /* CropHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = D1D310DE1CBEA0D0006019A8 /* CropHelper.swift */; }; + D1D310E21CBEA15B006019A8 /* CameraSessionManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = D1D310E11CBEA15B006019A8 /* CameraSessionManager.swift */; }; + D1D310E41CBEA17D006019A8 /* CameraViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D1D310E31CBEA17D006019A8 /* CameraViewController.swift */; }; + D1D310E61CBEA1AA006019A8 /* CameraViewControllerDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D1D310E51CBEA1AA006019A8 /* CameraViewControllerDelegate.swift */; }; + D1D310E81CBEA1CE006019A8 /* PhotoViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D1D310E71CBEA1CE006019A8 /* PhotoViewController.swift */; }; + D1D310EA1CBEA1E6006019A8 /* PhotoViewControllerDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D1D310E91CBEA1E6006019A8 /* PhotoViewControllerDelegate.swift */; }; +/* 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; + }; + 00E356F41AD99517003FC87E /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 83CBB9F71A601CBA00E9B192 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 13B07F861A680F5B00A75B9A; + remoteInfo = ReactNativeCameraKit; + }; + 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; + }; + 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; + }; +/* 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 = ""; }; + 00E356EE1AD99517003FC87E /* ReactNativeCameraKitTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ReactNativeCameraKitTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 00E356F11AD99517003FC87E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 00E356F21AD99517003FC87E /* ReactNativeCameraKitTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ReactNativeCameraKitTests.m; 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 /* ReactNativeCameraKit.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ReactNativeCameraKit.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 13B07FAF1A68108700A75B9A /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = ReactNativeCameraKit/AppDelegate.h; sourceTree = ""; }; + 13B07FB01A68108700A75B9A /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AppDelegate.m; path = ReactNativeCameraKit/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 = ReactNativeCameraKit/Images.xcassets; sourceTree = ""; }; + 13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = ReactNativeCameraKit/Info.plist; sourceTree = ""; }; + 13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = ReactNativeCameraKit/main.m; sourceTree = ""; }; + 146833FF1AC3E56700842450 /* React.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = React.xcodeproj; path = "../node_modules/react-native/React/React.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 = ""; }; + A09C6955B84903CA14AEF620 /* Pods-ReactNativeCameraKit.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ReactNativeCameraKit.debug.xcconfig"; path = "Pods/Target Support Files/Pods-ReactNativeCameraKit/Pods-ReactNativeCameraKit.debug.xcconfig"; sourceTree = ""; }; + C70242A4D4BE4A42B79CB1E5 /* Pods-ReactNativeCameraKit.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ReactNativeCameraKit.release.xcconfig"; path = "Pods/Target Support Files/Pods-ReactNativeCameraKit/Pods-ReactNativeCameraKit.release.xcconfig"; sourceTree = ""; }; + CD2DB716F7216B9BD5AF69BF /* Pods_ReactNativeCameraKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_ReactNativeCameraKit.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + D1D310CD1CBE9FD9006019A8 /* ReactNativeCameraKit-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "ReactNativeCameraKit-Bridging-Header.h"; sourceTree = ""; }; + D1D310CE1CBE9FD9006019A8 /* ReactNativeCameraKit.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReactNativeCameraKit.swift; sourceTree = ""; }; + D1D310DB1CBEA062006019A8 /* ReactNativeCameraKit.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ReactNativeCameraKit.m; sourceTree = ""; }; + D1D310DE1CBEA0D0006019A8 /* CropHelper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CropHelper.swift; sourceTree = ""; }; + D1D310E11CBEA15B006019A8 /* CameraSessionManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CameraSessionManager.swift; sourceTree = ""; }; + D1D310E31CBEA17D006019A8 /* CameraViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CameraViewController.swift; sourceTree = ""; }; + D1D310E51CBEA1AA006019A8 /* CameraViewControllerDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CameraViewControllerDelegate.swift; sourceTree = ""; }; + D1D310E71CBEA1CE006019A8 /* PhotoViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PhotoViewController.swift; sourceTree = ""; }; + D1D310E91CBEA1E6006019A8 /* PhotoViewControllerDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PhotoViewControllerDelegate.swift; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 00E356EB1AD99517003FC87E /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 13B07F8C1A680F5B00A75B9A /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 146834051AC3E58100842450 /* libReact.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 */, + 8F0E60179CBB773063C32C2F /* Pods_ReactNativeCameraKit.framework 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 */, + ); + name = Products; + sourceTree = ""; + }; + 00C302D41ABCB9D200DB3ED1 /* Products */ = { + isa = PBXGroup; + children = ( + 00C302DC1ABCB9D200DB3ED1 /* libRCTNetwork.a */, + ); + name = Products; + sourceTree = ""; + }; + 00C302E01ABCB9EE00DB3ED1 /* Products */ = { + isa = PBXGroup; + children = ( + 00C302E41ABCB9EE00DB3ED1 /* libRCTVibration.a */, + ); + name = Products; + sourceTree = ""; + }; + 00E356EF1AD99517003FC87E /* ReactNativeCameraKitTests */ = { + isa = PBXGroup; + children = ( + 00E356F21AD99517003FC87E /* ReactNativeCameraKitTests.m */, + 00E356F01AD99517003FC87E /* Supporting Files */, + ); + path = ReactNativeCameraKitTests; + sourceTree = ""; + }; + 00E356F01AD99517003FC87E /* Supporting Files */ = { + isa = PBXGroup; + children = ( + 00E356F11AD99517003FC87E /* Info.plist */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; + 139105B71AF99BAD00B5F7CC /* Products */ = { + isa = PBXGroup; + children = ( + 139105C11AF99BAD00B5F7CC /* libRCTSettings.a */, + ); + name = Products; + sourceTree = ""; + }; + 139FDEE71B06529A00C62182 /* Products */ = { + isa = PBXGroup; + children = ( + 139FDEF41B06529B00C62182 /* libRCTWebSocket.a */, + ); + name = Products; + sourceTree = ""; + }; + 13B07FAE1A68108700A75B9A /* ReactNativeCameraKit */ = { + isa = PBXGroup; + children = ( + D1D310E01CBEA0F6006019A8 /* Camera */, + D1D310DD1CBEA0B4006019A8 /* Helpers */, + 008F07F21AC5B25A0029DE68 /* main.jsbundle */, + 13B07FAF1A68108700A75B9A /* AppDelegate.h */, + 13B07FB01A68108700A75B9A /* AppDelegate.m */, + 13B07FB51A68108700A75B9A /* Images.xcassets */, + 13B07FB61A68108700A75B9A /* Info.plist */, + 13B07FB11A68108700A75B9A /* LaunchScreen.xib */, + 13B07FB71A68108700A75B9A /* main.m */, + D1D310CE1CBE9FD9006019A8 /* ReactNativeCameraKit.swift */, + D1D310CD1CBE9FD9006019A8 /* ReactNativeCameraKit-Bridging-Header.h */, + D1D310DB1CBEA062006019A8 /* ReactNativeCameraKit.m */, + ); + name = ReactNativeCameraKit; + sourceTree = ""; + }; + 146834001AC3E56700842450 /* Products */ = { + isa = PBXGroup; + children = ( + 146834041AC3E56700842450 /* libReact.a */, + ); + name = Products; + sourceTree = ""; + }; + 660045470EB1C3A662DB6860 /* Frameworks */ = { + isa = PBXGroup; + children = ( + CD2DB716F7216B9BD5AF69BF /* Pods_ReactNativeCameraKit.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + 78C398B11ACF4ADC00677621 /* Products */ = { + isa = PBXGroup; + children = ( + 78C398B91ACF4ADC00677621 /* libRCTLinking.a */, + ); + name = Products; + sourceTree = ""; + }; + 832341AE1AAA6A7D00B99B32 /* Libraries */ = { + isa = PBXGroup; + children = ( + 146833FF1AC3E56700842450 /* React.xcodeproj */, + 00C302A71ABCB8CE00DB3ED1 /* RCTActionSheet.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 */, + ); + name = Products; + sourceTree = ""; + }; + 83CBB9F61A601CBA00E9B192 = { + isa = PBXGroup; + children = ( + 13B07FAE1A68108700A75B9A /* ReactNativeCameraKit */, + 832341AE1AAA6A7D00B99B32 /* Libraries */, + 00E356EF1AD99517003FC87E /* ReactNativeCameraKitTests */, + 83CBBA001A601CBA00E9B192 /* Products */, + A0D5301919F082B381AED4B2 /* Pods */, + 660045470EB1C3A662DB6860 /* Frameworks */, + ); + indentWidth = 2; + sourceTree = ""; + tabWidth = 2; + }; + 83CBBA001A601CBA00E9B192 /* Products */ = { + isa = PBXGroup; + children = ( + 13B07F961A680F5B00A75B9A /* ReactNativeCameraKit.app */, + 00E356EE1AD99517003FC87E /* ReactNativeCameraKitTests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + A0D5301919F082B381AED4B2 /* Pods */ = { + isa = PBXGroup; + children = ( + A09C6955B84903CA14AEF620 /* Pods-ReactNativeCameraKit.debug.xcconfig */, + C70242A4D4BE4A42B79CB1E5 /* Pods-ReactNativeCameraKit.release.xcconfig */, + ); + name = Pods; + sourceTree = ""; + }; + D1D310DD1CBEA0B4006019A8 /* Helpers */ = { + isa = PBXGroup; + children = ( + D1D310DE1CBEA0D0006019A8 /* CropHelper.swift */, + ); + name = Helpers; + sourceTree = ""; + }; + D1D310E01CBEA0F6006019A8 /* Camera */ = { + isa = PBXGroup; + children = ( + D1D310E11CBEA15B006019A8 /* CameraSessionManager.swift */, + D1D310E31CBEA17D006019A8 /* CameraViewController.swift */, + D1D310E51CBEA1AA006019A8 /* CameraViewControllerDelegate.swift */, + D1D310E71CBEA1CE006019A8 /* PhotoViewController.swift */, + D1D310E91CBEA1E6006019A8 /* PhotoViewControllerDelegate.swift */, + ); + name = Camera; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 00E356ED1AD99517003FC87E /* ReactNativeCameraKitTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 00E357021AD99517003FC87E /* Build configuration list for PBXNativeTarget "ReactNativeCameraKitTests" */; + buildPhases = ( + 00E356EA1AD99517003FC87E /* Sources */, + 00E356EB1AD99517003FC87E /* Frameworks */, + 00E356EC1AD99517003FC87E /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 00E356F51AD99517003FC87E /* PBXTargetDependency */, + ); + name = ReactNativeCameraKitTests; + productName = ReactNativeCameraKitTests; + productReference = 00E356EE1AD99517003FC87E /* ReactNativeCameraKitTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + 13B07F861A680F5B00A75B9A /* ReactNativeCameraKit */ = { + isa = PBXNativeTarget; + buildConfigurationList = 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "ReactNativeCameraKit" */; + buildPhases = ( + 75BD5BC400E0F0FFB5CA4C9D /* Check Pods Manifest.lock */, + 13B07F871A680F5B00A75B9A /* Sources */, + 13B07F8C1A680F5B00A75B9A /* Frameworks */, + 13B07F8E1A680F5B00A75B9A /* Resources */, + 00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */, + 298D3A2F8738131D7D6292FD /* Embed Pods Frameworks */, + C901BAD3B5898B500305AA85 /* Copy Pods Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = ReactNativeCameraKit; + productName = "Hello World"; + productReference = 13B07F961A680F5B00A75B9A /* ReactNativeCameraKit.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 83CBB9F71A601CBA00E9B192 /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 0720; + LastUpgradeCheck = 0610; + ORGANIZATIONNAME = Facebook; + TargetAttributes = { + 00E356ED1AD99517003FC87E = { + CreatedOnToolsVersion = 6.2; + TestTargetID = 13B07F861A680F5B00A75B9A; + }; + 13B07F861A680F5B00A75B9A = { + DevelopmentTeam = FALU6K28DC; + }; + }; + }; + buildConfigurationList = 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "ReactNativeCameraKit" */; + 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 = 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 */; + }, + ); + projectRoot = ""; + targets = ( + 13B07F861A680F5B00A75B9A /* ReactNativeCameraKit */, + 00E356ED1AD99517003FC87E /* ReactNativeCameraKitTests */, + ); + }; +/* 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; + }; + 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; + }; +/* End PBXReferenceProxy section */ + +/* Begin PBXResourcesBuildPhase section */ + 00E356EC1AD99517003FC87E /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 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/packager/react-native-xcode.sh"; + }; + 298D3A2F8738131D7D6292FD /* Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Embed Pods Frameworks"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-ReactNativeCameraKit/Pods-ReactNativeCameraKit-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + 75BD5BC400E0F0FFB5CA4C9D /* Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Check Pods Manifest.lock"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n"; + showEnvVarsInLog = 0; + }; + C901BAD3B5898B500305AA85 /* Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Copy Pods Resources"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-ReactNativeCameraKit/Pods-ReactNativeCameraKit-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 00E356EA1AD99517003FC87E /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 00E356F31AD99517003FC87E /* ReactNativeCameraKitTests.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 13B07F871A680F5B00A75B9A /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + D1D310EA1CBEA1E6006019A8 /* PhotoViewControllerDelegate.swift in Sources */, + D1D310E61CBEA1AA006019A8 /* CameraViewControllerDelegate.swift in Sources */, + 13B07FBC1A68108700A75B9A /* AppDelegate.m in Sources */, + D1D310DC1CBEA062006019A8 /* ReactNativeCameraKit.m in Sources */, + D1D310CF1CBE9FD9006019A8 /* ReactNativeCameraKit.swift in Sources */, + 13B07FC11A68108700A75B9A /* main.m in Sources */, + D1D310E81CBEA1CE006019A8 /* PhotoViewController.swift in Sources */, + D1D310E41CBEA17D006019A8 /* CameraViewController.swift in Sources */, + D1D310DF1CBEA0D0006019A8 /* CropHelper.swift in Sources */, + D1D310E21CBEA15B006019A8 /* CameraSessionManager.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 00E356F51AD99517003FC87E /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 13B07F861A680F5B00A75B9A /* ReactNativeCameraKit */; + targetProxy = 00E356F41AD99517003FC87E /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + 13B07FB11A68108700A75B9A /* LaunchScreen.xib */ = { + isa = PBXVariantGroup; + children = ( + 13B07FB21A68108700A75B9A /* Base */, + ); + name = LaunchScreen.xib; + path = ReactNativeCameraKit; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 00E356F61AD99517003FC87E /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + FRAMEWORK_SEARCH_PATHS = ( + "$(SDKROOT)/Developer/Library/Frameworks", + "$(inherited)", + ); + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + INFOPLIST_FILE = ReactNativeCameraKitTests/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 8.2; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_NAME = "$(TARGET_NAME)"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/ReactNativeCameraKit.app/ReactNativeCameraKit"; + }; + name = Debug; + }; + 00E356F71AD99517003FC87E /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + COPY_PHASE_STRIP = NO; + FRAMEWORK_SEARCH_PATHS = ( + "$(SDKROOT)/Developer/Library/Frameworks", + "$(inherited)", + ); + INFOPLIST_FILE = ReactNativeCameraKitTests/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 8.2; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_NAME = "$(TARGET_NAME)"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/ReactNativeCameraKit.app/ReactNativeCameraKit"; + }; + name = Release; + }; + 13B07F941A680F5B00A75B9A /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = A09C6955B84903CA14AEF620 /* Pods-ReactNativeCameraKit.debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_IDENTITY = "iPhone Developer"; + DEAD_CODE_STRIPPING = NO; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, + "$(SRCROOT)/../node_modules/react-native/React/**", + ); + INFOPLIST_FILE = ReactNativeCameraKit/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + OTHER_LDFLAGS = "-ObjC"; + PRODUCT_BUNDLE_IDENTIFIER = ReactNativeCameraKit; + PRODUCT_NAME = ReactNativeCameraKit; + SWIFT_OBJC_BRIDGING_HEADER = "ReactNativeCameraKit-Bridging-Header.h"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 13B07F951A680F5B00A75B9A /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = C70242A4D4BE4A42B79CB1E5 /* Pods-ReactNativeCameraKit.release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_IDENTITY = "iPhone Developer"; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, + "$(SRCROOT)/../node_modules/react-native/React/**", + ); + INFOPLIST_FILE = ReactNativeCameraKit/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + OTHER_LDFLAGS = "-ObjC"; + PRODUCT_BUNDLE_IDENTIFIER = ReactNativeCameraKit; + PRODUCT_NAME = ReactNativeCameraKit; + SWIFT_OBJC_BRIDGING_HEADER = "ReactNativeCameraKit-Bridging-Header.h"; + }; + 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; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, + "$(SRCROOT)/../node_modules/react-native/React/**", + ); + IPHONEOS_DEPLOYMENT_TARGET = 7.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; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, + "$(SRCROOT)/../node_modules/react-native/React/**", + ); + IPHONEOS_DEPLOYMENT_TARGET = 7.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 00E357021AD99517003FC87E /* Build configuration list for PBXNativeTarget "ReactNativeCameraKitTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 00E356F61AD99517003FC87E /* Debug */, + 00E356F71AD99517003FC87E /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "ReactNativeCameraKit" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 13B07F941A680F5B00A75B9A /* Debug */, + 13B07F951A680F5B00A75B9A /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "ReactNativeCameraKit" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 83CBBA201A601CBA00E9B192 /* Debug */, + 83CBBA211A601CBA00E9B192 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 83CBB9F71A601CBA00E9B192 /* Project object */; +} diff --git a/ios/ReactNativeCameraKit.xcodeproj/xcshareddata/xcschemes/ReactNativeCameraKit.xcscheme b/ios/ReactNativeCameraKit.xcodeproj/xcshareddata/xcschemes/ReactNativeCameraKit.xcscheme new file mode 100644 index 0000000..5f7d181 --- /dev/null +++ b/ios/ReactNativeCameraKit.xcodeproj/xcshareddata/xcschemes/ReactNativeCameraKit.xcscheme @@ -0,0 +1,112 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ios/ReactNativeCameraKit.xcworkspace/contents.xcworkspacedata b/ios/ReactNativeCameraKit.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..7592e97 --- /dev/null +++ b/ios/ReactNativeCameraKit.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/ios/ReactNativeCameraKit/AppDelegate.h b/ios/ReactNativeCameraKit/AppDelegate.h new file mode 100644 index 0000000..a9654d5 --- /dev/null +++ b/ios/ReactNativeCameraKit/AppDelegate.h @@ -0,0 +1,16 @@ +/** + * 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/ios/ReactNativeCameraKit/AppDelegate.m b/ios/ReactNativeCameraKit/AppDelegate.m new file mode 100644 index 0000000..600f3c4 --- /dev/null +++ b/ios/ReactNativeCameraKit/AppDelegate.m @@ -0,0 +1,59 @@ +/** + * 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 "RCTRootView.h" + +@implementation AppDelegate + +- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions +{ + NSURL *jsCodeLocation; + + /** + * Loading JavaScript code - uncomment the one you want. + * + * OPTION 1 + * Load from development server. Start the server from the repository root: + * + * $ npm start + * + * To run on device, change `localhost` to the IP address of your computer + * (you can get this by typing `ifconfig` into the terminal and selecting the + * `inet` value under `en0:`) and make sure your computer and iOS device are + * on the same Wi-Fi network. + */ + + //jsCodeLocation = [NSURL URLWithString:@"http://localhost:8081/index.ios.bundle?platform=ios&dev=true"]; + + /** + * OPTION 2 + * Load from pre-bundled file on disk. The static bundle is automatically + * generated by the "Bundle React Native code and images" build step when + * running the project on an actual device or running the project on the + * simulator in the "Release" build configuration. + */ + + jsCodeLocation = [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"]; + + RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation + moduleName:@"ReactNativeCameraKit" + initialProperties:nil + launchOptions:launchOptions]; + + 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/ios/ReactNativeCameraKit/Base.lproj/LaunchScreen.xib b/ios/ReactNativeCameraKit/Base.lproj/LaunchScreen.xib new file mode 100644 index 0000000..427eafd --- /dev/null +++ b/ios/ReactNativeCameraKit/Base.lproj/LaunchScreen.xib @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ios/ReactNativeCameraKit/Images.xcassets/AppIcon.appiconset/Contents.json b/ios/ReactNativeCameraKit/Images.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..118c98f --- /dev/null +++ b/ios/ReactNativeCameraKit/Images.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,38 @@ +{ + "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/ios/ReactNativeCameraKit/Images.xcassets/CloseIcon.imageset/Contents.json b/ios/ReactNativeCameraKit/Images.xcassets/CloseIcon.imageset/Contents.json new file mode 100644 index 0000000..7428ddc --- /dev/null +++ b/ios/ReactNativeCameraKit/Images.xcassets/CloseIcon.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "Delete-2.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "Delete.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "Delete-1.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/ios/ReactNativeCameraKit/Images.xcassets/CloseIcon.imageset/Delete-1.png b/ios/ReactNativeCameraKit/Images.xcassets/CloseIcon.imageset/Delete-1.png new file mode 100644 index 0000000..91f7d22 Binary files /dev/null and b/ios/ReactNativeCameraKit/Images.xcassets/CloseIcon.imageset/Delete-1.png differ diff --git a/ios/ReactNativeCameraKit/Images.xcassets/CloseIcon.imageset/Delete-2.png b/ios/ReactNativeCameraKit/Images.xcassets/CloseIcon.imageset/Delete-2.png new file mode 100644 index 0000000..91f7d22 Binary files /dev/null and b/ios/ReactNativeCameraKit/Images.xcassets/CloseIcon.imageset/Delete-2.png differ diff --git a/ios/ReactNativeCameraKit/Images.xcassets/CloseIcon.imageset/Delete.png b/ios/ReactNativeCameraKit/Images.xcassets/CloseIcon.imageset/Delete.png new file mode 100644 index 0000000..91f7d22 Binary files /dev/null and b/ios/ReactNativeCameraKit/Images.xcassets/CloseIcon.imageset/Delete.png differ diff --git a/ios/ReactNativeCameraKit/Images.xcassets/FlashAutoIcon.imageset/Contents.json b/ios/ReactNativeCameraKit/Images.xcassets/FlashAutoIcon.imageset/Contents.json new file mode 100644 index 0000000..58b470b --- /dev/null +++ b/ios/ReactNativeCameraKit/Images.xcassets/FlashAutoIcon.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "flash_on_filled-25.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "flash_on_filled-50.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "flash_on_filled-75.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/ios/ReactNativeCameraKit/Images.xcassets/FlashAutoIcon.imageset/flash_on_filled-25.png b/ios/ReactNativeCameraKit/Images.xcassets/FlashAutoIcon.imageset/flash_on_filled-25.png new file mode 100644 index 0000000..4c0837e Binary files /dev/null and b/ios/ReactNativeCameraKit/Images.xcassets/FlashAutoIcon.imageset/flash_on_filled-25.png differ diff --git a/ios/ReactNativeCameraKit/Images.xcassets/FlashAutoIcon.imageset/flash_on_filled-50.png b/ios/ReactNativeCameraKit/Images.xcassets/FlashAutoIcon.imageset/flash_on_filled-50.png new file mode 100644 index 0000000..7bd8e30 Binary files /dev/null and b/ios/ReactNativeCameraKit/Images.xcassets/FlashAutoIcon.imageset/flash_on_filled-50.png differ diff --git a/ios/ReactNativeCameraKit/Images.xcassets/FlashAutoIcon.imageset/flash_on_filled-75.png b/ios/ReactNativeCameraKit/Images.xcassets/FlashAutoIcon.imageset/flash_on_filled-75.png new file mode 100644 index 0000000..71f5f82 Binary files /dev/null and b/ios/ReactNativeCameraKit/Images.xcassets/FlashAutoIcon.imageset/flash_on_filled-75.png differ diff --git a/ios/ReactNativeCameraKit/Images.xcassets/FlashOffIcon.imageset/Contents.json b/ios/ReactNativeCameraKit/Images.xcassets/FlashOffIcon.imageset/Contents.json new file mode 100644 index 0000000..26ef628 --- /dev/null +++ b/ios/ReactNativeCameraKit/Images.xcassets/FlashOffIcon.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "flash_off_filled-25.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "flash_off_filled-50.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "flash_off_filled-75.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/ios/ReactNativeCameraKit/Images.xcassets/FlashOffIcon.imageset/flash_off_filled-25.png b/ios/ReactNativeCameraKit/Images.xcassets/FlashOffIcon.imageset/flash_off_filled-25.png new file mode 100644 index 0000000..e31c744 Binary files /dev/null and b/ios/ReactNativeCameraKit/Images.xcassets/FlashOffIcon.imageset/flash_off_filled-25.png differ diff --git a/ios/ReactNativeCameraKit/Images.xcassets/FlashOffIcon.imageset/flash_off_filled-50.png b/ios/ReactNativeCameraKit/Images.xcassets/FlashOffIcon.imageset/flash_off_filled-50.png new file mode 100644 index 0000000..0777811 Binary files /dev/null and b/ios/ReactNativeCameraKit/Images.xcassets/FlashOffIcon.imageset/flash_off_filled-50.png differ diff --git a/ios/ReactNativeCameraKit/Images.xcassets/FlashOffIcon.imageset/flash_off_filled-75.png b/ios/ReactNativeCameraKit/Images.xcassets/FlashOffIcon.imageset/flash_off_filled-75.png new file mode 100644 index 0000000..82516b3 Binary files /dev/null and b/ios/ReactNativeCameraKit/Images.xcassets/FlashOffIcon.imageset/flash_off_filled-75.png differ diff --git a/ios/ReactNativeCameraKit/Images.xcassets/FlashOnIcon.imageset/Contents.json b/ios/ReactNativeCameraKit/Images.xcassets/FlashOnIcon.imageset/Contents.json new file mode 100644 index 0000000..58b470b --- /dev/null +++ b/ios/ReactNativeCameraKit/Images.xcassets/FlashOnIcon.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "flash_on_filled-25.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "flash_on_filled-50.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "flash_on_filled-75.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/ios/ReactNativeCameraKit/Images.xcassets/FlashOnIcon.imageset/flash_on_filled-25.png b/ios/ReactNativeCameraKit/Images.xcassets/FlashOnIcon.imageset/flash_on_filled-25.png new file mode 100644 index 0000000..ff186b6 Binary files /dev/null and b/ios/ReactNativeCameraKit/Images.xcassets/FlashOnIcon.imageset/flash_on_filled-25.png differ diff --git a/ios/ReactNativeCameraKit/Images.xcassets/FlashOnIcon.imageset/flash_on_filled-50.png b/ios/ReactNativeCameraKit/Images.xcassets/FlashOnIcon.imageset/flash_on_filled-50.png new file mode 100644 index 0000000..acafd2a Binary files /dev/null and b/ios/ReactNativeCameraKit/Images.xcassets/FlashOnIcon.imageset/flash_on_filled-50.png differ diff --git a/ios/ReactNativeCameraKit/Images.xcassets/FlashOnIcon.imageset/flash_on_filled-75.png b/ios/ReactNativeCameraKit/Images.xcassets/FlashOnIcon.imageset/flash_on_filled-75.png new file mode 100644 index 0000000..50b9850 Binary files /dev/null and b/ios/ReactNativeCameraKit/Images.xcassets/FlashOnIcon.imageset/flash_on_filled-75.png differ diff --git a/ios/ReactNativeCameraKit/Images.xcassets/ShutterIcon.imageset/Contents.json b/ios/ReactNativeCameraKit/Images.xcassets/ShutterIcon.imageset/Contents.json new file mode 100644 index 0000000..b04081d --- /dev/null +++ b/ios/ReactNativeCameraKit/Images.xcassets/ShutterIcon.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "Shutter-Release.jpg", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "Shutter-Release-1.jpg", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "Shutter-Release-2.jpg", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/ios/ReactNativeCameraKit/Images.xcassets/ShutterIcon.imageset/Shutter-Release-1.jpg b/ios/ReactNativeCameraKit/Images.xcassets/ShutterIcon.imageset/Shutter-Release-1.jpg new file mode 100644 index 0000000..bd95f5f Binary files /dev/null and b/ios/ReactNativeCameraKit/Images.xcassets/ShutterIcon.imageset/Shutter-Release-1.jpg differ diff --git a/ios/ReactNativeCameraKit/Images.xcassets/ShutterIcon.imageset/Shutter-Release-2.jpg b/ios/ReactNativeCameraKit/Images.xcassets/ShutterIcon.imageset/Shutter-Release-2.jpg new file mode 100644 index 0000000..bd95f5f Binary files /dev/null and b/ios/ReactNativeCameraKit/Images.xcassets/ShutterIcon.imageset/Shutter-Release-2.jpg differ diff --git a/ios/ReactNativeCameraKit/Images.xcassets/ShutterIcon.imageset/Shutter-Release.jpg b/ios/ReactNativeCameraKit/Images.xcassets/ShutterIcon.imageset/Shutter-Release.jpg new file mode 100644 index 0000000..bd95f5f Binary files /dev/null and b/ios/ReactNativeCameraKit/Images.xcassets/ShutterIcon.imageset/Shutter-Release.jpg differ diff --git a/ios/ReactNativeCameraKit/Info.plist b/ios/ReactNativeCameraKit/Info.plist new file mode 100644 index 0000000..9fad329 --- /dev/null +++ b/ios/ReactNativeCameraKit/Info.plist @@ -0,0 +1,47 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + LSRequiresIPhoneOS + + NSAppTransportSecurity + + NSAllowsArbitraryLoads + + + NSLocationWhenInUseUsageDescription + + UILaunchStoryboardName + LaunchScreen + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UIViewControllerBasedStatusBarAppearance + + + diff --git a/ios/ReactNativeCameraKit/main.m b/ios/ReactNativeCameraKit/main.m new file mode 100644 index 0000000..3d767fc --- /dev/null +++ b/ios/ReactNativeCameraKit/main.m @@ -0,0 +1,18 @@ +/** + * 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/ios/ReactNativeCameraKitTests/Info.plist b/ios/ReactNativeCameraKitTests/Info.plist new file mode 100644 index 0000000..886825c --- /dev/null +++ b/ios/ReactNativeCameraKitTests/Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + + diff --git a/ios/ReactNativeCameraKitTests/ReactNativeCameraKitTests.m b/ios/ReactNativeCameraKitTests/ReactNativeCameraKitTests.m new file mode 100644 index 0000000..1b95c9f --- /dev/null +++ b/ios/ReactNativeCameraKitTests/ReactNativeCameraKitTests.m @@ -0,0 +1,70 @@ +/** + * 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 + +#import "RCTLog.h" +#import "RCTRootView.h" + +#define TIMEOUT_SECONDS 240 +#define TEXT_TO_LOOK_FOR @"Welcome to React Native!" + +@interface ReactNativeCameraKitTests : XCTestCase + +@end + +@implementation ReactNativeCameraKitTests + +- (BOOL)findSubviewInView:(UIView *)view matching:(BOOL(^)(UIView *view))test +{ + if (test(view)) { + return YES; + } + for (UIView *subview in [view subviews]) { + if ([self findSubviewInView:subview matching:test]) { + return YES; + } + } + return NO; +} + +- (void)testRendersWelcomeScreen +{ + UIViewController *vc = [[[[UIApplication sharedApplication] delegate] window] rootViewController]; + NSDate *date = [NSDate dateWithTimeIntervalSinceNow:TIMEOUT_SECONDS]; + BOOL foundElement = NO; + + __block NSString *redboxError = nil; + RCTSetLogFunction(^(RCTLogLevel level, RCTLogSource source, NSString *fileName, NSNumber *lineNumber, NSString *message) { + if (level >= RCTLogLevelError) { + redboxError = message; + } + }); + + while ([date timeIntervalSinceNow] > 0 && !foundElement && !redboxError) { + [[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; + [[NSRunLoop mainRunLoop] runMode:NSRunLoopCommonModes beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; + + foundElement = [self findSubviewInView:vc.view matching:^BOOL(UIView *view) { + if ([view.accessibilityLabel isEqualToString:TEXT_TO_LOOK_FOR]) { + return YES; + } + return NO; + }]; + } + + RCTSetLogFunction(RCTDefaultLogFunction); + + XCTAssertNil(redboxError, @"RedBox error: %@", redboxError); + XCTAssertTrue(foundElement, @"Couldn't find element with text '%@' in %d seconds", TEXT_TO_LOOK_FOR, TIMEOUT_SECONDS); +} + + +@end diff --git a/package.json b/package.json new file mode 100644 index 0000000..bf5e4e9 --- /dev/null +++ b/package.json @@ -0,0 +1,12 @@ +{ + "name": "react-native-camera-kit", + "version": "0.0.1", + "private": true, + "scripts": { + "start": "node node_modules/react-native/local-cli/cli.js start" + }, + "dependencies": { + "react": "^0.14.8", + "react-native": "^0.23.1" + } +}