diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..3c53fa0ce --- /dev/null +++ b/.gitignore @@ -0,0 +1,42 @@ +# 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 + +# BUCK +buck-out/ +\.buckd/ +android/app/libs +android/keystores/debug.keystore +pods +.vscode diff --git a/README.md b/README.md new file mode 100644 index 000000000..abaddf8d3 --- /dev/null +++ b/README.md @@ -0,0 +1,109 @@ +# react-native-image-crop-picker +iOS/Android image picker with support for multiple images and cropping + +**NOTE:** This library is result of one-night hacking, so please use it with caution. Don't assume there are not bugs. It is tested just on simple cases. + +## Result + +#### iOS + + + + +#### Android + + + + +## Usage + +Import library +```javascript +import ImagePicker from 'react-native-image-crop-picker'; +``` + +Call single image picker with cropping +```javascript +ImagePicker.openPicker({ + width: 300, + height: 400, + cropping: true +}).then(image => { + console.log(image); +}); +``` + +Call multiple image picker +```javascript +ImagePicker.openPicker({ + multiple: true +}).then(images => { + console.log(images); +}); +``` + +## Install + +`npm install react-native-image-crop-picker --save` + +#### iOS + +``` +pod 'react-native-image-crop-picker', :path => '../node_modules/react-native-image-crop-picker/ios' +``` + +#### Android +```gradle +// file: android/settings.gradle +... + +include ':react-native-image-crop-picker' +project(':react-native-image-crop-picker').projectDir = new File(settingsDir, '../node_modules/react-native-image-crop-picker/android') +``` +```gradle +// file: android/app/build.gradle +... + +dependencies { + ... + compile project(':react-native-image-crop-picker') +} +``` + +```java +// file: MainActivity.java +... + +import com.reactnative.picker.PickerPackage; // import package + +public class MainActivity extends ReactActivity { + + /** + * 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(), + new PickerPackage() // Add package + ); + } +... +} +``` + +## How it works? + +It is basically wrapper around few libraries + +#### Android +- Native Image Picker +- uCrop + +#### iOS +- QBImagePickerController +- RSKImageCropper + +## License +*MIT* diff --git a/android/android.iml b/android/android.iml new file mode 100644 index 000000000..12ad1fbdb --- /dev/null +++ b/android/android.iml @@ -0,0 +1,146 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/android/build.gradle b/android/build.gradle new file mode 100644 index 000000000..7f62216b1 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,34 @@ +buildscript { + repositories { + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:2.1.0' + } +} + +apply plugin: 'com.android.library' + +android { + compileSdkVersion 23 + buildToolsVersion "23.0.1" + + defaultConfig { + minSdkVersion 18 + targetSdkVersion 22 + versionCode 1 + } + lintOptions { + abortOnError false + } +} + +repositories { + mavenCentral() +} + +dependencies { + compile 'com.facebook.react:react-native:0.20.+' + compile 'com.yalantis:ucrop:1.5.0' +} \ No newline at end of file diff --git a/android/gradle/wrapper/gradle-wrapper.jar b/android/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 000000000..13372aef5 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 000000000..0f5c93fa2 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Tue May 17 14:28:43 CEST 2016 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-2.10-all.zip diff --git a/android/gradlew b/android/gradlew new file mode 100644 index 000000000..9d82f7891 --- /dev/null +++ b/android/gradlew @@ -0,0 +1,160 @@ +#!/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 + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + 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"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + 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 000000000..aec99730b --- /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/react-native-image-crop-picker.iml b/android/react-native-image-crop-picker.iml new file mode 100644 index 000000000..c950f3cb7 --- /dev/null +++ b/android/react-native-image-crop-picker.iml @@ -0,0 +1,122 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/android/src/main/AndroidManifest.xml b/android/src/main/AndroidManifest.xml new file mode 100644 index 000000000..dad75a95e --- /dev/null +++ b/android/src/main/AndroidManifest.xml @@ -0,0 +1,11 @@ + + + + + + + diff --git a/android/src/main/java/com/reactnative/picker/PickerModule.java b/android/src/main/java/com/reactnative/picker/PickerModule.java new file mode 100644 index 000000000..da47bb0c3 --- /dev/null +++ b/android/src/main/java/com/reactnative/picker/PickerModule.java @@ -0,0 +1,163 @@ +package com.reactnative.picker; + +import android.app.Activity; +import android.content.ClipData; +import android.content.Intent; +import android.database.Cursor; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.net.Uri; +import android.provider.DocumentsContract; +import android.provider.MediaStore; + +import com.facebook.react.bridge.ActivityEventListener; +import com.facebook.react.bridge.Promise; +import com.facebook.react.bridge.ReactApplicationContext; +import com.facebook.react.bridge.ReactContextBaseJavaModule; +import com.facebook.react.bridge.ReactMethod; +import com.facebook.react.bridge.ReadableMap; +import com.facebook.react.bridge.WritableArray; +import com.facebook.react.bridge.WritableMap; +import com.facebook.react.bridge.WritableNativeArray; +import com.facebook.react.bridge.WritableNativeMap; +import com.yalantis.ucrop.UCrop; + +import java.io.File; +import java.util.UUID; + +/** + * Created by ipusic on 5/16/16. + */ +public class PickerModule extends ReactContextBaseJavaModule implements ActivityEventListener { + + private static final int IMAGE_PICKER_REQUEST = 1; + private static final String E_ACTIVITY_DOES_NOT_EXIST = "E_ACTIVITY_DOES_NOT_EXIST"; + private static final String E_PICKER_CANCELLED = "E_PICKER_CANCELLED"; + private static final String E_FAILED_TO_SHOW_PICKER = "E_FAILED_TO_SHOW_PICKER"; + private static final String E_NO_IMAGE_DATA_FOUND = "E_NO_IMAGE_DATA_FOUND"; + + private Promise mPickerPromise; + private Activity activity; + + private boolean cropping = false; + private boolean multiple = false; + private int width = 100; + private int height = 100; + + public PickerModule(ReactApplicationContext reactContext) { + super(reactContext); + reactContext.addActivityEventListener(this); + } + + @Override + public String getName() { + return "ImageCropPicker"; + } + + @ReactMethod + public void openPicker(final ReadableMap options, final Promise promise) { + activity = getCurrentActivity(); + + if (activity == null) { + promise.reject(E_ACTIVITY_DOES_NOT_EXIST, "Activity doesn't exist"); + return; + } + + multiple = options.hasKey("multiple") && options.getBoolean("multiple"); + width = options.hasKey("width") ? options.getInt("width") : width; + height = options.hasKey("height") ? options.getInt("height") : height; + cropping = options.hasKey("cropping") ? options.getBoolean("cropping") : cropping; + + // Store the promise to resolve/reject when picker returns data + mPickerPromise = promise; + + try { + final Intent galleryIntent = new Intent(Intent.ACTION_PICK); + galleryIntent.setType("image/*"); + galleryIntent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, multiple); + galleryIntent.setAction(Intent.ACTION_GET_CONTENT); + + final Intent chooserIntent = Intent.createChooser(galleryIntent, "Pick an image"); + activity.startActivityForResult(chooserIntent, IMAGE_PICKER_REQUEST); + } catch (Exception e) { + mPickerPromise.reject(E_FAILED_TO_SHOW_PICKER, e); + mPickerPromise = null; + } + } + + private WritableMap getImage(Uri uri, boolean resolvePath) { + WritableMap image = new WritableNativeMap(); + String path = uri.getPath(); + + if (resolvePath) { + path = RealPathUtil.getRealPathFromURI(activity, uri); + } + + BitmapFactory.Options options = new BitmapFactory.Options(); + options.inJustDecodeBounds = true; + BitmapFactory.decodeFile(path, options); + + image.putString("path", "file://" + path); + image.putInt("width", options.outWidth); + image.putInt("height", options.outHeight); + + return image; + } + + @Override + public void onActivityResult(final int requestCode, final int resultCode, final Intent data) { + if (requestCode == IMAGE_PICKER_REQUEST) { + if (mPickerPromise != null) { + if (resultCode == Activity.RESULT_CANCELED) { + mPickerPromise.reject(E_PICKER_CANCELLED, "Image picker was cancelled"); + } else if (resultCode == Activity.RESULT_OK) { + if (multiple) { + ClipData clipData = data.getClipData(); + WritableArray result = new WritableNativeArray(); + + // only one image selected + if (clipData == null) { + result.pushMap(getImage(data.getData(), true)); + } else { + for (int i = 0; i < clipData.getItemCount(); i++) { + result.pushMap(getImage(clipData.getItemAt(i).getUri(), true)); + } + } + + mPickerPromise.resolve(result); + mPickerPromise = null; + } else { + Uri uri = data.getData(); + + if (cropping) { + UCrop.Options options = new UCrop.Options(); + options.setCompressionFormat(Bitmap.CompressFormat.JPEG); + + UCrop.of(uri, Uri.fromFile(new File(activity.getCacheDir(), UUID.randomUUID().toString() + ".jpg"))) + .withMaxResultSize(width, height) + .withAspectRatio(width, height) + .withOptions(options) + .start(activity); + } else { + mPickerPromise.resolve(getImage(uri, true)); + mPickerPromise = null; + } + } + } + } + } else if (requestCode == UCrop.REQUEST_CROP) { + if (data != null) { + final Uri resultUri = UCrop.getOutput(data); + if (resultUri != null) { + mPickerPromise.resolve(getImage(resultUri, false)); + } else { + mPickerPromise.reject(E_NO_IMAGE_DATA_FOUND, "Cannot find image data"); + } + } else { + mPickerPromise.reject(E_NO_IMAGE_DATA_FOUND, "Image cropping rejected"); + } + + mPickerPromise = null; + } + } +} diff --git a/android/src/main/java/com/reactnative/picker/PickerPackage.java b/android/src/main/java/com/reactnative/picker/PickerPackage.java new file mode 100644 index 000000000..072d1756c --- /dev/null +++ b/android/src/main/java/com/reactnative/picker/PickerPackage.java @@ -0,0 +1,35 @@ +package com.reactnative.picker; + +import com.facebook.react.ReactPackage; +import com.facebook.react.bridge.JavaScriptModule; +import com.facebook.react.bridge.NativeModule; +import com.facebook.react.bridge.ReactApplicationContext; +import com.facebook.react.uimanager.ViewManager; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * Created by ipusic on 5/16/16. + */ +public class PickerPackage implements ReactPackage { + + @Override + public List> createJSModules() { + return Collections.emptyList(); + } + + @Override + public List createViewManagers(ReactApplicationContext reactContext) { + return Collections.emptyList(); + } + + @Override + public List createNativeModules(ReactApplicationContext reactContext) { + List modules = new ArrayList<>(); + modules.add(new PickerModule(reactContext)); + + return modules; + } +} diff --git a/android/src/main/java/com/reactnative/picker/RealPathUtil.java b/android/src/main/java/com/reactnative/picker/RealPathUtil.java new file mode 100644 index 000000000..8198513cb --- /dev/null +++ b/android/src/main/java/com/reactnative/picker/RealPathUtil.java @@ -0,0 +1,66 @@ +package com.reactnative.picker; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.content.CursorLoader; +import android.database.Cursor; +import android.net.Uri; +import android.os.Build; +import android.provider.DocumentsContract; +import android.provider.MediaStore; + +/** + * Created by ipusic on 5/18/16. + */ +public class RealPathUtil { + + public static String getRealPathFromURI(Context context, Uri uri) { + if (Build.VERSION.SDK_INT < 19) + return RealPathUtil.getRealPathFromURI_API11to18(context, uri); + else + return RealPathUtil.getRealPathFromURI_API19(context, uri); + } + + @SuppressLint("NewApi") + private static String getRealPathFromURI_API19(Context context, Uri uri) { + String filePath = ""; + String wholeID = DocumentsContract.getDocumentId(uri); + + // Split at colon, use second item in the array + String id = wholeID.split(":")[1]; + + String[] column = {MediaStore.Images.Media.DATA}; + + // where id is equal to + String sel = MediaStore.Images.Media._ID + "=?"; + + Cursor cursor = context.getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, + column, sel, new String[]{id}, null); + + int columnIndex = cursor.getColumnIndex(column[0]); + + if (cursor.moveToFirst()) { + filePath = cursor.getString(columnIndex); + } + cursor.close(); + return filePath; + } + + private static String getRealPathFromURI_API11to18(Context context, Uri contentUri) { + String[] proj = {MediaStore.Images.Media.DATA}; + String result = null; + + CursorLoader cursorLoader = new CursorLoader( + context, + contentUri, proj, null, null, null); + Cursor cursor = cursorLoader.loadInBackground(); + + if (cursor != null) { + int column_index = + cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA); + cursor.moveToFirst(); + result = cursor.getString(column_index); + } + return result; + } +} diff --git a/android/src/test/test.iml b/android/src/test/test.iml new file mode 100644 index 000000000..a0e49a3ba --- /dev/null +++ b/android/src/test/test.iml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/example/.buckconfig b/example/.buckconfig new file mode 100644 index 000000000..934256cb2 --- /dev/null +++ b/example/.buckconfig @@ -0,0 +1,6 @@ + +[android] + target = Google Inc.:Google APIs:23 + +[maven_repositories] + central = https://repo1.maven.org/maven2 diff --git a/example/.flowconfig b/example/.flowconfig new file mode 100644 index 000000000..f56848d2f --- /dev/null +++ b/example/.flowconfig @@ -0,0 +1,96 @@ +[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/.* + +# Ignore generators +.*/local-cli/generator.* + +# Ignore BUCK generated folders +.*\.buckd/ + +.*/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-3]\\|1[0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\) +suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(>=0\\.\\(2[0-3]\\|1[0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)?:? #[0-9]+ +suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy + +[version] +0.23.0 diff --git a/example/.gitignore b/example/.gitignore new file mode 100644 index 000000000..42c9490e5 --- /dev/null +++ b/example/.gitignore @@ -0,0 +1,40 @@ +# 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 + +# BUCK +buck-out/ +\.buckd/ +android/app/libs +android/keystores/debug.keystore diff --git a/example/.watchmanconfig b/example/.watchmanconfig new file mode 100644 index 000000000..9e26dfeeb --- /dev/null +++ b/example/.watchmanconfig @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/example/android/app/BUCK b/example/android/app/BUCK new file mode 100644 index 000000000..d73aebd81 --- /dev/null +++ b/example/android/app/BUCK @@ -0,0 +1,66 @@ +import re + +# To learn about Buck see [Docs](https://buckbuild.com/). +# To run your application with Buck: +# - install Buck +# - `npm start` - to start the packager +# - `cd android` +# - `keytool -genkey -v -keystore keystores/debug.keystore -storepass android -alias androiddebugkey -keypass android -dname "CN=Android Debug,O=Android,C=US` +# - `./gradlew :app:copyDownloadableDepsToLibs` - make all Gradle compile dependencies available to Buck +# - `buck install -r android/app` - compile, install and run application +# + +lib_deps = [] +for jarfile in glob(['libs/*.jar']): + name = 'jars__' + re.sub(r'^.*/([^/]+)\.jar$', r'\1', jarfile) + lib_deps.append(':' + name) + prebuilt_jar( + name = name, + binary_jar = jarfile, + ) + +for aarfile in glob(['libs/*.aar']): + name = 'aars__' + re.sub(r'^.*/([^/]+)\.aar$', r'\1', aarfile) + lib_deps.append(':' + name) + android_prebuilt_aar( + name = name, + aar = aarfile, + ) + +android_library( + name = 'all-libs', + exported_deps = lib_deps +) + +android_library( + name = 'app-code', + srcs = glob([ + 'src/main/java/**/*.java', + ]), + deps = [ + ':all-libs', + ':build_config', + ':res', + ], +) + +android_build_config( + name = 'build_config', + package = 'com.example', +) + +android_resource( + name = 'res', + res = 'src/main/res', + package = 'com.example', +) + +android_binary( + name = 'app', + package_type = 'debug', + manifest = 'src/main/AndroidManifest.xml', + keystore = '//android/keystores:debug', + deps = [ + ':app-code', + ], +) diff --git a/example/android/app/app.iml b/example/android/app/app.iml new file mode 100644 index 000000000..ca018f031 --- /dev/null +++ b/example/android/app/app.iml @@ -0,0 +1,131 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/example/android/app/build.gradle b/example/android/app/build.gradle new file mode 100644 index 000000000..d964842ea --- /dev/null +++ b/example/android/app/build.gradle @@ -0,0 +1,133 @@ +apply plugin: "com.android.application" + +import com.android.build.OutputFile + +/** + * The react.gradle file registers a task for each build variant (e.g. bundleDebugJsAndAssets + * and bundleReleaseJsAndAssets). + * These basically call `react-native bundle` with the correct arguments during the Android build + * cycle. By default, bundleDebugJsAndAssets is skipped, as in debug/dev mode we prefer to load the + * bundle directly from the development server. Below you can see all the possible configurations + * and their defaults. If you decide to add a configuration block, make sure to add it before the + * `apply from: "../../node_modules/react-native/react.gradle"` line. + * + * project.ext.react = [ + * // the name of the generated asset file containing your JS bundle + * bundleAssetName: "index.android.bundle", + * + * // the entry file for bundle generation + * entryFile: "index.android.js", + * + * // whether to bundle JS and assets in debug mode + * bundleInDebug: false, + * + * // whether to bundle JS and assets in release mode + * bundleInRelease: true, + * + * // whether to bundle JS and assets in another build variant (if configured). + * // See http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Build-Variants + * // The configuration property can be in the following formats + * // 'bundleIn${productFlavor}${buildType}' + * // 'bundleIn${buildType}' + * // bundleInFreeDebug: true, + * // bundleInPaidRelease: true, + * // bundleInBeta: true, + * + * // 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: "../../node_modules/react-native/react.gradle" + +/** + * Set this to true to create two separate APKs instead of one: + * - An APK that only works on ARM devices + * - An APK that only works on x86 devices + * The advantage is the size of the APK is reduced by about 4MB. + * Upload all the APKs to the Play Store and people will download + * the correct one based on the CPU architecture of their device. + */ +def enableSeparateBuildPerCPUArchitecture = false + +/** + * Run Proguard to shrink the Java bytecode in release builds. + */ +def enableProguardInReleaseBuilds = false + +android { + compileSdkVersion 23 + buildToolsVersion "23.0.1" + + defaultConfig { + applicationId "com.example" + minSdkVersion 18 + targetSdkVersion 22 + versionCode 1 + 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 + compile project(':react-native-image-crop-picker') +} + +// Run this once to be able to run the application with BUCK +// puts all compile dependencies into folder libs for BUCK to use +task copyDownloadableDepsToLibs(type: Copy) { + from configurations.compile + into 'libs' +} diff --git a/example/android/app/proguard-rules.pro b/example/android/app/proguard-rules.pro new file mode 100644 index 000000000..347a13ce1 --- /dev/null +++ b/example/android/app/proguard-rules.pro @@ -0,0 +1,63 @@ +# 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.** diff --git a/example/android/app/src/main/AndroidManifest.xml b/example/android/app/src/main/AndroidManifest.xml new file mode 100644 index 000000000..f18334724 --- /dev/null +++ b/example/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + diff --git a/example/android/app/src/main/java/com/example/MainActivity.java b/example/android/app/src/main/java/com/example/MainActivity.java new file mode 100644 index 000000000..31d83753e --- /dev/null +++ b/example/android/app/src/main/java/com/example/MainActivity.java @@ -0,0 +1,43 @@ +package com.example; + +import com.facebook.react.ReactActivity; +import com.facebook.react.ReactPackage; +import com.facebook.react.shell.MainReactPackage; + +import com.reactnative.picker.PickerPackage; + +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 "example"; + } + + /** + * 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(), + new PickerPackage() + ); + } +} diff --git a/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 000000000..cde69bccc Binary files /dev/null and b/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 000000000..c133a0cbd Binary files /dev/null and b/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 000000000..bfa42f0e7 Binary files /dev/null and b/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 000000000..324e72cdd Binary files /dev/null and b/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/example/android/app/src/main/res/values/strings.xml b/example/android/app/src/main/res/values/strings.xml new file mode 100644 index 000000000..d75426c8a --- /dev/null +++ b/example/android/app/src/main/res/values/strings.xml @@ -0,0 +1,3 @@ + + example + diff --git a/example/android/app/src/main/res/values/styles.xml b/example/android/app/src/main/res/values/styles.xml new file mode 100644 index 000000000..319eb0ca1 --- /dev/null +++ b/example/android/app/src/main/res/values/styles.xml @@ -0,0 +1,8 @@ + + + + + + diff --git a/example/android/build.gradle b/example/android/build.gradle new file mode 100644 index 000000000..403a00756 --- /dev/null +++ b/example/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/example/android/example.iml b/example/android/example.iml new file mode 100644 index 000000000..644878a55 --- /dev/null +++ b/example/android/example.iml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/example/android/gradle.properties b/example/android/gradle.properties new file mode 100644 index 000000000..1fd964e90 --- /dev/null +++ b/example/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/example/android/gradle/wrapper/gradle-wrapper.jar b/example/android/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 000000000..b5166dad4 Binary files /dev/null and b/example/android/gradle/wrapper/gradle-wrapper.jar differ diff --git a/example/android/gradle/wrapper/gradle-wrapper.properties b/example/android/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 000000000..b9fbfaba0 --- /dev/null +++ b/example/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/example/android/gradlew b/example/android/gradlew new file mode 100755 index 000000000..91a7e269e --- /dev/null +++ b/example/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/example/android/gradlew.bat b/example/android/gradlew.bat new file mode 100644 index 000000000..aec99730b --- /dev/null +++ b/example/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/example/android/settings.gradle b/example/android/settings.gradle new file mode 100644 index 000000000..b915a6c42 --- /dev/null +++ b/example/android/settings.gradle @@ -0,0 +1,6 @@ +rootProject.name = 'example' + +include ':app' + +include ':react-native-image-crop-picker' +project(':react-native-image-crop-picker').projectDir = new File(settingsDir, '../../android') \ No newline at end of file diff --git a/example/app.js b/example/app.js new file mode 100644 index 000000000..9c102d147 --- /dev/null +++ b/example/app.js @@ -0,0 +1,82 @@ +import React, {Component} from 'react'; +import {View, Text, StyleSheet, ScrollView, Image, TouchableOpacity} from 'react-native'; + +import {NativeModules} from 'react-native'; +var ImagePicker = NativeModules.ImageCropPicker; + +const styles = StyleSheet.create({ + container: { + flex: 1, + justifyContent: 'center', + alignItems: 'center' + }, + button: { + backgroundColor: 'blue', + marginBottom: 10 + }, + text: { + color: 'white', + fontSize: 20 + } +}); + +export default class App extends Component { + + constructor() { + super(); + this.state = { + image: null, + images: null + }; + } + + pickSingle(cropit) { + ImagePicker.openPicker({ + width: 300, + height: 300, + cropping: cropit + }).then(image => { + this.setState({ + image: {uri: image.path, width: image.width, height: image.height}, + images: null + }); + }).catch(e => {}); + } + + pickMultiple() { + ImagePicker.openPicker({ + multiple: true + }).then(images => { + this.setState({ + image: null, + images: images.map(i => { + return {uri: i.path, width: i.width, height: i.height}; + }) + }); + }).catch(e => {}); + } + + scaledHeight(oldW, oldH, newW) { + return (oldH / oldW) * newW; + } + + render() { + return + + + {this.state.image ? : null} + {this.state.images ? this.state.images.map(i => ) : null} + + + this.pickSingle(false)} style={styles.button}> + Select Single + + this.pickSingle(true)} style={styles.button}> + Select Single With Cropping + + + Select Multiple + + ; + } +} diff --git a/example/index.android.js b/example/index.android.js new file mode 100644 index 000000000..7b25275b8 --- /dev/null +++ b/example/index.android.js @@ -0,0 +1,4 @@ +import {AppRegistry} from 'react-native'; +import App from './app'; + +AppRegistry.registerComponent('example', () => App); diff --git a/example/index.ios.js b/example/index.ios.js new file mode 100644 index 000000000..7b25275b8 --- /dev/null +++ b/example/index.ios.js @@ -0,0 +1,4 @@ +import {AppRegistry} from 'react-native'; +import App from './app'; + +AppRegistry.registerComponent('example', () => App); diff --git a/example/ios/Podfile b/example/ios/Podfile new file mode 100644 index 000000000..9afe5bc52 --- /dev/null +++ b/example/ios/Podfile @@ -0,0 +1,23 @@ +# 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 'example' do + +pod 'React', :path => '../node_modules/react-native', :subspecs => [ +'Core', +'RCTImage', +'RCTNetwork', +'RCTText', +'RCTWebSocket' +] + +pod 'react-native-image-crop-picker', :path => '../../ios' + +end + +target 'exampleTests' do + +end + diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock new file mode 100644 index 000000000..328846186 --- /dev/null +++ b/example/ios/Podfile.lock @@ -0,0 +1,44 @@ +PODS: + - QBImagePickerController (3.4.0) + - React (0.25.1): + - React/Core (= 0.25.1) + - react-native-image-crop-picker (0.2.0): + - QBImagePickerController + - React + - RSKImageCropper + - UIImage-Resize (~> 1.0) + - React/Core (0.25.1) + - React/RCTImage (0.25.1): + - React/Core + - React/RCTNetwork + - React/RCTNetwork (0.25.1): + - React/Core + - React/RCTText (0.25.1): + - React/Core + - React/RCTWebSocket (0.25.1): + - React/Core + - RSKImageCropper (1.5.1) + - UIImage-Resize (1.0.1) + +DEPENDENCIES: + - react-native-image-crop-picker (from `../../ios`) + - React/Core (from `../node_modules/react-native`) + - React/RCTImage (from `../node_modules/react-native`) + - React/RCTNetwork (from `../node_modules/react-native`) + - React/RCTText (from `../node_modules/react-native`) + - React/RCTWebSocket (from `../node_modules/react-native`) + +EXTERNAL SOURCES: + React: + :path: ../node_modules/react-native + react-native-image-crop-picker: + :path: ../../ios + +SPEC CHECKSUMS: + QBImagePickerController: d54cf93db6decf26baf6ed3472f336ef35cae022 + React: b35b2b2e07273da1f7266ab2975e0d1033bd913d + react-native-image-crop-picker: 835e9ecacf63b0aedead841ce3e1da2028cf6917 + RSKImageCropper: edd65fedb3734332818deb139906d6b7f54b8a44 + UIImage-Resize: fa776860f10e6900bbaf53a73e494bdceaaccc77 + +COCOAPODS: 0.39.0 diff --git a/example/ios/example.xcodeproj/project.pbxproj b/example/ios/example.xcodeproj/project.pbxproj new file mode 100644 index 000000000..bbbd38f79 --- /dev/null +++ b/example/ios/example.xcodeproj/project.pbxproj @@ -0,0 +1,544 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 00E356F31AD99517003FC87E /* exampleTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 00E356F21AD99517003FC87E /* exampleTests.m */; }; + 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 */; }; + 417020CA0E8449695DCE5F97 /* libPods-example.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 302C8E2A4F507A8E37AB06E9 /* libPods-example.a */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 00E356F41AD99517003FC87E /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 83CBB9F71A601CBA00E9B192 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 13B07F861A680F5B00A75B9A; + remoteInfo = example; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXFileReference section */ + 008F07F21AC5B25A0029DE68 /* main.jsbundle */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = main.jsbundle; sourceTree = ""; }; + 00E356EE1AD99517003FC87E /* exampleTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = exampleTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 00E356F11AD99517003FC87E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 00E356F21AD99517003FC87E /* exampleTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = exampleTests.m; sourceTree = ""; }; + 13B07F961A680F5B00A75B9A /* example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = example.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 13B07FAF1A68108700A75B9A /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = example/AppDelegate.h; sourceTree = ""; }; + 13B07FB01A68108700A75B9A /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AppDelegate.m; path = example/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 = example/Images.xcassets; sourceTree = ""; }; + 13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = example/Info.plist; sourceTree = ""; }; + 13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = example/main.m; sourceTree = ""; }; + 302C8E2A4F507A8E37AB06E9 /* libPods-example.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-example.a"; sourceTree = BUILT_PRODUCTS_DIR; }; + E533556A6EBCA3262E4F7D0E /* Pods-example.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-example.release.xcconfig"; path = "Pods/Target Support Files/Pods-example/Pods-example.release.xcconfig"; sourceTree = ""; }; + F1958A2AE62F046351294BCA /* Pods-example.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-example.debug.xcconfig"; path = "Pods/Target Support Files/Pods-example/Pods-example.debug.xcconfig"; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 00E356EB1AD99517003FC87E /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 13B07F8C1A680F5B00A75B9A /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 417020CA0E8449695DCE5F97 /* libPods-example.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 00E356EF1AD99517003FC87E /* exampleTests */ = { + isa = PBXGroup; + children = ( + 00E356F21AD99517003FC87E /* exampleTests.m */, + 00E356F01AD99517003FC87E /* Supporting Files */, + ); + path = exampleTests; + sourceTree = ""; + }; + 00E356F01AD99517003FC87E /* Supporting Files */ = { + isa = PBXGroup; + children = ( + 00E356F11AD99517003FC87E /* Info.plist */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; + 13B07FAE1A68108700A75B9A /* example */ = { + isa = PBXGroup; + children = ( + 008F07F21AC5B25A0029DE68 /* main.jsbundle */, + 13B07FAF1A68108700A75B9A /* AppDelegate.h */, + 13B07FB01A68108700A75B9A /* AppDelegate.m */, + 13B07FB51A68108700A75B9A /* Images.xcassets */, + 13B07FB61A68108700A75B9A /* Info.plist */, + 13B07FB11A68108700A75B9A /* LaunchScreen.xib */, + 13B07FB71A68108700A75B9A /* main.m */, + ); + name = example; + sourceTree = ""; + }; + 832341AE1AAA6A7D00B99B32 /* Libraries */ = { + isa = PBXGroup; + children = ( + ); + name = Libraries; + sourceTree = ""; + }; + 83CBB9F61A601CBA00E9B192 = { + isa = PBXGroup; + children = ( + 13B07FAE1A68108700A75B9A /* example */, + 832341AE1AAA6A7D00B99B32 /* Libraries */, + 00E356EF1AD99517003FC87E /* exampleTests */, + 83CBBA001A601CBA00E9B192 /* Products */, + F7B6AE37FC56969E5D7A6B11 /* Pods */, + DE3EF9D0A1F93DBCBB69F68A /* Frameworks */, + ); + indentWidth = 2; + sourceTree = ""; + tabWidth = 2; + }; + 83CBBA001A601CBA00E9B192 /* Products */ = { + isa = PBXGroup; + children = ( + 13B07F961A680F5B00A75B9A /* example.app */, + 00E356EE1AD99517003FC87E /* exampleTests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + DE3EF9D0A1F93DBCBB69F68A /* Frameworks */ = { + isa = PBXGroup; + children = ( + 302C8E2A4F507A8E37AB06E9 /* libPods-example.a */, + ); + name = Frameworks; + sourceTree = ""; + }; + F7B6AE37FC56969E5D7A6B11 /* Pods */ = { + isa = PBXGroup; + children = ( + F1958A2AE62F046351294BCA /* Pods-example.debug.xcconfig */, + E533556A6EBCA3262E4F7D0E /* Pods-example.release.xcconfig */, + ); + name = Pods; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 00E356ED1AD99517003FC87E /* exampleTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 00E357021AD99517003FC87E /* Build configuration list for PBXNativeTarget "exampleTests" */; + buildPhases = ( + 00E356EA1AD99517003FC87E /* Sources */, + 00E356EB1AD99517003FC87E /* Frameworks */, + 00E356EC1AD99517003FC87E /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 00E356F51AD99517003FC87E /* PBXTargetDependency */, + ); + name = exampleTests; + productName = exampleTests; + productReference = 00E356EE1AD99517003FC87E /* exampleTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + 13B07F861A680F5B00A75B9A /* example */ = { + isa = PBXNativeTarget; + buildConfigurationList = 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "example" */; + buildPhases = ( + 142C452B1883D1A87E76905A /* Check Pods Manifest.lock */, + 13B07F871A680F5B00A75B9A /* Sources */, + 13B07F8C1A680F5B00A75B9A /* Frameworks */, + 13B07F8E1A680F5B00A75B9A /* Resources */, + 00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */, + 03E7B54AF0F528D2F8813E90 /* Embed Pods Frameworks */, + F0A45B62662A5D43F222910D /* Copy Pods Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = example; + productName = "Hello World"; + productReference = 13B07F961A680F5B00A75B9A /* example.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 83CBB9F71A601CBA00E9B192 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0730; + ORGANIZATIONNAME = Facebook; + TargetAttributes = { + 00E356ED1AD99517003FC87E = { + CreatedOnToolsVersion = 6.2; + TestTargetID = 13B07F861A680F5B00A75B9A; + }; + }; + }; + buildConfigurationList = 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "example" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 83CBB9F61A601CBA00E9B192; + productRefGroup = 83CBBA001A601CBA00E9B192 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 13B07F861A680F5B00A75B9A /* example */, + 00E356ED1AD99517003FC87E /* exampleTests */, + ); + }; +/* End PBXProject 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"; + }; + 03E7B54AF0F528D2F8813E90 /* 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-example/Pods-example-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + 142C452B1883D1A87E76905A /* 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; + }; + F0A45B62662A5D43F222910D /* 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-example/Pods-example-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 00E356EA1AD99517003FC87E /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 00E356F31AD99517003FC87E /* exampleTests.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 13B07F871A680F5B00A75B9A /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 13B07FBC1A68108700A75B9A /* AppDelegate.m in Sources */, + 13B07FC11A68108700A75B9A /* main.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 00E356F51AD99517003FC87E /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 13B07F861A680F5B00A75B9A /* example */; + targetProxy = 00E356F41AD99517003FC87E /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + 13B07FB11A68108700A75B9A /* LaunchScreen.xib */ = { + isa = PBXVariantGroup; + children = ( + 13B07FB21A68108700A75B9A /* Base */, + ); + name = LaunchScreen.xib; + path = example; + 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 = exampleTests/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 8.2; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)"; + PRODUCT_NAME = "$(TARGET_NAME)"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/example.app/example"; + }; + 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 = exampleTests/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 8.2; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)"; + PRODUCT_NAME = "$(TARGET_NAME)"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/example.app/example"; + }; + name = Release; + }; + 13B07F941A680F5B00A75B9A /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = F1958A2AE62F046351294BCA /* Pods-example.debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + 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 = example/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + OTHER_LDFLAGS = ( + "-ObjC", + "$(inherited)", + ); + PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)"; + PRODUCT_NAME = example; + }; + name = Debug; + }; + 13B07F951A680F5B00A75B9A /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = E533556A6EBCA3262E4F7D0E /* Pods-example.release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, + "$(SRCROOT)/../node_modules/react-native/React/**", + ); + INFOPLIST_FILE = example/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + OTHER_LDFLAGS = ( + "-ObjC", + "$(inherited)", + ); + PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)"; + PRODUCT_NAME = example; + }; + 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; + ENABLE_TESTABILITY = 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 "exampleTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 00E356F61AD99517003FC87E /* Debug */, + 00E356F71AD99517003FC87E /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "example" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 13B07F941A680F5B00A75B9A /* Debug */, + 13B07F951A680F5B00A75B9A /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "example" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 83CBBA201A601CBA00E9B192 /* Debug */, + 83CBBA211A601CBA00E9B192 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 83CBB9F71A601CBA00E9B192 /* Project object */; +} diff --git a/example/ios/example.xcodeproj/xcshareddata/xcschemes/example.xcscheme b/example/ios/example.xcodeproj/xcshareddata/xcschemes/example.xcscheme new file mode 100644 index 000000000..83c8729f3 --- /dev/null +++ b/example/ios/example.xcodeproj/xcshareddata/xcschemes/example.xcscheme @@ -0,0 +1,115 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/example/ios/example.xcworkspace/contents.xcworkspacedata b/example/ios/example.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..7f5c3aab5 --- /dev/null +++ b/example/ios/example.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/example/ios/example.xcworkspace/xcshareddata/example.xcscmblueprint b/example/ios/example.xcworkspace/xcshareddata/example.xcscmblueprint new file mode 100644 index 000000000..d9ede37e6 --- /dev/null +++ b/example/ios/example.xcworkspace/xcshareddata/example.xcscmblueprint @@ -0,0 +1,30 @@ +{ + "DVTSourceControlWorkspaceBlueprintPrimaryRemoteRepositoryKey" : "1C9524A6289E62D7AD24253A60749234C5B5991B", + "DVTSourceControlWorkspaceBlueprintWorkingCopyRepositoryLocationsKey" : { + + }, + "DVTSourceControlWorkspaceBlueprintWorkingCopyStatesKey" : { + "1C9524A6289E62D7AD24253A60749234C5B5991B" : 0, + "70F8ECE2EBC921B30FAAC42DFF3269CDD79B3E93" : 0 + }, + "DVTSourceControlWorkspaceBlueprintIdentifierKey" : "A193AD17-2A35-4862-8D44-BBBFF06F7291", + "DVTSourceControlWorkspaceBlueprintWorkingCopyPathsKey" : { + "1C9524A6289E62D7AD24253A60749234C5B5991B" : "react-native-image-crop-picker\/", + "70F8ECE2EBC921B30FAAC42DFF3269CDD79B3E93" : "..\/..\/..\/.." + }, + "DVTSourceControlWorkspaceBlueprintNameKey" : "example", + "DVTSourceControlWorkspaceBlueprintVersion" : 204, + "DVTSourceControlWorkspaceBlueprintRelativePathToProjectKey" : "example\/ios\/example.xcworkspace", + "DVTSourceControlWorkspaceBlueprintRemoteRepositoriesKey" : [ + { + "DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "github.com:ivpusic\/react-native-image-crop-picker.git", + "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git", + "DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "1C9524A6289E62D7AD24253A60749234C5B5991B" + }, + { + "DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "github.com:ivpusic\/wissprs.git", + "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git", + "DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "70F8ECE2EBC921B30FAAC42DFF3269CDD79B3E93" + } + ] +} \ No newline at end of file diff --git a/example/ios/example/AppDelegate.h b/example/ios/example/AppDelegate.h new file mode 100644 index 000000000..a9654d5e0 --- /dev/null +++ b/example/ios/example/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/example/ios/example/AppDelegate.m b/example/ios/example/AppDelegate.m new file mode 100644 index 000000000..2c4750abc --- /dev/null +++ b/example/ios/example/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:@"example" + 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/example/ios/example/Base.lproj/LaunchScreen.xib b/example/ios/example/Base.lproj/LaunchScreen.xib new file mode 100644 index 000000000..201e8e0df --- /dev/null +++ b/example/ios/example/Base.lproj/LaunchScreen.xib @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/example/ios/example/Images.xcassets/AppIcon.appiconset/Contents.json b/example/ios/example/Images.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 000000000..118c98f74 --- /dev/null +++ b/example/ios/example/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/example/ios/example/Info.plist b/example/ios/example/Info.plist new file mode 100644 index 000000000..682480a6e --- /dev/null +++ b/example/ios/example/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/example/ios/example/main.m b/example/ios/example/main.m new file mode 100644 index 000000000..3d767fcbb --- /dev/null +++ b/example/ios/example/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/example/ios/exampleTests/Info.plist b/example/ios/exampleTests/Info.plist new file mode 100644 index 000000000..ba72822e8 --- /dev/null +++ b/example/ios/exampleTests/Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + + diff --git a/example/ios/exampleTests/exampleTests.m b/example/ios/exampleTests/exampleTests.m new file mode 100644 index 000000000..4a4c307c7 --- /dev/null +++ b/example/ios/exampleTests/exampleTests.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 600 +#define TEXT_TO_LOOK_FOR @"Welcome to React Native!" + +@interface exampleTests : XCTestCase + +@end + +@implementation exampleTests + +- (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/example/package.json b/example/package.json new file mode 100644 index 000000000..95879d7a3 --- /dev/null +++ b/example/package.json @@ -0,0 +1,12 @@ +{ + "name": "example", + "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.25.1" + } +} diff --git a/images/android_crop.png b/images/android_crop.png new file mode 100644 index 000000000..840cc8119 Binary files /dev/null and b/images/android_crop.png differ diff --git a/images/android_multiple.png b/images/android_multiple.png new file mode 100644 index 000000000..a0e11419d Binary files /dev/null and b/images/android_multiple.png differ diff --git a/images/android_single_pick.png b/images/android_single_pick.png new file mode 100644 index 000000000..34a8e925f Binary files /dev/null and b/images/android_single_pick.png differ diff --git a/images/ios_crop.png b/images/ios_crop.png new file mode 100644 index 000000000..dff7da49c Binary files /dev/null and b/images/ios_crop.png differ diff --git a/images/ios_multiple_pick.png b/images/ios_multiple_pick.png new file mode 100644 index 000000000..becc3964a Binary files /dev/null and b/images/ios_multiple_pick.png differ diff --git a/images/ios_single_pick.png b/images/ios_single_pick.png new file mode 100644 index 000000000..e6e7f4f54 Binary files /dev/null and b/images/ios_single_pick.png differ diff --git a/index.js b/index.js new file mode 100644 index 000000000..acc02f98c --- /dev/null +++ b/index.js @@ -0,0 +1,4 @@ +import React from 'react'; + +import {NativeModules} from 'react-native'; +export default NativeModules.ImageCropPicker; diff --git a/ios/ImageCropPicker.h b/ios/ImageCropPicker.h new file mode 100644 index 000000000..9b0b6fe80 --- /dev/null +++ b/ios/ImageCropPicker.h @@ -0,0 +1,31 @@ +// +// ImageManager.h +// +// Created by Ivan Pusic on 5/4/16. +// Copyright © 2016 Facebook. All rights reserved. +// + +#ifndef RN_GoogleSigning_h +#define RN_GoogleSigning_h + +#import +#import "RCTBridgeModule.h" +#import "RCTLog.h" +#import +#import +#import "UIImage+Resize.h" + +@interface ImageCropPicker : NSObject< + RCTBridgeModule, + QBImagePickerControllerDelegate, + RSKImageCropViewControllerDelegate, + RSKImageCropViewControllerDataSource> + +@property (nonatomic, strong) NSDictionary *defaultOptions; +@property (nonatomic, retain) NSMutableDictionary *options; +@property (nonatomic, strong) RCTPromiseResolveBlock resolve; +@property (nonatomic, strong) RCTPromiseRejectBlock reject; + +@end + +#endif diff --git a/ios/ImageCropPicker.m b/ios/ImageCropPicker.m new file mode 100644 index 000000000..7785ba718 --- /dev/null +++ b/ios/ImageCropPicker.m @@ -0,0 +1,234 @@ +// +// ImageManager.m +// +// Created by Ivan Pusic on 5/4/16. +// Copyright © 2016 Facebook. All rights reserved. +// + +#import "ImageCropPicker.h" + + +@implementation ImageCropPicker + +RCT_EXPORT_MODULE(); + + +- (instancetype)init +{ + if (self = [super init]) { + self.defaultOptions = @{ + @"multiple": @NO, + @"cropping": @NO, + @"maxFiles": @5, + @"width": @200, + @"height": @200 + }; + } + + return self; +} + +RCT_EXPORT_METHOD(openPicker:(NSDictionary *)options + resolver:(RCTPromiseResolveBlock)resolve + rejecter:(RCTPromiseRejectBlock)reject) { + + self.resolve = resolve; + self.reject = reject; + self.options = [NSMutableDictionary dictionaryWithDictionary:self.defaultOptions]; + for (NSString *key in options.keyEnumerator) { + [self.options setValue:options[key] forKey:key]; + } + + [PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) { + dispatch_async(dispatch_get_main_queue(), ^{ + // init picker + QBImagePickerController *imagePickerController = + [QBImagePickerController new]; + imagePickerController.delegate = self; + imagePickerController.allowsMultipleSelection = [[self.options objectForKey:@"multiple"] boolValue]; + imagePickerController.maximumNumberOfSelection = [[self.options objectForKey:@"maxFiles"] intValue]; + imagePickerController.showsNumberOfSelectedAssets = YES; + + UIViewController *root = [[[[UIApplication sharedApplication] delegate] + window] rootViewController]; + [root presentViewController:imagePickerController + animated:YES + completion:NULL]; + }); + }]; +} + +- (void)qb_imagePickerController: +(QBImagePickerController *)imagePickerController + didFinishPickingAssets:(NSArray *)assets { + + PHImageManager *manager = [PHImageManager defaultManager]; + + if ([[[self options] objectForKey:@"multiple"] boolValue]) { + NSMutableArray *images = [[NSMutableArray alloc] init]; + PHImageRequestOptions* options = [[PHImageRequestOptions alloc] init]; + options.synchronous = YES; + + for (PHAsset *asset in assets) { + [manager + requestImageDataForAsset:asset + options:options + resultHandler:^(NSData *imageData, NSString *dataUTI, UIImageOrientation orientation, NSDictionary *info) { + NSURL *imageURL = [info valueForKey:@"PHImageFileURLKey"]; + [images addObject:@{ + @"path": [imageURL absoluteString], + @"width": @(asset.pixelWidth), + @"height": @(asset.pixelHeight) + }]; + }]; + } + + self.resolve(images); + [imagePickerController dismissViewControllerAnimated:YES completion:nil]; + } else { + PHAsset *asset = [assets objectAtIndex:0]; + + [manager + requestImageDataForAsset:asset + options:nil + resultHandler:^(NSData *imageData, NSString *dataUTI, + UIImageOrientation orientation, + NSDictionary *info) { + + if ([[[self options] objectForKey:@"cropping"] boolValue]) { + UIImage *image = [UIImage imageWithData:imageData]; + RSKImageCropViewController *imageCropVC = [[RSKImageCropViewController alloc] initWithImage:image cropMode:RSKImageCropModeCustom]; + + imageCropVC.avoidEmptySpaceAroundImage = YES; + imageCropVC.dataSource = self; + imageCropVC.delegate = self; + + UIViewController *root = [[[[UIApplication sharedApplication] delegate] window] rootViewController]; + [imagePickerController dismissViewControllerAnimated:YES completion:nil]; + [root presentViewController:imageCropVC animated:YES completion:nil]; + } else { + NSURL *imageURL = [info valueForKey:@"PHImageFileURLKey"]; + self.resolve(@{ + @"path": [imageURL absoluteString], + @"width": @(asset.pixelWidth), + @"height": @(asset.pixelHeight) + }); + [imagePickerController dismissViewControllerAnimated:YES completion:nil]; + } + }]; + } +} + +- (void)qb_imagePickerControllerDidCancel:(QBImagePickerController *)imagePickerController { + [imagePickerController dismissViewControllerAnimated:YES completion:nil]; +} + +#pragma mark - CustomCropModeDelegates + +// Returns a custom rect for the mask. +- (CGRect)imageCropViewControllerCustomMaskRect: +(RSKImageCropViewController *)controller { + CGSize maskSize = CGSizeMake( + [[self.options objectForKey:@"width"] intValue], + [[self.options objectForKey:@"height"] intValue]); + + CGFloat viewWidth = CGRectGetWidth(controller.view.frame); + CGFloat viewHeight = CGRectGetHeight(controller.view.frame); + + CGRect maskRect = CGRectMake((viewWidth - maskSize.width) * 0.5f, + (viewHeight - maskSize.height) * 0.5f, + maskSize.width, maskSize.height); + + return maskRect; +} + +// if provided width or height is bigger than screen w/h, +// then we should scale draw area +- (CGRect) scaleRect:(RSKImageCropViewController *)controller { + CGRect rect = controller.maskRect; + CGFloat viewWidth = CGRectGetWidth(controller.view.frame); + CGFloat viewHeight = CGRectGetHeight(controller.view.frame); + + if (rect.size.width > viewWidth) { + float scaleFactor = viewWidth / rect.size.width; + rect.size.width *= scaleFactor; + rect.size.height *= scaleFactor; + rect.origin.x = 0; + rect.origin.y = viewHeight / 2 * 0.5f; + } else if (rect.size.height > viewHeight) { + float scaleFactor = viewHeight / rect.size.height; + rect.size.width *= scaleFactor; + rect.size.height *= scaleFactor; + rect.origin.x = viewWidth / 2 * 0.5f; + rect.origin.y = 0; + } + + return rect; +} + +// Returns a custom path for the mask. +- (UIBezierPath *)imageCropViewControllerCustomMaskPath: +(RSKImageCropViewController *)controller { + CGRect rect = [self scaleRect:controller]; + UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:rect + byRoundingCorners:UIRectCornerAllCorners + cornerRadii:CGSizeMake(0, 0)]; + return path; +} + +// Returns a custom rect in which the image can be moved. +- (CGRect)imageCropViewControllerCustomMovementRect: +(RSKImageCropViewController *)controller { + return [self scaleRect:controller]; +} + +#pragma mark - CropFinishDelegate + +// Crop image has been canceled. +- (void)imageCropViewControllerDidCancelCrop: +(RSKImageCropViewController *)controller { + [controller dismissViewControllerAnimated:YES completion:nil]; +} + +// The original image has been cropped. +- (void)imageCropViewController:(RSKImageCropViewController *)controller + didCropImage:(UIImage *)croppedImage + usingCropRect:(CGRect)cropRect { + + // create temp file + NSString *filePath = [NSTemporaryDirectory() stringByAppendingString:[[NSUUID UUID] UUIDString]]; + filePath = [filePath stringByAppendingString:@".png"]; + + // we have correct rect, but not correct dimensions + // so resize image + CGSize resizedImageSize = CGSizeMake([[[self options] objectForKey:@"width"] intValue], [[[self options] objectForKey:@"height"] intValue]); + UIImage *resizedImage = [croppedImage resizedImageToFitInSize:resizedImageSize scaleIfSmaller:YES]; + NSData *data = UIImageJPEGRepresentation(resizedImage, 1); + + // save cropped file + BOOL status = [data writeToFile:filePath atomically:YES]; + if (!status) { + self.reject(@"cannot_save_image", @"Cannot save image", nil); + return; + } + + NSDictionary *image = @{ + @"path": filePath, + @"width": @(resizedImage.size.width), + @"height": @(resizedImage.size.height) + }; + + self.resolve(image); + [controller dismissViewControllerAnimated:YES completion:nil]; +} + +// The original image has been cropped. Additionally provides a rotation angle +// used to produce image. +- (void)imageCropViewController:(RSKImageCropViewController *)controller + didCropImage:(UIImage *)croppedImage + usingCropRect:(CGRect)cropRect + rotationAngle:(CGFloat)rotationAngle { + [self imageCropViewController:controller didCropImage:croppedImage usingCropRect:cropRect]; +} + +@end diff --git a/ios/Podfile b/ios/Podfile new file mode 100644 index 000000000..9d3ee7a92 --- /dev/null +++ b/ios/Podfile @@ -0,0 +1,11 @@ +# 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 'ios' do + pod 'React', :path => '../node_modules/react-native' + pod 'QBImagePickerController', '3.4.0' + pod 'RSKImageCropper', '1.5.1' + pod 'UIImage-Resize', '~> 1.0' +end diff --git a/ios/Podfile.lock b/ios/Podfile.lock new file mode 100644 index 000000000..c47b9e050 --- /dev/null +++ b/ios/Podfile.lock @@ -0,0 +1,25 @@ +PODS: + - QBImagePickerController (3.4.0) + - React (0.25.1): + - React/Core (= 0.25.1) + - React/Core (0.25.1) + - RSKImageCropper (1.5.1) + - UIImage-Resize (1.0.1) + +DEPENDENCIES: + - QBImagePickerController (= 3.4.0) + - React (from `../node_modules/react-native`) + - RSKImageCropper (= 1.5.1) + - UIImage-Resize (~> 1.0) + +EXTERNAL SOURCES: + React: + :path: ../node_modules/react-native + +SPEC CHECKSUMS: + QBImagePickerController: d54cf93db6decf26baf6ed3472f336ef35cae022 + React: b35b2b2e07273da1f7266ab2975e0d1033bd913d + RSKImageCropper: edd65fedb3734332818deb139906d6b7f54b8a44 + UIImage-Resize: fa776860f10e6900bbaf53a73e494bdceaaccc77 + +COCOAPODS: 0.39.0 diff --git a/ios/ios.xcodeproj/project.pbxproj b/ios/ios.xcodeproj/project.pbxproj new file mode 100644 index 000000000..5ca991f91 --- /dev/null +++ b/ios/ios.xcodeproj/project.pbxproj @@ -0,0 +1,585 @@ + + + + + archiveVersion + 1 + classes + + objectVersion + 46 + objects + + 05ED982300309570595E6415 + + fileRef + 1BD68D2BA210764F2B45A9E8 + isa + PBXBuildFile + + 1BD68D2BA210764F2B45A9E8 + + explicitFileType + archive.ar + includeInIndex + 0 + isa + PBXFileReference + path + libPods.a + sourceTree + BUILT_PRODUCTS_DIR + + 1F2C7A7F1CD107249FB80C39 + + buildActionMask + 2147483647 + files + + inputPaths + + isa + PBXShellScriptBuildPhase + name + Check Pods Manifest.lock + outputPaths + + runOnlyForDeploymentPostprocessing + 0 + shellPath + /bin/sh + shellScript + diff "${PODS_ROOT}/../Podfile.lock" "${PODS_ROOT}/Manifest.lock" > /dev/null +if [[ $? != 0 ]] ; then + cat << EOM +error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation. +EOM + exit 1 +fi + + showEnvVarsInLog + 0 + + 28D0F40878CF442B0366B8BD + + explicitFileType + archive.ar + includeInIndex + 0 + isa + PBXFileReference + path + libPods-ios.a + sourceTree + BUILT_PRODUCTS_DIR + + 3400A7FF1CEB54A6008A0BC7 + + children + + 3400A8141CEB54F3008A0BC7 + 3400A8151CEB54F3008A0BC7 + 3400A8091CEB54A6008A0BC7 + DE9F36C10D014D61FADE41D2 + 65C0726CDFB1FE151957AC17 + + isa + PBXGroup + sourceTree + <group> + + 3400A8001CEB54A6008A0BC7 + + attributes + + LastUpgradeCheck + 0730 + ORGANIZATIONNAME + Ivan Pusic + TargetAttributes + + 3400A8071CEB54A6008A0BC7 + + CreatedOnToolsVersion + 7.3.1 + + + + buildConfigurationList + 3400A8031CEB54A6008A0BC7 + compatibilityVersion + Xcode 3.2 + developmentRegion + English + hasScannedForEncodings + 0 + isa + PBXProject + knownRegions + + en + + mainGroup + 3400A7FF1CEB54A6008A0BC7 + productRefGroup + 3400A8091CEB54A6008A0BC7 + projectDirPath + + projectReferences + + projectRoot + + targets + + 3400A8071CEB54A6008A0BC7 + + + 3400A8031CEB54A6008A0BC7 + + buildConfigurations + + 3400A80F1CEB54A6008A0BC7 + 3400A8101CEB54A6008A0BC7 + + defaultConfigurationIsVisible + 0 + defaultConfigurationName + Release + isa + XCConfigurationList + + 3400A8041CEB54A6008A0BC7 + + buildActionMask + 2147483647 + files + + 3400A8161CEB54F3008A0BC7 + + isa + PBXSourcesBuildPhase + runOnlyForDeploymentPostprocessing + 0 + + 3400A8051CEB54A6008A0BC7 + + buildActionMask + 2147483647 + files + + 7C2FA32BD238084092BADC62 + 05ED982300309570595E6415 + + isa + PBXFrameworksBuildPhase + runOnlyForDeploymentPostprocessing + 0 + + 3400A8061CEB54A6008A0BC7 + + buildActionMask + 2147483647 + dstPath + include/$(PRODUCT_NAME) + dstSubfolderSpec + 16 + files + + isa + PBXCopyFilesBuildPhase + runOnlyForDeploymentPostprocessing + 0 + + 3400A8071CEB54A6008A0BC7 + + buildConfigurationList + 3400A8111CEB54A6008A0BC7 + buildPhases + + 1F2C7A7F1CD107249FB80C39 + 3400A8041CEB54A6008A0BC7 + 3400A8051CEB54A6008A0BC7 + 3400A8061CEB54A6008A0BC7 + B7013FD691B18B2F86EDB78C + + buildRules + + dependencies + + isa + PBXNativeTarget + name + ios + productName + picker + productReference + 3400A8081CEB54A6008A0BC7 + productType + com.apple.product-type.library.static + + 3400A8081CEB54A6008A0BC7 + + explicitFileType + archive.ar + includeInIndex + 0 + isa + PBXFileReference + path + libios.a + sourceTree + BUILT_PRODUCTS_DIR + + 3400A8091CEB54A6008A0BC7 + + children + + 3400A8081CEB54A6008A0BC7 + + isa + PBXGroup + name + Products + sourceTree + <group> + + 3400A80F1CEB54A6008A0BC7 + + buildSettings + + ALWAYS_SEARCH_USER_PATHS + NO + CLANG_ANALYZER_NONNULL + YES + 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 + DEBUG_INFORMATION_FORMAT + dwarf + ENABLE_STRICT_OBJC_MSGSEND + YES + ENABLE_TESTABILITY + YES + GCC_C_LANGUAGE_STANDARD + gnu99 + GCC_DYNAMIC_NO_PIC + NO + GCC_NO_COMMON_BLOCKS + YES + GCC_OPTIMIZATION_LEVEL + 0 + GCC_PREPROCESSOR_DEFINITIONS + + DEBUG=1 + $(inherited) + + GCC_WARN_64_TO_32_BIT_CONVERSION + YES + GCC_WARN_ABOUT_RETURN_TYPE + YES_ERROR + GCC_WARN_UNDECLARED_SELECTOR + YES + GCC_WARN_UNINITIALIZED_AUTOS + YES_AGGRESSIVE + GCC_WARN_UNUSED_FUNCTION + YES + GCC_WARN_UNUSED_VARIABLE + YES + IPHONEOS_DEPLOYMENT_TARGET + 9.3 + MTL_ENABLE_DEBUG_INFO + YES + ONLY_ACTIVE_ARCH + YES + SDKROOT + iphoneos + + isa + XCBuildConfiguration + name + Debug + + 3400A8101CEB54A6008A0BC7 + + buildSettings + + ALWAYS_SEARCH_USER_PATHS + NO + CLANG_ANALYZER_NONNULL + YES + 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 + DEBUG_INFORMATION_FORMAT + dwarf-with-dsym + ENABLE_NS_ASSERTIONS + NO + ENABLE_STRICT_OBJC_MSGSEND + YES + GCC_C_LANGUAGE_STANDARD + gnu99 + GCC_NO_COMMON_BLOCKS + YES + GCC_WARN_64_TO_32_BIT_CONVERSION + YES + GCC_WARN_ABOUT_RETURN_TYPE + YES_ERROR + GCC_WARN_UNDECLARED_SELECTOR + YES + GCC_WARN_UNINITIALIZED_AUTOS + YES_AGGRESSIVE + GCC_WARN_UNUSED_FUNCTION + YES + GCC_WARN_UNUSED_VARIABLE + YES + IPHONEOS_DEPLOYMENT_TARGET + 9.3 + MTL_ENABLE_DEBUG_INFO + NO + SDKROOT + iphoneos + VALIDATE_PRODUCT + YES + + isa + XCBuildConfiguration + name + Release + + 3400A8111CEB54A6008A0BC7 + + buildConfigurations + + 3400A8121CEB54A6008A0BC7 + 3400A8131CEB54A6008A0BC7 + + defaultConfigurationIsVisible + 0 + defaultConfigurationName + Release + isa + XCConfigurationList + + 3400A8121CEB54A6008A0BC7 + + baseConfigurationReference + 5334DE9EC8523E00C03E7B1F + buildSettings + + OTHER_LDFLAGS + + -ObjC + $(inherited) + + PRODUCT_NAME + ios + SKIP_INSTALL + YES + + isa + XCBuildConfiguration + name + Debug + + 3400A8131CEB54A6008A0BC7 + + baseConfigurationReference + 7AD9B365910E1EAA1889FC3C + buildSettings + + OTHER_LDFLAGS + + -ObjC + $(inherited) + + PRODUCT_NAME + ios + SKIP_INSTALL + YES + + isa + XCBuildConfiguration + name + Release + + 3400A8141CEB54F3008A0BC7 + + fileEncoding + 4 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + path + ImageCropPicker.h + sourceTree + <group> + + 3400A8151CEB54F3008A0BC7 + + fileEncoding + 4 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.objc + path + ImageCropPicker.m + sourceTree + <group> + + 3400A8161CEB54F3008A0BC7 + + fileRef + 3400A8151CEB54F3008A0BC7 + isa + PBXBuildFile + + 5334DE9EC8523E00C03E7B1F + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + text.xcconfig + name + Pods-ios.debug.xcconfig + path + Pods/Target Support Files/Pods-ios/Pods-ios.debug.xcconfig + sourceTree + <group> + + 65C0726CDFB1FE151957AC17 + + children + + 28D0F40878CF442B0366B8BD + 1BD68D2BA210764F2B45A9E8 + + isa + PBXGroup + name + Frameworks + sourceTree + <group> + + 7AD9B365910E1EAA1889FC3C + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + text.xcconfig + name + Pods-ios.release.xcconfig + path + Pods/Target Support Files/Pods-ios/Pods-ios.release.xcconfig + sourceTree + <group> + + 7C2FA32BD238084092BADC62 + + fileRef + 28D0F40878CF442B0366B8BD + isa + PBXBuildFile + + B7013FD691B18B2F86EDB78C + + buildActionMask + 2147483647 + files + + inputPaths + + isa + PBXShellScriptBuildPhase + name + Copy Pods Resources + outputPaths + + runOnlyForDeploymentPostprocessing + 0 + shellPath + /bin/sh + shellScript + "${SRCROOT}/Pods/Target Support Files/Pods-ios/Pods-ios-resources.sh" + + showEnvVarsInLog + 0 + + DE9F36C10D014D61FADE41D2 + + children + + 5334DE9EC8523E00C03E7B1F + 7AD9B365910E1EAA1889FC3C + + isa + PBXGroup + name + Pods + sourceTree + <group> + + + rootObject + 3400A8001CEB54A6008A0BC7 + + diff --git a/ios/ios.xcworkspace/contents.xcworkspacedata b/ios/ios.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..b984d5dd1 --- /dev/null +++ b/ios/ios.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/ios/ios.xcworkspace/xcshareddata/ios.xcscmblueprint b/ios/ios.xcworkspace/xcshareddata/ios.xcscmblueprint new file mode 100644 index 000000000..e02da1a30 --- /dev/null +++ b/ios/ios.xcworkspace/xcshareddata/ios.xcscmblueprint @@ -0,0 +1,30 @@ +{ + "DVTSourceControlWorkspaceBlueprintPrimaryRemoteRepositoryKey" : "E22760A5F9571E7C2A61889FF42B398765F62583", + "DVTSourceControlWorkspaceBlueprintWorkingCopyRepositoryLocationsKey" : { + + }, + "DVTSourceControlWorkspaceBlueprintWorkingCopyStatesKey" : { + "E22760A5F9571E7C2A61889FF42B398765F62583" : 0, + "70F8ECE2EBC921B30FAAC42DFF3269CDD79B3E93" : 0 + }, + "DVTSourceControlWorkspaceBlueprintIdentifierKey" : "433638DA-09E5-4A9C-BAAF-D81A52EB4BEE", + "DVTSourceControlWorkspaceBlueprintWorkingCopyPathsKey" : { + "E22760A5F9571E7C2A61889FF42B398765F62583" : "react-native-image-crop-picker\/", + "70F8ECE2EBC921B30FAAC42DFF3269CDD79B3E93" : "..\/..\/..\/.." + }, + "DVTSourceControlWorkspaceBlueprintNameKey" : "ios", + "DVTSourceControlWorkspaceBlueprintVersion" : 204, + "DVTSourceControlWorkspaceBlueprintRelativePathToProjectKey" : "ios\/ios.xcworkspace", + "DVTSourceControlWorkspaceBlueprintRemoteRepositoriesKey" : [ + { + "DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "github.com:ivpusic\/wissprs.git", + "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git", + "DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "70F8ECE2EBC921B30FAAC42DFF3269CDD79B3E93" + }, + { + "DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "github.com:ivpusic\/react-native-image-crop-picker.git", + "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git", + "DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "E22760A5F9571E7C2A61889FF42B398765F62583" + } + ] +} \ No newline at end of file diff --git a/ios/react-native-image-crop-picker.podspec b/ios/react-native-image-crop-picker.podspec new file mode 100644 index 000000000..bb0dc3baf --- /dev/null +++ b/ios/react-native-image-crop-picker.podspec @@ -0,0 +1,20 @@ +require 'json' + +package = JSON.parse(File.read(File.join(__dir__, '../package.json'))) + +Pod::Spec.new do |s| + s.name = "react-native-image-crop-picker" + s.version = package['version'] + s.license = "MIT" + s.homepage = "https://github.com/ivpusic/react-native-image-crop-picker" + s.authors = { 'Ivan Pusic' => 'pusic007@gmail.com' } + s.summary = "Select single or multiple images with cropping option" + s.source = { :git => "https://github.com/ivpusic/react-native-image-crop-picker.git", :tag => "v#{s.version}" } + s.source_files = "*.{h,m}" + + s.platform = :ios, "8.0" + s.dependency 'React', '0.25.1' + s.dependency 'QBImagePickerController', '3.4.0' + s.dependency 'RSKImageCropper', '1.5.1' + s.dependency 'UIImage-Resize', '~> 1.0' +end diff --git a/package.json b/package.json new file mode 100644 index 000000000..c15fb8a29 --- /dev/null +++ b/package.json @@ -0,0 +1,32 @@ +{ + "name": "react-native-image-crop-picker", + "version": "0.2.3", + "description": "Select single or multiple images, with croping option", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/ivpusic/react-native-image-crop-picker.git" + }, + "keywords": [ + "react", + "native", + "react-native", + "image", + "picker", + "crop", + "cropping", + "multiple" + ], + "author": "Ivan Pusic", + "license": "MIT", + "bugs": { + "url": "https://github.com/ivpusic/react-native-image-crop-picker/issues" + }, + "homepage": "https://github.com/ivpusic/react-native-image-crop-picker#readme", + "dependencies": { + "react-native": "^0.25.1" + } +}