├── .github
└── FUNDING.yml
├── .gitignore
├── .npmignore
├── AwesomeExample
├── .bundle
│ └── config
├── .eslintrc.js
├── .gitignore
├── .prettierrc.js
├── .watchmanconfig
├── App.tsx
├── Gemfile
├── Gemfile.lock
├── README.md
├── __tests__
│ └── App.test.tsx
├── android
│ ├── app
│ │ ├── build.gradle
│ │ ├── debug.keystore
│ │ ├── proguard-rules.pro
│ │ └── src
│ │ │ ├── debug
│ │ │ └── AndroidManifest.xml
│ │ │ └── main
│ │ │ ├── AndroidManifest.xml
│ │ │ ├── java
│ │ │ └── com
│ │ │ │ └── awesomeexample
│ │ │ │ ├── MainActivity.kt
│ │ │ │ └── MainApplication.kt
│ │ │ └── res
│ │ │ ├── drawable
│ │ │ └── rn_edit_text_material.xml
│ │ │ ├── mipmap-hdpi
│ │ │ ├── ic_launcher.png
│ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-mdpi
│ │ │ ├── ic_launcher.png
│ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-xhdpi
│ │ │ ├── ic_launcher.png
│ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-xxhdpi
│ │ │ ├── ic_launcher.png
│ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-xxxhdpi
│ │ │ ├── ic_launcher.png
│ │ │ └── ic_launcher_round.png
│ │ │ └── values
│ │ │ ├── strings.xml
│ │ │ └── styles.xml
│ ├── build.gradle
│ ├── gradle.properties
│ ├── gradle
│ │ └── wrapper
│ │ │ ├── gradle-wrapper.jar
│ │ │ └── gradle-wrapper.properties
│ ├── gradlew
│ ├── gradlew.bat
│ └── settings.gradle
├── app.json
├── babel.config.js
├── index.js
├── ios
│ ├── .xcode.env
│ ├── AwesomeExample.xcodeproj
│ │ ├── project.pbxproj
│ │ └── xcshareddata
│ │ │ └── xcschemes
│ │ │ └── AwesomeExample.xcscheme
│ ├── AwesomeExample.xcworkspace
│ │ └── contents.xcworkspacedata
│ ├── AwesomeExample
│ │ ├── AppDelegate.swift
│ │ ├── Images.xcassets
│ │ │ ├── AppIcon.appiconset
│ │ │ │ └── Contents.json
│ │ │ └── Contents.json
│ │ ├── Info.plist
│ │ ├── LaunchScreen.storyboard
│ │ └── PrivacyInfo.xcprivacy
│ ├── Podfile
│ └── Podfile.lock
├── jest.config.js
├── metro.config.js
├── package
├── package.json
├── tsconfig.json
└── yarn.lock
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── ISSUE_TEMPLATE.md
├── LICENSE
├── README.md
├── RNImageCropPicker.podspec
├── android
├── android.iml
├── build.gradle
├── gradle
│ └── wrapper
│ │ ├── gradle-wrapper.jar
│ │ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
└── src
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── com
│ │ │ └── reactnative
│ │ │ └── ivpusic
│ │ │ └── imagepicker
│ │ │ ├── Compression.java
│ │ │ ├── ExifExtractor.java
│ │ │ ├── GeoDegree.java
│ │ │ ├── ImageCropPicker.java
│ │ │ ├── IvpusicImagePickerFileProvider.java
│ │ │ ├── PickerPackage.java
│ │ │ ├── RealPathUtil.java
│ │ │ └── ResultCollector.java
│ └── res
│ │ └── xml
│ │ └── ivpusic_imagepicker_provider_paths.xml
│ ├── newArch
│ └── java
│ │ └── com
│ │ └── reactnative
│ │ └── ivpusic
│ │ └── imagepicker
│ │ └── PickerModule.java
│ ├── oldArch
│ └── java
│ │ └── com
│ │ └── reactnative
│ │ └── ivpusic
│ │ └── imagepicker
│ │ └── PickerModule.java
│ └── test
│ └── test.iml
├── images
├── ios_circular_crop.png
├── ios_multiple_pick_v2.png
├── ios_normal_crop.png
└── ios_single_pick_v2.png
├── index.d.ts
├── index.js
├── ios
├── ImageCropPickerSDK
│ └── QBImagePicker.framework
│ │ ├── Headers
│ │ ├── QBImagePicker.h
│ │ └── QBImagePickerController.h
│ │ ├── Info.plist
│ │ ├── Modules
│ │ └── module.modulemap
│ │ ├── QBImagePicker
│ │ ├── QBImagePicker.storyboardc
│ │ ├── Info.plist
│ │ ├── QBAlbumsNavigationController.nib
│ │ ├── QBAlbumsViewController.nib
│ │ ├── QBAssetsViewController.nib
│ │ ├── QL5-wR-LYt-view-66K-TS-Yoc.nib
│ │ └── QiH-NZ-ZGN-view-sD2-zK-ryo.nib
│ │ ├── _CodeSignature
│ │ └── CodeResources
│ │ ├── de.lproj
│ │ └── QBImagePicker.strings
│ │ ├── en.lproj
│ │ └── QBImagePicker.strings
│ │ ├── es.lproj
│ │ └── QBImagePicker.strings
│ │ ├── ja.lproj
│ │ └── QBImagePicker.strings
│ │ ├── pl.lproj
│ │ └── QBImagePicker.strings
│ │ └── zh-Hans.lproj
│ │ └── QBImagePicker.strings
├── PrivacyInfo.xcprivacy
├── QBImagePicker
│ ├── .gitignore
│ ├── LICENSE
│ ├── QBImagePicker.xcodeproj
│ │ ├── project.pbxproj
│ │ └── xcshareddata
│ │ │ └── xcschemes
│ │ │ └── QBImagePicker.xcscheme
│ ├── QBImagePicker
│ │ ├── Info.plist
│ │ ├── QBAlbumCell.h
│ │ ├── QBAlbumCell.m
│ │ ├── QBAlbumsViewController.h
│ │ ├── QBAlbumsViewController.m
│ │ ├── QBAssetCell.h
│ │ ├── QBAssetCell.m
│ │ ├── QBAssetsViewController.h
│ │ ├── QBAssetsViewController.m
│ │ ├── QBCheckmarkView.h
│ │ ├── QBCheckmarkView.m
│ │ ├── QBImagePicker.h
│ │ ├── QBImagePicker.storyboard
│ │ ├── QBImagePickerController.h
│ │ ├── QBImagePickerController.m
│ │ ├── QBSlomoIconView.h
│ │ ├── QBSlomoIconView.m
│ │ ├── QBVideoIconView.h
│ │ ├── QBVideoIconView.m
│ │ ├── QBVideoIndicatorView.h
│ │ ├── QBVideoIndicatorView.m
│ │ ├── da.lproj
│ │ │ └── QBImagePicker.strings
│ │ ├── de.lproj
│ │ │ └── QBImagePicker.strings
│ │ ├── en.lproj
│ │ │ └── QBImagePicker.strings
│ │ ├── es.lproj
│ │ │ └── QBImagePicker.strings
│ │ ├── fi.lproj
│ │ │ └── QBImagePicker.strings
│ │ ├── fr.lproj
│ │ │ └── QBImagePicker.strings
│ │ ├── it.lproj
│ │ │ └── QBImagePicker.strings
│ │ ├── ja.lproj
│ │ │ └── QBImagePicker.strings
│ │ ├── ko.lproj
│ │ │ └── QBImagePicker.strings
│ │ ├── nb.lproj
│ │ │ └── QBImagePicker.strings
│ │ ├── nl.lproj
│ │ │ └── QBImagePicker.strings
│ │ ├── pl.lproj
│ │ │ └── QBImagePicker.strings
│ │ ├── pt.lproj
│ │ │ └── QBImagePicker.strings
│ │ ├── ro.lproj
│ │ │ └── QBImagePicker.strings
│ │ ├── ru.lproj
│ │ │ └── QBImagePicker.strings
│ │ ├── sv.lproj
│ │ │ └── QBImagePicker.strings
│ │ ├── tr.lproj
│ │ │ └── QBImagePicker.strings
│ │ ├── uk.lproj
│ │ │ └── QBImagePicker.strings
│ │ ├── vi.lproj
│ │ │ └── QBImagePicker.strings
│ │ ├── zh-Hans.lproj
│ │ │ └── QBImagePicker.strings
│ │ └── zh-Hant.lproj
│ │ │ └── QBImagePicker.strings
│ └── QBImagePickerController.podspec
├── imageCropPicker.xcodeproj
│ └── project.pbxproj
└── src
│ ├── Compression.h
│ ├── Compression.m
│ ├── ImageCropPicker.h
│ ├── ImageCropPicker.mm
│ ├── UIImage+Extension.h
│ ├── UIImage+Extension.m
│ ├── UIImage+Resize.h
│ └── UIImage+Resize.m
├── package.json
├── src
└── NativeImageCropPicker.ts
├── svg.svg
└── yarn.lock
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | open_collective: react-native-image-crop-picker
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # OSX
2 | #
3 | .DS_Store
4 |
5 | # android studio
6 | *.iml
7 | .idea
8 | .gradle
9 | build/
10 |
11 | # Xcode
12 | #
13 | build/
14 | *.pbxuser
15 | !default.pbxuser
16 | *.mode1v3
17 | !default.mode1v3
18 | *.mode2v3
19 | !default.mode2v3
20 | *.perspectivev3
21 | !default.perspectivev3
22 | xcuserdata
23 | *.xccheckout
24 | *.moved-aside
25 | DerivedData
26 | *.hmap
27 | *.ipa
28 | *.xcuserstate
29 | project.xcworkspace
30 |
31 | # Android/IJ
32 | #
33 | .idea
34 | .gradle
35 | local.properties
36 |
37 | # node.js
38 | #
39 | node_modules/
40 | npm-debug.log
41 |
42 | # BUCK
43 | buck-out/
44 | \.buckd/
45 | android/app/libs
46 | android/keystores/debug.keystore
47 | pods
48 | .vscode
49 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | .git
2 | example
3 | node_modules
4 | build
5 | images
6 |
7 | # android studio
8 | *.iml
9 | .idea
10 | .gradle
11 | build/
--------------------------------------------------------------------------------
/AwesomeExample/.bundle/config:
--------------------------------------------------------------------------------
1 | BUNDLE_PATH: "vendor/bundle"
2 | BUNDLE_FORCE_RUBY_PLATFORM: 1
3 |
--------------------------------------------------------------------------------
/AwesomeExample/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | extends: '@react-native',
4 | };
5 |
--------------------------------------------------------------------------------
/AwesomeExample/.gitignore:
--------------------------------------------------------------------------------
1 | # OSX
2 | #
3 | .DS_Store
4 |
5 | # Xcode
6 | #
7 | build/
8 | *.pbxuser
9 | !default.pbxuser
10 | *.mode1v3
11 | !default.mode1v3
12 | *.mode2v3
13 | !default.mode2v3
14 | *.perspectivev3
15 | !default.perspectivev3
16 | xcuserdata
17 | *.xccheckout
18 | *.moved-aside
19 | DerivedData
20 | *.hmap
21 | *.ipa
22 | *.xcuserstate
23 | **/.xcode.env.local
24 |
25 | # Android/IntelliJ
26 | #
27 | build/
28 | .idea
29 | .gradle
30 | local.properties
31 | *.iml
32 | *.hprof
33 | .cxx/
34 | *.keystore
35 | !debug.keystore
36 | .kotlin/
37 |
38 | # node.js
39 | #
40 | node_modules/
41 | npm-debug.log
42 | yarn-error.log
43 |
44 | # fastlane
45 | #
46 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
47 | # screenshots whenever they are needed.
48 | # For more information about the recommended setup visit:
49 | # https://docs.fastlane.tools/best-practices/source-control/
50 |
51 | **/fastlane/report.xml
52 | **/fastlane/Preview.html
53 | **/fastlane/screenshots
54 | **/fastlane/test_output
55 |
56 | # Bundle artifact
57 | *.jsbundle
58 |
59 | # Ruby / CocoaPods
60 | **/Pods/
61 | /vendor/bundle/
62 |
63 | # Temporary files created by Metro to check the health of the file watcher
64 | .metro-health-check*
65 |
66 | # testing
67 | /coverage
68 |
69 | # Yarn
70 | .yarn/*
71 | !.yarn/patches
72 | !.yarn/plugins
73 | !.yarn/releases
74 | !.yarn/sdks
75 | !.yarn/versions
76 |
--------------------------------------------------------------------------------
/AwesomeExample/.prettierrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | arrowParens: 'avoid',
3 | bracketSameLine: true,
4 | bracketSpacing: false,
5 | singleQuote: true,
6 | trailingComma: 'all',
7 | };
8 |
--------------------------------------------------------------------------------
/AwesomeExample/.watchmanconfig:
--------------------------------------------------------------------------------
1 | {}
2 |
--------------------------------------------------------------------------------
/AwesomeExample/Gemfile:
--------------------------------------------------------------------------------
1 | source 'https://rubygems.org'
2 |
3 | # You may use http://rbenv.org/ or https://rvm.io/ to install and use this version
4 | ruby ">= 2.6.10"
5 |
6 | # Exclude problematic versions of cocoapods and activesupport that causes build failures.
7 | gem 'cocoapods', '>= 1.13', '!= 1.15.0', '!= 1.15.1'
8 | gem 'activesupport', '>= 6.1.7.5', '!= 7.1.0'
9 | gem 'xcodeproj', '< 1.26.0'
10 | gem 'concurrent-ruby', '< 1.3.4'
11 |
12 | # Ruby 3.4.0 has removed some libraries from the standard library.
13 | gem 'bigdecimal'
14 | gem 'logger'
15 | gem 'benchmark'
16 | gem 'mutex_m'
17 |
--------------------------------------------------------------------------------
/AwesomeExample/Gemfile.lock:
--------------------------------------------------------------------------------
1 | GEM
2 | remote: https://rubygems.org/
3 | specs:
4 | CFPropertyList (3.0.7)
5 | base64
6 | nkf
7 | rexml
8 | activesupport (7.2.2.1)
9 | base64
10 | benchmark (>= 0.3)
11 | bigdecimal
12 | concurrent-ruby (~> 1.0, >= 1.3.1)
13 | connection_pool (>= 2.2.5)
14 | drb
15 | i18n (>= 1.6, < 2)
16 | logger (>= 1.4.2)
17 | minitest (>= 5.1)
18 | securerandom (>= 0.3)
19 | tzinfo (~> 2.0, >= 2.0.5)
20 | addressable (2.8.7)
21 | public_suffix (>= 2.0.2, < 7.0)
22 | algoliasearch (1.27.5)
23 | httpclient (~> 2.8, >= 2.8.3)
24 | json (>= 1.5.1)
25 | atomos (0.1.3)
26 | base64 (0.2.0)
27 | benchmark (0.4.0)
28 | bigdecimal (3.1.9)
29 | claide (1.1.0)
30 | cocoapods (1.15.2)
31 | addressable (~> 2.8)
32 | claide (>= 1.0.2, < 2.0)
33 | cocoapods-core (= 1.15.2)
34 | cocoapods-deintegrate (>= 1.0.3, < 2.0)
35 | cocoapods-downloader (>= 2.1, < 3.0)
36 | cocoapods-plugins (>= 1.0.0, < 2.0)
37 | cocoapods-search (>= 1.0.0, < 2.0)
38 | cocoapods-trunk (>= 1.6.0, < 2.0)
39 | cocoapods-try (>= 1.1.0, < 2.0)
40 | colored2 (~> 3.1)
41 | escape (~> 0.0.4)
42 | fourflusher (>= 2.3.0, < 3.0)
43 | gh_inspector (~> 1.0)
44 | molinillo (~> 0.8.0)
45 | nap (~> 1.0)
46 | ruby-macho (>= 2.3.0, < 3.0)
47 | xcodeproj (>= 1.23.0, < 2.0)
48 | cocoapods-core (1.15.2)
49 | activesupport (>= 5.0, < 8)
50 | addressable (~> 2.8)
51 | algoliasearch (~> 1.0)
52 | concurrent-ruby (~> 1.1)
53 | fuzzy_match (~> 2.0.4)
54 | nap (~> 1.0)
55 | netrc (~> 0.11)
56 | public_suffix (~> 4.0)
57 | typhoeus (~> 1.0)
58 | cocoapods-deintegrate (1.0.5)
59 | cocoapods-downloader (2.1)
60 | cocoapods-plugins (1.0.0)
61 | nap
62 | cocoapods-search (1.0.1)
63 | cocoapods-trunk (1.6.0)
64 | nap (>= 0.8, < 2.0)
65 | netrc (~> 0.11)
66 | cocoapods-try (1.2.0)
67 | colored2 (3.1.2)
68 | concurrent-ruby (1.3.3)
69 | connection_pool (2.5.3)
70 | drb (2.2.3)
71 | escape (0.0.4)
72 | ethon (0.16.0)
73 | ffi (>= 1.15.0)
74 | ffi (1.17.2)
75 | fourflusher (2.3.1)
76 | fuzzy_match (2.0.4)
77 | gh_inspector (1.1.3)
78 | httpclient (2.9.0)
79 | mutex_m
80 | i18n (1.14.7)
81 | concurrent-ruby (~> 1.0)
82 | json (2.12.2)
83 | logger (1.7.0)
84 | minitest (5.25.5)
85 | molinillo (0.8.0)
86 | mutex_m (0.3.0)
87 | nanaimo (0.3.0)
88 | nap (1.1.0)
89 | netrc (0.11.0)
90 | nkf (0.2.0)
91 | public_suffix (4.0.7)
92 | rexml (3.4.1)
93 | ruby-macho (2.5.1)
94 | securerandom (0.4.1)
95 | typhoeus (1.4.1)
96 | ethon (>= 0.9.0)
97 | tzinfo (2.0.6)
98 | concurrent-ruby (~> 1.0)
99 | xcodeproj (1.25.1)
100 | CFPropertyList (>= 2.3.3, < 4.0)
101 | atomos (~> 0.1.3)
102 | claide (>= 1.0.2, < 2.0)
103 | colored2 (~> 3.1)
104 | nanaimo (~> 0.3.0)
105 | rexml (>= 3.3.6, < 4.0)
106 |
107 | PLATFORMS
108 | ruby
109 |
110 | DEPENDENCIES
111 | activesupport (>= 6.1.7.5, != 7.1.0)
112 | benchmark
113 | bigdecimal
114 | cocoapods (>= 1.13, != 1.15.1, != 1.15.0)
115 | concurrent-ruby (< 1.3.4)
116 | logger
117 | mutex_m
118 | xcodeproj (< 1.26.0)
119 |
120 | RUBY VERSION
121 | ruby 3.4.4p34
122 |
123 | BUNDLED WITH
124 | 2.6.9
125 |
--------------------------------------------------------------------------------
/AwesomeExample/README.md:
--------------------------------------------------------------------------------
1 | This is a new [**React Native**](https://reactnative.dev) project, bootstrapped using [`@react-native-community/cli`](https://github.com/react-native-community/cli).
2 |
3 | # Getting Started
4 |
5 | > **Note**: Make sure you have completed the [Set Up Your Environment](https://reactnative.dev/docs/set-up-your-environment) guide before proceeding.
6 |
7 | ## Step 1: Start Metro
8 |
9 | First, you will need to run **Metro**, the JavaScript build tool for React Native.
10 |
11 | To start the Metro dev server, run the following command from the root of your React Native project:
12 |
13 | ```sh
14 | # Using npm
15 | npm start
16 |
17 | # OR using Yarn
18 | yarn start
19 | ```
20 |
21 | ## Step 2: Build and run your app
22 |
23 | With Metro running, open a new terminal window/pane from the root of your React Native project, and use one of the following commands to build and run your Android or iOS app:
24 |
25 | ### Android
26 |
27 | ```sh
28 | # Using npm
29 | npm run android
30 |
31 | # OR using Yarn
32 | yarn android
33 | ```
34 |
35 | ### iOS
36 |
37 | For iOS, remember to install CocoaPods dependencies (this only needs to be run on first clone or after updating native deps).
38 |
39 | The first time you create a new project, run the Ruby bundler to install CocoaPods itself:
40 |
41 | ```sh
42 | bundle install
43 | ```
44 |
45 | Then, and every time you update your native dependencies, run:
46 |
47 | ```sh
48 | bundle exec pod install
49 | ```
50 |
51 | For more information, please visit [CocoaPods Getting Started guide](https://guides.cocoapods.org/using/getting-started.html).
52 |
53 | ```sh
54 | # Using npm
55 | npm run ios
56 |
57 | # OR using Yarn
58 | yarn ios
59 | ```
60 |
61 | If everything is set up correctly, you should see your new app running in the Android Emulator, iOS Simulator, or your connected device.
62 |
63 | This is one way to run your app — you can also build it directly from Android Studio or Xcode.
64 |
65 | ## Step 3: Modify your app
66 |
67 | Now that you have successfully run the app, let's make changes!
68 |
69 | Open `App.tsx` in your text editor of choice and make some changes. When you save, your app will automatically update and reflect these changes — this is powered by [Fast Refresh](https://reactnative.dev/docs/fast-refresh).
70 |
71 | When you want to forcefully reload, for example to reset the state of your app, you can perform a full reload:
72 |
73 | - **Android**: Press the R key twice or select **"Reload"** from the **Dev Menu**, accessed via Ctrl + M (Windows/Linux) or Cmd ⌘ + M (macOS).
74 | - **iOS**: Press R in iOS Simulator.
75 |
76 | ## Congratulations! :tada:
77 |
78 | You've successfully run and modified your React Native App. :partying_face:
79 |
80 | ### Now what?
81 |
82 | - If you want to add this new React Native code to an existing application, check out the [Integration guide](https://reactnative.dev/docs/integration-with-existing-apps).
83 | - If you're curious to learn more about React Native, check out the [docs](https://reactnative.dev/docs/getting-started).
84 |
85 | # Troubleshooting
86 |
87 | If you're having issues getting the above steps to work, see the [Troubleshooting](https://reactnative.dev/docs/troubleshooting) page.
88 |
89 | # Learn More
90 |
91 | To learn more about React Native, take a look at the following resources:
92 |
93 | - [React Native Website](https://reactnative.dev) - learn more about React Native.
94 | - [Getting Started](https://reactnative.dev/docs/environment-setup) - an **overview** of React Native and how setup your environment.
95 | - [Learn the Basics](https://reactnative.dev/docs/getting-started) - a **guided tour** of the React Native **basics**.
96 | - [Blog](https://reactnative.dev/blog) - read the latest official React Native **Blog** posts.
97 | - [`@facebook/react-native`](https://github.com/facebook/react-native) - the Open Source; GitHub **repository** for React Native.
98 |
--------------------------------------------------------------------------------
/AwesomeExample/__tests__/App.test.tsx:
--------------------------------------------------------------------------------
1 | /**
2 | * @format
3 | */
4 |
5 | import React from 'react';
6 | import ReactTestRenderer from 'react-test-renderer';
7 | import App from '../App';
8 |
9 | test('renders correctly', async () => {
10 | await ReactTestRenderer.act(() => {
11 | ReactTestRenderer.create();
12 | });
13 | });
14 |
--------------------------------------------------------------------------------
/AwesomeExample/android/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: "com.android.application"
2 | apply plugin: "org.jetbrains.kotlin.android"
3 | apply plugin: "com.facebook.react"
4 |
5 | /**
6 | * This is the configuration block to customize your React Native Android app.
7 | * By default you don't need to apply any configuration, just uncomment the lines you need.
8 | */
9 | react {
10 | /* Folders */
11 | // The root of your project, i.e. where "package.json" lives. Default is '../..'
12 | // root = file("../../")
13 | // The folder where the react-native NPM package is. Default is ../../node_modules/react-native
14 | // reactNativeDir = file("../../node_modules/react-native")
15 | // The folder where the react-native Codegen package is. Default is ../../node_modules/@react-native/codegen
16 | // codegenDir = file("../../node_modules/@react-native/codegen")
17 | // The cli.js file which is the React Native CLI entrypoint. Default is ../../node_modules/react-native/cli.js
18 | // cliFile = file("../../node_modules/react-native/cli.js")
19 |
20 | /* Variants */
21 | // The list of variants to that are debuggable. For those we're going to
22 | // skip the bundling of the JS bundle and the assets. By default is just 'debug'.
23 | // If you add flavors like lite, prod, etc. you'll have to list your debuggableVariants.
24 | // debuggableVariants = ["liteDebug", "prodDebug"]
25 |
26 | /* Bundling */
27 | // A list containing the node command and its flags. Default is just 'node'.
28 | // nodeExecutableAndArgs = ["node"]
29 | //
30 | // The command to run when bundling. By default is 'bundle'
31 | // bundleCommand = "ram-bundle"
32 | //
33 | // The path to the CLI configuration file. Default is empty.
34 | // bundleConfig = file(../rn-cli.config.js)
35 | //
36 | // The name of the generated asset file containing your JS bundle
37 | // bundleAssetName = "MyApplication.android.bundle"
38 | //
39 | // The entry file for bundle generation. Default is 'index.android.js' or 'index.js'
40 | // entryFile = file("../js/MyApplication.android.js")
41 | //
42 | // A list of extra flags to pass to the 'bundle' commands.
43 | // See https://github.com/react-native-community/cli/blob/main/docs/commands.md#bundle
44 | // extraPackagerArgs = []
45 |
46 | /* Hermes Commands */
47 | // The hermes compiler command to run. By default it is 'hermesc'
48 | // hermesCommand = "$rootDir/my-custom-hermesc/bin/hermesc"
49 | //
50 | // The list of flags to pass to the Hermes compiler. By default is "-O", "-output-source-map"
51 | // hermesFlags = ["-O", "-output-source-map"]
52 |
53 | /* Autolinking */
54 | autolinkLibrariesWithApp()
55 | }
56 |
57 | /**
58 | * Set this to true to Run Proguard on Release builds to minify the Java bytecode.
59 | */
60 | def enableProguardInReleaseBuilds = false
61 |
62 | /**
63 | * The preferred build flavor of JavaScriptCore (JSC)
64 | *
65 | * For example, to use the international variant, you can use:
66 | * `def jscFlavor = io.github.react-native-community:jsc-android-intl:2026004.+`
67 | *
68 | * The international variant includes ICU i18n library and necessary data
69 | * allowing to use e.g. `Date.toLocaleString` and `String.localeCompare` that
70 | * give correct results when using with locales other than en-US. Note that
71 | * this variant is about 6MiB larger per architecture than default.
72 | */
73 | def jscFlavor = 'io.github.react-native-community:jsc-android:2026004.+'
74 |
75 | android {
76 | ndkVersion rootProject.ext.ndkVersion
77 | buildToolsVersion rootProject.ext.buildToolsVersion
78 | compileSdk rootProject.ext.compileSdkVersion
79 |
80 | namespace "com.awesomeexample"
81 | defaultConfig {
82 | applicationId "com.awesomeexample"
83 | minSdkVersion rootProject.ext.minSdkVersion
84 | targetSdkVersion rootProject.ext.targetSdkVersion
85 | versionCode 1
86 | versionName "1.0"
87 | }
88 | signingConfigs {
89 | debug {
90 | storeFile file('debug.keystore')
91 | storePassword 'android'
92 | keyAlias 'androiddebugkey'
93 | keyPassword 'android'
94 | }
95 | }
96 | buildTypes {
97 | debug {
98 | signingConfig signingConfigs.debug
99 | }
100 | release {
101 | // Caution! In production, you need to generate your own keystore file.
102 | // see https://reactnative.dev/docs/signed-apk-android.
103 | signingConfig signingConfigs.debug
104 | minifyEnabled enableProguardInReleaseBuilds
105 | proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
106 | }
107 | }
108 | }
109 |
110 | dependencies {
111 | // The version of react-native is set by the React Native Gradle Plugin
112 | implementation("com.facebook.react:react-android")
113 |
114 | if (hermesEnabled.toBoolean()) {
115 | implementation("com.facebook.react:hermes-android")
116 | } else {
117 | implementation jscFlavor
118 | }
119 | }
120 |
--------------------------------------------------------------------------------
/AwesomeExample/android/app/debug.keystore:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivpusic/react-native-image-crop-picker/748898a3d8ee1af82a333780f1f9bb6c62439d28/AwesomeExample/android/app/debug.keystore
--------------------------------------------------------------------------------
/AwesomeExample/android/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /usr/local/Cellar/android-sdk/24.3.3/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
--------------------------------------------------------------------------------
/AwesomeExample/android/app/src/debug/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
9 |
10 |
--------------------------------------------------------------------------------
/AwesomeExample/android/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
8 |
9 |
10 |
18 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/AwesomeExample/android/app/src/main/java/com/awesomeexample/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package com.awesomeexample
2 |
3 | import com.facebook.react.ReactActivity
4 | import com.facebook.react.ReactActivityDelegate
5 | import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.fabricEnabled
6 | import com.facebook.react.defaults.DefaultReactActivityDelegate
7 |
8 | class MainActivity : ReactActivity() {
9 |
10 | /**
11 | * Returns the name of the main component registered from JavaScript. This is used to schedule
12 | * rendering of the component.
13 | */
14 | override fun getMainComponentName(): String = "AwesomeExample"
15 |
16 | /**
17 | * Returns the instance of the [ReactActivityDelegate]. We use [DefaultReactActivityDelegate]
18 | * which allows you to enable New Architecture with a single boolean flags [fabricEnabled]
19 | */
20 | override fun createReactActivityDelegate(): ReactActivityDelegate =
21 | DefaultReactActivityDelegate(this, mainComponentName, fabricEnabled)
22 | }
23 |
--------------------------------------------------------------------------------
/AwesomeExample/android/app/src/main/java/com/awesomeexample/MainApplication.kt:
--------------------------------------------------------------------------------
1 | package com.awesomeexample
2 |
3 | import android.app.Application
4 | import com.facebook.react.PackageList
5 | import com.facebook.react.ReactApplication
6 | import com.facebook.react.ReactHost
7 | import com.facebook.react.ReactNativeHost
8 | import com.facebook.react.ReactPackage
9 | import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.load
10 | import com.facebook.react.defaults.DefaultReactHost.getDefaultReactHost
11 | import com.facebook.react.defaults.DefaultReactNativeHost
12 | import com.facebook.react.soloader.OpenSourceMergedSoMapping
13 | import com.facebook.soloader.SoLoader
14 |
15 | class MainApplication : Application(), ReactApplication {
16 |
17 | override val reactNativeHost: ReactNativeHost =
18 | object : DefaultReactNativeHost(this) {
19 | override fun getPackages(): List =
20 | PackageList(this).packages.apply {
21 | // Packages that cannot be autolinked yet can be added manually here, for example:
22 | // add(MyReactNativePackage())
23 | }
24 |
25 | override fun getJSMainModuleName(): String = "index"
26 |
27 | override fun getUseDeveloperSupport(): Boolean = BuildConfig.DEBUG
28 |
29 | override val isNewArchEnabled: Boolean = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED
30 | override val isHermesEnabled: Boolean = BuildConfig.IS_HERMES_ENABLED
31 | }
32 |
33 | override val reactHost: ReactHost
34 | get() = getDefaultReactHost(applicationContext, reactNativeHost)
35 |
36 | override fun onCreate() {
37 | super.onCreate()
38 | SoLoader.init(this, OpenSourceMergedSoMapping)
39 | if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {
40 | // If you opted-in for the New Architecture, we load the native entry point for this app.
41 | load()
42 | }
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/AwesomeExample/android/app/src/main/res/drawable/rn_edit_text_material.xml:
--------------------------------------------------------------------------------
1 |
2 |
16 |
22 |
23 |
24 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/AwesomeExample/android/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivpusic/react-native-image-crop-picker/748898a3d8ee1af82a333780f1f9bb6c62439d28/AwesomeExample/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/AwesomeExample/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivpusic/react-native-image-crop-picker/748898a3d8ee1af82a333780f1f9bb6c62439d28/AwesomeExample/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/AwesomeExample/android/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivpusic/react-native-image-crop-picker/748898a3d8ee1af82a333780f1f9bb6c62439d28/AwesomeExample/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/AwesomeExample/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivpusic/react-native-image-crop-picker/748898a3d8ee1af82a333780f1f9bb6c62439d28/AwesomeExample/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/AwesomeExample/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivpusic/react-native-image-crop-picker/748898a3d8ee1af82a333780f1f9bb6c62439d28/AwesomeExample/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/AwesomeExample/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivpusic/react-native-image-crop-picker/748898a3d8ee1af82a333780f1f9bb6c62439d28/AwesomeExample/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/AwesomeExample/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivpusic/react-native-image-crop-picker/748898a3d8ee1af82a333780f1f9bb6c62439d28/AwesomeExample/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/AwesomeExample/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivpusic/react-native-image-crop-picker/748898a3d8ee1af82a333780f1f9bb6c62439d28/AwesomeExample/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/AwesomeExample/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivpusic/react-native-image-crop-picker/748898a3d8ee1af82a333780f1f9bb6c62439d28/AwesomeExample/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/AwesomeExample/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivpusic/react-native-image-crop-picker/748898a3d8ee1af82a333780f1f9bb6c62439d28/AwesomeExample/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/AwesomeExample/android/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | AwesomeExample
3 |
4 |
--------------------------------------------------------------------------------
/AwesomeExample/android/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/AwesomeExample/android/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | ext {
3 | buildToolsVersion = "35.0.0"
4 | minSdkVersion = 24
5 | compileSdkVersion = 35
6 | targetSdkVersion = 35
7 | ndkVersion = "27.1.12297006"
8 | kotlinVersion = "2.0.21"
9 | }
10 | repositories {
11 | google()
12 | mavenCentral()
13 | }
14 | dependencies {
15 | classpath("com.android.tools.build:gradle")
16 | classpath("com.facebook.react:react-native-gradle-plugin")
17 | classpath("org.jetbrains.kotlin:kotlin-gradle-plugin")
18 | }
19 | }
20 |
21 | apply plugin: "com.facebook.react.rootproject"
22 |
--------------------------------------------------------------------------------
/AwesomeExample/android/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | # Default value: -Xmx512m -XX:MaxMetaspaceSize=256m
13 | org.gradle.jvmargs=-Xmx2048m -XX:MaxMetaspaceSize=512m
14 |
15 | # When configured, Gradle will run in incubating parallel mode.
16 | # This option should only be used with decoupled projects. More details, visit
17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
18 | # org.gradle.parallel=true
19 |
20 | # AndroidX package structure to make it clearer which packages are bundled with the
21 | # Android operating system, and which are packaged with your app's APK
22 | # https://developer.android.com/topic/libraries/support-library/androidx-rn
23 | android.useAndroidX=true
24 |
25 | # Use this property to specify which architecture you want to build.
26 | # You can also override it from the CLI using
27 | # ./gradlew -PreactNativeArchitectures=x86_64
28 | reactNativeArchitectures=armeabi-v7a,arm64-v8a,x86,x86_64
29 |
30 | # Use this property to enable support to the new architecture.
31 | # This will allow you to use TurboModules and the Fabric render in
32 | # your application. You should enable this flag either if you want
33 | # to write custom TurboModules/Fabric components OR use libraries that
34 | # are providing them.
35 | newArchEnabled=true
36 |
37 | # Use this property to enable or disable the Hermes JS engine.
38 | # If set to false, you will be using JSC instead.
39 | hermesEnabled=true
40 |
--------------------------------------------------------------------------------
/AwesomeExample/android/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivpusic/react-native-image-crop-picker/748898a3d8ee1af82a333780f1f9bb6c62439d28/AwesomeExample/android/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/AwesomeExample/android/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip
4 | networkTimeout=10000
5 | validateDistributionUrl=true
6 | zipStoreBase=GRADLE_USER_HOME
7 | zipStorePath=wrapper/dists
8 |
--------------------------------------------------------------------------------
/AwesomeExample/android/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 | @rem SPDX-License-Identifier: Apache-2.0
17 | @rem
18 |
19 | @if "%DEBUG%"=="" @echo off
20 | @rem ##########################################################################
21 | @rem
22 | @rem Gradle startup script for Windows
23 | @rem
24 | @rem ##########################################################################
25 |
26 | @rem Set local scope for the variables with windows NT shell
27 | if "%OS%"=="Windows_NT" setlocal
28 |
29 | set DIRNAME=%~dp0
30 | if "%DIRNAME%"=="" set DIRNAME=.
31 | @rem This is normally unused
32 | set APP_BASE_NAME=%~n0
33 | set APP_HOME=%DIRNAME%
34 |
35 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
36 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
37 |
38 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
39 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
40 |
41 | @rem Find java.exe
42 | if defined JAVA_HOME goto findJavaFromJavaHome
43 |
44 | set JAVA_EXE=java.exe
45 | %JAVA_EXE% -version >NUL 2>&1
46 | if %ERRORLEVEL% equ 0 goto execute
47 |
48 | echo. 1>&2
49 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
50 | echo. 1>&2
51 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2
52 | echo location of your Java installation. 1>&2
53 |
54 | goto fail
55 |
56 | :findJavaFromJavaHome
57 | set JAVA_HOME=%JAVA_HOME:"=%
58 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
59 |
60 | if exist "%JAVA_EXE%" goto execute
61 |
62 | echo. 1>&2
63 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
64 | echo. 1>&2
65 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2
66 | echo location of your Java installation. 1>&2
67 |
68 | goto fail
69 |
70 | :execute
71 | @rem Setup the command line
72 |
73 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
74 |
75 |
76 | @rem Execute Gradle
77 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
78 |
79 | :end
80 | @rem End local scope for the variables with windows NT shell
81 | if %ERRORLEVEL% equ 0 goto mainEnd
82 |
83 | :fail
84 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
85 | rem the _cmd.exe /c_ return code!
86 | set EXIT_CODE=%ERRORLEVEL%
87 | if %EXIT_CODE% equ 0 set EXIT_CODE=1
88 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
89 | exit /b %EXIT_CODE%
90 |
91 | :mainEnd
92 | if "%OS%"=="Windows_NT" endlocal
93 |
94 | :omega
95 |
--------------------------------------------------------------------------------
/AwesomeExample/android/settings.gradle:
--------------------------------------------------------------------------------
1 | pluginManagement { includeBuild("../node_modules/@react-native/gradle-plugin") }
2 | plugins { id("com.facebook.react.settings") }
3 | extensions.configure(com.facebook.react.ReactSettingsExtension){ ex -> ex.autolinkLibrariesFromCommand() }
4 | rootProject.name = 'AwesomeExample'
5 | include ':app'
6 | includeBuild('../node_modules/@react-native/gradle-plugin')
7 |
--------------------------------------------------------------------------------
/AwesomeExample/app.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "AwesomeExample",
3 | "displayName": "AwesomeExample"
4 | }
5 |
--------------------------------------------------------------------------------
/AwesomeExample/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: ['module:@react-native/babel-preset'],
3 | };
4 |
--------------------------------------------------------------------------------
/AwesomeExample/index.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @format
3 | */
4 |
5 | import {AppRegistry} from 'react-native';
6 | import App from './App';
7 | import {name as appName} from './app.json';
8 |
9 | AppRegistry.registerComponent(appName, () => App);
10 |
--------------------------------------------------------------------------------
/AwesomeExample/ios/.xcode.env:
--------------------------------------------------------------------------------
1 | # This `.xcode.env` file is versioned and is used to source the environment
2 | # used when running script phases inside Xcode.
3 | # To customize your local environment, you can create an `.xcode.env.local`
4 | # file that is not versioned.
5 |
6 | # NODE_BINARY variable contains the PATH to the node executable.
7 | #
8 | # Customize the NODE_BINARY variable here.
9 | # For example, to use nvm with brew, add the following line
10 | # . "$(brew --prefix nvm)/nvm.sh" --no-use
11 | export NODE_BINARY=$(command -v node)
12 |
--------------------------------------------------------------------------------
/AwesomeExample/ios/AwesomeExample.xcodeproj/xcshareddata/xcschemes/AwesomeExample.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
33 |
39 |
40 |
41 |
42 |
43 |
53 |
55 |
61 |
62 |
63 |
64 |
70 |
72 |
78 |
79 |
80 |
81 |
83 |
84 |
87 |
88 |
89 |
--------------------------------------------------------------------------------
/AwesomeExample/ios/AwesomeExample.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/AwesomeExample/ios/AwesomeExample/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 | import React
3 | import React_RCTAppDelegate
4 | import ReactAppDependencyProvider
5 |
6 | @main
7 | class AppDelegate: UIResponder, UIApplicationDelegate {
8 | var window: UIWindow?
9 |
10 | var reactNativeDelegate: ReactNativeDelegate?
11 | var reactNativeFactory: RCTReactNativeFactory?
12 |
13 | func application(
14 | _ application: UIApplication,
15 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil
16 | ) -> Bool {
17 | let delegate = ReactNativeDelegate()
18 | let factory = RCTReactNativeFactory(delegate: delegate)
19 | delegate.dependencyProvider = RCTAppDependencyProvider()
20 |
21 | reactNativeDelegate = delegate
22 | reactNativeFactory = factory
23 |
24 | window = UIWindow(frame: UIScreen.main.bounds)
25 |
26 | factory.startReactNative(
27 | withModuleName: "AwesomeExample",
28 | in: window,
29 | launchOptions: launchOptions
30 | )
31 |
32 | return true
33 | }
34 | }
35 |
36 | class ReactNativeDelegate: RCTDefaultReactNativeFactoryDelegate {
37 | override func sourceURL(for bridge: RCTBridge) -> URL? {
38 | self.bundleURL()
39 | }
40 |
41 | override func bundleURL() -> URL? {
42 | #if DEBUG
43 | RCTBundleURLProvider.sharedSettings().jsBundleURL(forBundleRoot: "index")
44 | #else
45 | Bundle.main.url(forResource: "main", withExtension: "jsbundle")
46 | #endif
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/AwesomeExample/ios/AwesomeExample/Images.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "scale" : "2x",
6 | "size" : "20x20"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "scale" : "3x",
11 | "size" : "20x20"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "scale" : "2x",
16 | "size" : "29x29"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "scale" : "3x",
21 | "size" : "29x29"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "scale" : "2x",
26 | "size" : "40x40"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "scale" : "3x",
31 | "size" : "40x40"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "scale" : "2x",
36 | "size" : "60x60"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "scale" : "3x",
41 | "size" : "60x60"
42 | },
43 | {
44 | "idiom" : "ios-marketing",
45 | "scale" : "1x",
46 | "size" : "1024x1024"
47 | }
48 | ],
49 | "info" : {
50 | "author" : "xcode",
51 | "version" : 1
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/AwesomeExample/ios/AwesomeExample/Images.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/AwesomeExample/ios/AwesomeExample/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleDisplayName
8 | AwesomeExample
9 | CFBundleExecutable
10 | $(EXECUTABLE_NAME)
11 | CFBundleIdentifier
12 | $(PRODUCT_BUNDLE_IDENTIFIER)
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | $(PRODUCT_NAME)
17 | CFBundlePackageType
18 | APPL
19 | NSPhotoLibraryUsageDescription
20 | Photo Library Access Warning
21 | NSCameraUsageDescription
22 | Camera usage description
23 | NSMicrophoneUsageDescription
24 | This app requires to access your microphone to record video with your voice send via chat
25 | CFBundleShortVersionString
26 | $(MARKETING_VERSION)
27 | CFBundleSignature
28 | ????
29 | CFBundleVersion
30 | $(CURRENT_PROJECT_VERSION)
31 | LSRequiresIPhoneOS
32 |
33 | NSAppTransportSecurity
34 |
35 |
36 | NSAllowsArbitraryLoads
37 |
38 | NSAllowsLocalNetworking
39 |
40 |
41 | NSLocationWhenInUseUsageDescription
42 |
43 | UILaunchStoryboardName
44 | LaunchScreen
45 | UIRequiredDeviceCapabilities
46 |
47 | arm64
48 |
49 | UISupportedInterfaceOrientations
50 |
51 | UIInterfaceOrientationPortrait
52 | UIInterfaceOrientationLandscapeLeft
53 | UIInterfaceOrientationLandscapeRight
54 |
55 | UIViewControllerBasedStatusBarAppearance
56 |
57 |
58 |
59 |
--------------------------------------------------------------------------------
/AwesomeExample/ios/AwesomeExample/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
24 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/AwesomeExample/ios/AwesomeExample/PrivacyInfo.xcprivacy:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | NSPrivacyAccessedAPITypes
6 |
7 |
8 | NSPrivacyAccessedAPIType
9 | NSPrivacyAccessedAPICategoryFileTimestamp
10 | NSPrivacyAccessedAPITypeReasons
11 |
12 | 3B52.1
13 | C617.1
14 |
15 |
16 |
17 | NSPrivacyAccessedAPIType
18 | NSPrivacyAccessedAPICategoryUserDefaults
19 | NSPrivacyAccessedAPITypeReasons
20 |
21 | CA92.1
22 |
23 |
24 |
25 | NSPrivacyAccessedAPIType
26 | NSPrivacyAccessedAPICategorySystemBootTime
27 | NSPrivacyAccessedAPITypeReasons
28 |
29 | 35F9.1
30 |
31 |
32 |
33 | NSPrivacyCollectedDataTypes
34 |
35 | NSPrivacyTracking
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/AwesomeExample/ios/Podfile:
--------------------------------------------------------------------------------
1 | # Resolve react_native_pods.rb with node to allow for hoisting
2 | require Pod::Executable.execute_command('node', ['-p',
3 | 'require.resolve(
4 | "react-native/scripts/react_native_pods.rb",
5 | {paths: [process.argv[1]]},
6 | )', __dir__]).strip
7 |
8 | platform :ios, min_ios_version_supported
9 | prepare_react_native_project!
10 |
11 | linkage = ENV['USE_FRAMEWORKS']
12 | if linkage != nil
13 | Pod::UI.puts "Configuring Pod with #{linkage}ally linked Frameworks".green
14 | use_frameworks! :linkage => linkage.to_sym
15 | end
16 |
17 | target 'AwesomeExample' do
18 | config = use_native_modules!
19 |
20 | use_react_native!(
21 | :path => config[:reactNativePath],
22 | # An absolute path to your application root.
23 | :app_path => "#{Pod::Config.instance.installation_root}/.."
24 | )
25 |
26 | post_install do |installer|
27 | # https://github.com/facebook/react-native/blob/main/packages/react-native/scripts/react_native_pods.rb#L197-L202
28 | react_native_post_install(
29 | installer,
30 | config[:reactNativePath],
31 | :mac_catalyst_enabled => false,
32 | # :ccache_enabled => true
33 | )
34 | end
35 | end
36 |
--------------------------------------------------------------------------------
/AwesomeExample/jest.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | preset: 'react-native',
3 | };
4 |
--------------------------------------------------------------------------------
/AwesomeExample/metro.config.js:
--------------------------------------------------------------------------------
1 | const {getDefaultConfig, mergeConfig} = require('@react-native/metro-config');
2 |
3 | /**
4 | * Metro configuration
5 | * https://reactnative.dev/docs/metro
6 | *
7 | * @type {import('@react-native/metro-config').MetroConfig}
8 | */
9 | const config = {};
10 |
11 | module.exports = mergeConfig(getDefaultConfig(__dirname), config);
12 |
--------------------------------------------------------------------------------
/AwesomeExample/package:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivpusic/react-native-image-crop-picker/748898a3d8ee1af82a333780f1f9bb6c62439d28/AwesomeExample/package
--------------------------------------------------------------------------------
/AwesomeExample/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "AwesomeExample",
3 | "version": "0.0.1",
4 | "private": true,
5 | "scripts": {
6 | "android": "react-native run-android",
7 | "ios": "react-native run-ios",
8 | "lint": "eslint .",
9 | "start": "react-native start",
10 | "test": "jest"
11 | },
12 | "dependencies": {
13 | "react": "19.0.0",
14 | "react-native": "0.79.2",
15 | "react-native-image-crop-picker": "../",
16 | "react-native-video": "^6.14.1"
17 | },
18 | "devDependencies": {
19 | "@babel/core": "^7.25.2",
20 | "@babel/preset-env": "^7.25.3",
21 | "@babel/runtime": "^7.25.0",
22 | "@react-native-community/cli": "18.0.0",
23 | "@react-native-community/cli-platform-android": "18.0.0",
24 | "@react-native-community/cli-platform-ios": "18.0.0",
25 | "@react-native/babel-preset": "0.79.2",
26 | "@react-native/eslint-config": "0.79.2",
27 | "@react-native/metro-config": "0.79.2",
28 | "@react-native/typescript-config": "0.79.2",
29 | "@types/jest": "^29.5.13",
30 | "@types/react": "^19.0.0",
31 | "@types/react-test-renderer": "^19.0.0",
32 | "eslint": "^8.19.0",
33 | "jest": "^29.6.3",
34 | "prettier": "2.8.8",
35 | "react-test-renderer": "19.0.0",
36 | "typescript": "5.0.4"
37 | },
38 | "engines": {
39 | "node": ">=18"
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/AwesomeExample/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "@react-native/typescript-config/tsconfig.json"
3 | }
4 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Contributor Covenant Code of Conduct
2 |
3 | ## Our Pledge
4 |
5 | In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
6 |
7 | ## Our Standards
8 |
9 | Examples of behavior that contributes to creating a positive environment include:
10 |
11 | * Using welcoming and inclusive language
12 | * Being respectful of differing viewpoints and experiences
13 | * Gracefully accepting constructive criticism
14 | * Focusing on what is best for the community
15 | * Showing empathy towards other community members
16 |
17 | Examples of unacceptable behavior by participants include:
18 |
19 | * The use of sexualized language or imagery and unwelcome sexual attention or advances
20 | * Trolling, insulting/derogatory comments, and personal or political attacks
21 | * Public or private harassment
22 | * Publishing others' private information, such as a physical or electronic address, without explicit permission
23 | * Other conduct which could reasonably be considered inappropriate in a professional setting
24 |
25 | ## Our Responsibilities
26 |
27 | Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
28 |
29 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
30 |
31 | ## Scope
32 |
33 | This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
34 |
35 | ## Enforcement
36 |
37 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at pusic007@gmail.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
38 |
39 | Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
40 |
41 | ## Attribution
42 |
43 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
44 |
45 | [homepage]: http://contributor-covenant.org
46 | [version]: http://contributor-covenant.org/version/1/4/
47 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contribute
2 |
3 | ## Introduction
4 |
5 | First, thank you for considering contributing to react-native-image-crop-picker! It's people like you that make the open source community such a great community! 😊
6 |
7 | We welcome any type of contribution, not only code. You can help with
8 | - **QA**: file bug reports, the more details you can give the better (e.g. screenshots with the console open)
9 | - **Marketing**: writing blog posts, howto's, printing stickers, ...
10 | - **Community**: presenting the project at meetups, organizing a dedicated meetup for the local community, ...
11 | - **Code**: take a look at the [open issues](https://github.com/ivpusic/react-native-image-crop-picker/issues). Even if you can't write code, commenting on them, showing that you care about a given
12 | matters. It helps us triage them.
13 | - **Money**: we welcome financial contributions in full transparency on our [open collective](https://opencollective.com/react-native-image-crop-picker).
14 |
15 | ## Your First Contribution
16 |
17 | Working on your first Pull Request? You can learn how from this *free* series, [How to Contribute to an Open Source Project on GitHub](https://egghead.io/series/how-to-contribute-to-an-open-source-project-on-github).
18 |
19 | ## Submitting code
20 |
21 | Any code change should be submitted as a pull request. The description should explain what the code does and give steps to execute it. The pull request should also contain tests.
22 |
23 | ## Code review process
24 |
25 | The bigger the pull request, the longer it will take to review and merge. Try to break down large pull requests in smaller chunks that are easier to review and merge.
26 | It is also always helpful to have some context for your pull request. What was the purpose? Why does it matter to you?
27 |
28 | ## Financial contributions
29 |
30 | We also welcome financial contributions in full transparency on our [open collective](https://opencollective.com/react-native-image-crop-picker).
31 | Anyone can file an expense. If the expense makes sense for the development of the community, it will be "merged" in the ledger of our open collective by the core contributors and the person who filed the expense will be reimbursed.
32 |
33 | ## Questions
34 |
35 | If you have any questions, create an [issue](https://github.com/ivpusic/react-native-image-crop-picker/issues) (protip: do a quick search first to see if someone else didn't ask the same question before!).
36 | You can also reach us at hello@react-native-image-crop-picker.opencollective.com.
37 |
38 | ## Credits
39 |
40 | ### Contributors
41 |
42 | Thank you to all the people who have already contributed to react-native-image-crop-picker!
43 |
44 |
45 |
46 | ### Backers
47 |
48 | Thank you to all our backers! [[Become a backer](https://opencollective.com/react-native-image-crop-picker#backer)]
49 |
50 |
51 |
52 |
53 | ### Sponsors
54 |
55 | Thank you to all our sponsors! (please ask your company to also support this open source project by [becoming a sponsor](https://opencollective.com/react-native-image-crop-picker#sponsor))
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
--------------------------------------------------------------------------------
/ISSUE_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | ### Version
2 | Tell us which versions you are using:
3 |
4 | - react-native-image-crop-picker v0.?.?
5 | - react-native v0.?.?
6 |
7 | ### Platform
8 | Tell us to which platform this issue is related
9 |
10 | - iOS
11 | - Android
12 |
13 | ### Expected behaviour
14 |
15 |
16 |
17 | ### Actual behaviour
18 |
19 |
20 |
21 | ### Steps to reproduce
22 |
23 | 1.
24 |
25 | 2.
26 |
27 | 3.
28 |
29 | ### Attachments
30 |
31 | // stacktrace or any other useful debug info
32 |
33 | Love react-native-image-crop-picker? Please consider supporting our collective:
34 | 👉 https://opencollective.com/react-native-image-crop-picker/donate
35 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 Ivan Pusic
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/RNImageCropPicker.podspec:
--------------------------------------------------------------------------------
1 | package = JSON.parse(File.read(File.join(__dir__, "package.json")))
2 |
3 | Pod::Spec.new do |s|
4 | s.name = "RNImageCropPicker"
5 | s.version = package['version']
6 | s.summary = package["description"]
7 | s.requires_arc = true
8 | s.license = 'MIT'
9 | s.homepage = 'n/a'
10 | s.authors = { "ivpusic" => "" }
11 | s.source = { :git => "https://github.com/ivpusic/react-native-image-crop-picker", :tag => "v#{s.version}"}
12 | s.source_files = 'ios/src/*.{h,m,mm}'
13 | s.platform = :ios, "8.0"
14 | s.dependency 'React-Core'
15 | s.dependency 'React-RCTImage'
16 | s.dependency 'TOCropViewController', '~> 2.7.4'
17 | s.resource_bundles = {
18 | 'RNImageCropPickerPrivacyInfo' => ['ios/PrivacyInfo.xcprivacy'],
19 | }
20 |
21 | s.subspec 'QBImagePickerController' do |qb|
22 | qb.name = "QBImagePickerController"
23 | qb.source_files = "ios/QBImagePicker/QBImagePicker/*.{h,m}"
24 | qb.exclude_files = "ios/QBImagePicker/QBImagePicker/QBImagePicker.h"
25 | qb.resource_bundles = { "QBImagePicker" => "ios/QBImagePicker/QBImagePicker/*.{lproj,storyboard}" }
26 | qb.requires_arc = true
27 | qb.frameworks = "Photos", "PhotosUI"
28 | end
29 |
30 | install_modules_dependencies(s)
31 | end
32 |
--------------------------------------------------------------------------------
/android/build.gradle:
--------------------------------------------------------------------------------
1 | import com.android.Version
2 |
3 | apply plugin: 'com.android.library'
4 |
5 | def safeExtGet(prop, fallback) {
6 | rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
7 | }
8 |
9 | def isNewArchitectureEnabled() {
10 | return project.hasProperty("newArchEnabled") && project.newArchEnabled == "true"
11 | }
12 |
13 | def resolveReactNativeDirectory() {
14 | def reactNativeLocation = safeExtGet("REACT_NATIVE_NODE_MODULES_DIR", null)
15 | if (reactNativeLocation != null) {
16 | return file(reactNativeLocation)
17 | }
18 |
19 | def reactNativeFromProjectNodeModules = file("${rootProject.projectDir}/../node_modules/react-native")
20 | if (reactNativeFromProjectNodeModules.exists()) {
21 | return reactNativeFromProjectNodeModules
22 | }
23 |
24 | def reactNativeFromNodeModulesWithPicker = file("${projectDir}/../../react-native")
25 | if (reactNativeFromNodeModulesWithPicker.exists()) {
26 | return reactNativeFromNodeModulesWithPicker
27 | }
28 |
29 | throw new Exception(
30 | "[react-native-picker] Unable to resolve react-native location in " +
31 | "node_modules. You should add project extension property (in app/build.gradle) " +
32 | "`REACT_NATIVE_NODE_MODULES_DIR` with path to react-native."
33 | )
34 | }
35 |
36 | def getReactNativeMinorVersion() {
37 | def REACT_NATIVE_DIR = resolveReactNativeDirectory()
38 |
39 | def reactProperties = new Properties()
40 | file("$REACT_NATIVE_DIR/ReactAndroid/gradle.properties").withInputStream { reactProperties.load(it) }
41 |
42 | def REACT_NATIVE_VERSION = reactProperties.getProperty("VERSION_NAME")
43 | def REACT_NATIVE_MINOR_VERSION = REACT_NATIVE_VERSION.startsWith("0.0.0-") ? 1000 : REACT_NATIVE_VERSION.split("\\.")[1].toInteger()
44 |
45 | return REACT_NATIVE_MINOR_VERSION
46 | }
47 |
48 |
49 | if (isNewArchitectureEnabled()) {
50 | apply plugin: "com.facebook.react"
51 | }
52 |
53 | android {
54 | compileSdk safeExtGet('compileSdkVersion', 34)
55 |
56 | def agpVersion = Version.ANDROID_GRADLE_PLUGIN_VERSION
57 | // Check AGP version for backward compatibility reasons
58 | if (agpVersion.tokenize('.')[0].toInteger() >= 7) {
59 | namespace = "com.reactnative.ivpusic.imagepicker"
60 | }
61 |
62 | defaultConfig {
63 | minSdkVersion safeExtGet('minSdkVersion', 23)
64 | targetSdkVersion safeExtGet('targetSdkVersion', 34)
65 | versionCode 1
66 | buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString()
67 | }
68 | lintOptions {
69 | abortOnError false
70 | }
71 |
72 | sourceSets.main {
73 | java {
74 | if (isNewArchitectureEnabled()) {
75 | srcDirs += [
76 | "src/newArch/java",
77 | ]
78 | } else {
79 | srcDirs += [
80 | "src/oldArch/java",
81 | ]
82 | }
83 | }
84 | }
85 | }
86 |
87 | repositories {
88 | maven {
89 | url "$projectDir/../node_modules/react-native/android"
90 | }
91 | google()
92 | mavenCentral()
93 | }
94 | dependencies {
95 | if (isNewArchitectureEnabled() && getReactNativeMinorVersion() < 71) {
96 | implementation project(":ReactAndroid")
97 | } else {
98 | implementation 'com.facebook.react:react-native:+'
99 | }
100 | implementation "com.facebook.react:react-native:${safeExtGet('reactNativeVersion', '+')}"
101 | implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0'
102 | implementation 'com.github.yalantis:ucrop:2.2.10'
103 | implementation 'androidx.activity:activity:1.10.1'
104 | implementation "androidx.core:core:1.16.0"
105 | implementation 'androidx.exifinterface:exifinterface:1.4.1'
106 | }
107 |
--------------------------------------------------------------------------------
/android/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivpusic/react-native-image-crop-picker/748898a3d8ee1af82a333780f1f9bb6c62439d28/android/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/android/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 |
--------------------------------------------------------------------------------
/android/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # Attempt to set APP_HOME
46 | # Resolve links: $0 may be a link
47 | PRG="$0"
48 | # Need this for relative symlinks.
49 | while [ -h "$PRG" ] ; do
50 | ls=`ls -ld "$PRG"`
51 | link=`expr "$ls" : '.*-> \(.*\)$'`
52 | if expr "$link" : '/.*' > /dev/null; then
53 | PRG="$link"
54 | else
55 | PRG=`dirname "$PRG"`"/$link"
56 | fi
57 | done
58 | SAVED="`pwd`"
59 | cd "`dirname \"$PRG\"`/" >/dev/null
60 | APP_HOME="`pwd -P`"
61 | cd "$SAVED" >/dev/null
62 |
63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
64 |
65 | # Determine the Java command to use to start the JVM.
66 | if [ -n "$JAVA_HOME" ] ; then
67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
68 | # IBM's JDK on AIX uses strange locations for the executables
69 | JAVACMD="$JAVA_HOME/jre/sh/java"
70 | else
71 | JAVACMD="$JAVA_HOME/bin/java"
72 | fi
73 | if [ ! -x "$JAVACMD" ] ; then
74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
75 |
76 | Please set the JAVA_HOME variable in your environment to match the
77 | location of your Java installation."
78 | fi
79 | else
80 | JAVACMD="java"
81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
82 |
83 | Please set the JAVA_HOME variable in your environment to match the
84 | location of your Java installation."
85 | fi
86 |
87 | # Increase the maximum file descriptors if we can.
88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
89 | MAX_FD_LIMIT=`ulimit -H -n`
90 | if [ $? -eq 0 ] ; then
91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
92 | MAX_FD="$MAX_FD_LIMIT"
93 | fi
94 | ulimit -n $MAX_FD
95 | if [ $? -ne 0 ] ; then
96 | warn "Could not set maximum file descriptor limit: $MAX_FD"
97 | fi
98 | else
99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
100 | fi
101 | fi
102 |
103 | # For Darwin, add options to specify how the application appears in the dock
104 | if $darwin; then
105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
106 | fi
107 |
108 | # For Cygwin, switch paths to Windows format before running java
109 | if $cygwin ; then
110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
112 | JAVACMD=`cygpath --unix "$JAVACMD"`
113 |
114 | # We build the pattern for arguments to be converted via cygpath
115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
116 | SEP=""
117 | for dir in $ROOTDIRSRAW ; do
118 | ROOTDIRS="$ROOTDIRS$SEP$dir"
119 | SEP="|"
120 | done
121 | OURCYGPATTERN="(^($ROOTDIRS))"
122 | # Add a user-defined pattern to the cygpath arguments
123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
125 | fi
126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
127 | i=0
128 | for arg in "$@" ; do
129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
131 |
132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
134 | else
135 | eval `echo args$i`="\"$arg\""
136 | fi
137 | i=$((i+1))
138 | done
139 | case $i in
140 | (0) set -- ;;
141 | (1) set -- "$args0" ;;
142 | (2) set -- "$args0" "$args1" ;;
143 | (3) set -- "$args0" "$args1" "$args2" ;;
144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
150 | esac
151 | fi
152 |
153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
154 | function splitJvmOpts() {
155 | JVM_OPTS=("$@")
156 | }
157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
159 |
160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
161 |
--------------------------------------------------------------------------------
/android/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/android/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
12 |
13 |
14 |
15 |
20 |
23 |
24 |
25 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/android/src/main/java/com/reactnative/ivpusic/imagepicker/Compression.java:
--------------------------------------------------------------------------------
1 | package com.reactnative.ivpusic.imagepicker;
2 |
3 | import android.app.Activity;
4 | import android.content.Context;
5 | import android.graphics.Bitmap;
6 | import android.graphics.BitmapFactory;
7 | import android.media.ExifInterface;
8 | import android.os.Environment;
9 | import android.util.Log;
10 | import android.util.Pair;
11 |
12 | import com.facebook.react.bridge.Promise;
13 | import com.facebook.react.bridge.ReadableMap;
14 |
15 | import java.io.BufferedOutputStream;
16 | import java.io.File;
17 | import java.io.FileOutputStream;
18 | import java.io.IOException;
19 | import java.io.OutputStream;
20 | import java.util.Arrays;
21 | import java.util.List;
22 | import java.util.UUID;
23 |
24 | /**
25 | * Created by ipusic on 12/27/16.
26 | */
27 |
28 | class Compression {
29 |
30 | File resize(
31 | Context context,
32 | String originalImagePath,
33 | int originalWidth,
34 | int originalHeight,
35 | int maxWidth,
36 | int maxHeight,
37 | int quality
38 | ) throws IOException,OutOfMemoryError {
39 | Pair targetDimensions =
40 | this.calculateTargetDimensions(originalWidth, originalHeight, maxWidth, maxHeight);
41 |
42 | int targetWidth = targetDimensions.first;
43 | int targetHeight = targetDimensions.second;
44 |
45 | Bitmap bitmap = null;
46 | if (originalWidth <= maxWidth && originalHeight <= maxHeight) {
47 | bitmap = BitmapFactory.decodeFile(originalImagePath);
48 | } else {
49 | BitmapFactory.Options options = new BitmapFactory.Options();
50 | options.inSampleSize = calculateInSampleSize(originalWidth, originalHeight, targetWidth, targetHeight);
51 | bitmap = BitmapFactory.decodeFile(originalImagePath, options);
52 | }
53 |
54 | // Use original image exif orientation data to preserve image orientation for the resized bitmap
55 | ExifInterface originalExif = new ExifInterface(originalImagePath);
56 | String originalOrientation = originalExif.getAttribute(ExifInterface.TAG_ORIENTATION);
57 |
58 | bitmap = Bitmap.createScaledBitmap(bitmap, targetWidth, targetHeight, true);
59 |
60 | File imageDirectory = context.getExternalFilesDir(Environment.DIRECTORY_PICTURES);
61 |
62 | if (!imageDirectory.exists()) {
63 | Log.d("image-crop-picker", "Pictures Directory is not existing. Will create this directory.");
64 | imageDirectory.mkdirs();
65 | }
66 |
67 | File resizeImageFile = new File(imageDirectory, UUID.randomUUID() + ".jpg");
68 |
69 | OutputStream os = new BufferedOutputStream(new FileOutputStream(resizeImageFile));
70 | bitmap.compress(Bitmap.CompressFormat.JPEG, quality, os);
71 |
72 | // Don't set unnecessary exif attribute
73 | if (shouldSetOrientation(originalOrientation)) {
74 | ExifInterface exif = new ExifInterface(resizeImageFile.getAbsolutePath());
75 | exif.setAttribute(ExifInterface.TAG_ORIENTATION, originalOrientation);
76 | exif.saveAttributes();
77 | }
78 |
79 | os.close();
80 | bitmap.recycle();
81 |
82 | return resizeImageFile;
83 | }
84 |
85 | private int calculateInSampleSize(int originalWidth, int originalHeight, int requestedWidth, int requestedHeight) {
86 | int inSampleSize = 1;
87 |
88 | if (originalWidth > requestedWidth || originalHeight > requestedHeight) {
89 | final int halfWidth = originalWidth / 2;
90 | final int halfHeight = originalHeight / 2;
91 |
92 | // Calculate the largest inSampleSize value that is a power of 2 and keeps both
93 | // height and width larger than the requested height and width.
94 | while ((halfWidth / inSampleSize) >= requestedWidth
95 | && (halfHeight / inSampleSize) >= requestedHeight) {
96 | inSampleSize *= 2;
97 | }
98 | }
99 |
100 | return inSampleSize;
101 | }
102 |
103 | private boolean shouldSetOrientation(String orientation) {
104 | return !orientation.equals(String.valueOf(ExifInterface.ORIENTATION_NORMAL))
105 | && !orientation.equals(String.valueOf(ExifInterface.ORIENTATION_UNDEFINED));
106 | }
107 |
108 | File compressImage(final Context context, final ReadableMap options, final String originalImagePath, final BitmapFactory.Options bitmapOptions) throws IOException,OutOfMemoryError {
109 | Integer maxWidth = options.hasKey("compressImageMaxWidth") ? options.getInt("compressImageMaxWidth") : null;
110 | Integer maxHeight = options.hasKey("compressImageMaxHeight") ? options.getInt("compressImageMaxHeight") : null;
111 | Double quality = options.hasKey("compressImageQuality") ? options.getDouble("compressImageQuality") : null;
112 |
113 | boolean isLossLess = (quality == null || quality == 1.0);
114 | boolean useOriginalWidth = (maxWidth == null || maxWidth >= bitmapOptions.outWidth);
115 | boolean useOriginalHeight = (maxHeight == null || maxHeight >= bitmapOptions.outHeight);
116 |
117 | List knownMimes = Arrays.asList("image/jpeg", "image/jpg", "image/png", "image/gif", "image/tiff");
118 | boolean isKnownMimeType = (bitmapOptions.outMimeType != null && knownMimes.contains(bitmapOptions.outMimeType.toLowerCase()));
119 |
120 | if (isLossLess && useOriginalWidth && useOriginalHeight && isKnownMimeType) {
121 | Log.d("image-crop-picker", "Skipping image compression");
122 | return new File(originalImagePath);
123 | }
124 |
125 | Log.d("image-crop-picker", "Image compression activated");
126 |
127 | // compression quality
128 | int targetQuality = quality != null ? (int) (quality * 100) : 100;
129 | Log.d("image-crop-picker", "Compressing image with quality " + targetQuality);
130 |
131 | if (maxWidth == null) maxWidth = bitmapOptions.outWidth;
132 | if (maxHeight == null) maxHeight = bitmapOptions.outHeight;
133 |
134 | return resize(context, originalImagePath, bitmapOptions.outWidth, bitmapOptions.outHeight, maxWidth, maxHeight, targetQuality);
135 | }
136 |
137 | private Pair calculateTargetDimensions(int currentWidth, int currentHeight, int maxWidth, int maxHeight) {
138 | int width = currentWidth;
139 | int height = currentHeight;
140 |
141 | if (width > maxWidth) {
142 | float ratio = ((float) maxWidth / width);
143 | height = (int) (height * ratio);
144 | width = maxWidth;
145 | }
146 |
147 | if (height > maxHeight) {
148 | float ratio = ((float) maxHeight / height);
149 | width = (int) (width * ratio);
150 | height = maxHeight;
151 | }
152 |
153 | return Pair.create(width, height);
154 | }
155 |
156 | synchronized void compressVideo(final Activity activity, final ReadableMap options, final String originalVideo, final String compressedVideo, final Promise promise) {
157 | // todo: video compression
158 | // failed attempt 1: ffmpeg => slow and licensing issues
159 | promise.resolve(originalVideo);
160 | }
161 | }
162 |
--------------------------------------------------------------------------------
/android/src/main/java/com/reactnative/ivpusic/imagepicker/ExifExtractor.java:
--------------------------------------------------------------------------------
1 | package com.reactnative.ivpusic.imagepicker;
2 |
3 | import android.media.ExifInterface;
4 | import android.os.Build;
5 |
6 | import com.facebook.react.bridge.WritableMap;
7 | import com.facebook.react.bridge.WritableNativeMap;
8 |
9 | import java.io.IOException;
10 | import java.util.ArrayList;
11 | import java.util.Arrays;
12 | import java.util.List;
13 |
14 | import static android.media.ExifInterface.*;
15 |
16 | class ExifExtractor {
17 |
18 | static WritableMap extract(String path) throws IOException {
19 | WritableMap exifData = new WritableNativeMap();
20 |
21 | List attributes = getBasicAttributes();
22 |
23 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
24 | attributes.addAll(getLevel23Attributes());
25 | }
26 |
27 | ExifInterface exif = new ExifInterface(path);
28 |
29 | try {
30 | GeoDegree geoDegree = new GeoDegree(exif);
31 | if (geoDegree.getLatitude() != null && geoDegree.getLongitude() != null) {
32 | exifData.putDouble("Latitude", geoDegree.getLatitude());
33 | exifData.putDouble("Longitude", geoDegree.getLongitude());
34 | }
35 | } catch (Exception e) {
36 | e.printStackTrace();
37 | }
38 |
39 | for (String attribute : attributes) {
40 | String value = exif.getAttribute(attribute);
41 | exifData.putString(attribute, value);
42 | }
43 |
44 | return exifData;
45 | }
46 |
47 | private static List getBasicAttributes() {
48 | return new ArrayList<>(Arrays.asList(
49 | TAG_APERTURE,
50 | TAG_DATETIME,
51 | TAG_EXPOSURE_TIME,
52 | TAG_FLASH,
53 | TAG_FOCAL_LENGTH,
54 | TAG_GPS_ALTITUDE,
55 | TAG_GPS_ALTITUDE_REF,
56 | TAG_GPS_DATESTAMP,
57 | TAG_GPS_LATITUDE,
58 | TAG_GPS_LATITUDE_REF,
59 | TAG_GPS_LONGITUDE,
60 | TAG_GPS_LONGITUDE_REF,
61 | TAG_GPS_PROCESSING_METHOD,
62 | TAG_GPS_TIMESTAMP,
63 | TAG_IMAGE_LENGTH,
64 | TAG_IMAGE_WIDTH,
65 | TAG_ISO,
66 | TAG_MAKE,
67 | TAG_MODEL,
68 | TAG_ORIENTATION,
69 | TAG_WHITE_BALANCE
70 | ));
71 | }
72 |
73 | private static List getLevel23Attributes() {
74 | return new ArrayList<>(Arrays.asList(
75 | TAG_DATETIME_DIGITIZED,
76 | TAG_SUBSEC_TIME,
77 | TAG_SUBSEC_TIME_DIG,
78 | TAG_SUBSEC_TIME_ORIG
79 | ));
80 | }
81 | }
--------------------------------------------------------------------------------
/android/src/main/java/com/reactnative/ivpusic/imagepicker/GeoDegree.java:
--------------------------------------------------------------------------------
1 | package com.reactnative.ivpusic.imagepicker;
2 |
3 | import android.media.ExifInterface;
4 |
5 | public class GeoDegree {
6 | Float latitude;
7 | Float longitude;
8 |
9 | public GeoDegree(ExifInterface exif) {
10 | String attrLATITUDE = exif.getAttribute(ExifInterface.TAG_GPS_LATITUDE);
11 | String attrLATITUDE_REF = exif.getAttribute(ExifInterface.TAG_GPS_LATITUDE_REF);
12 | String attrLONGITUDE = exif.getAttribute(ExifInterface.TAG_GPS_LONGITUDE);
13 | String attrLONGITUDE_REF = exif.getAttribute(ExifInterface.TAG_GPS_LONGITUDE_REF);
14 |
15 | if ((attrLATITUDE != null)
16 | && (attrLATITUDE_REF != null)
17 | && (attrLONGITUDE != null)
18 | && (attrLONGITUDE_REF != null)) {
19 |
20 | if (attrLATITUDE_REF.equals("N")) {
21 | latitude = convertToDegree(attrLATITUDE);
22 | } else {
23 | latitude = 0 - convertToDegree(attrLATITUDE);
24 | }
25 |
26 | if (attrLONGITUDE_REF.equals("E")) {
27 | longitude = convertToDegree(attrLONGITUDE);
28 | } else {
29 | longitude = 0 - convertToDegree(attrLONGITUDE);
30 | }
31 | }
32 | }
33 |
34 | private Float convertToDegree(String stringDMS) {
35 | Float result = null;
36 | String[] DMS = stringDMS.split(",", 3);
37 |
38 | String[] stringD = DMS[0].split("/", 2);
39 | Double D0 = Double.valueOf(stringD[0]);
40 | Double D1 = Double.valueOf(stringD[1]);
41 | double FloatD = D0 / D1;
42 |
43 | String[] stringM = DMS[1].split("/", 2);
44 | Double M0 = Double.valueOf(stringM[0]);
45 | Double M1 = Double.valueOf(stringM[1]);
46 | double FloatM = M0 / M1;
47 |
48 | String[] stringS = DMS[2].split("/", 2);
49 | Double S0 = Double.valueOf(stringS[0]);
50 | Double S1 = Double.valueOf(stringS[1]);
51 | double FloatS = S0 / S1;
52 |
53 | result = (float) (FloatD + (FloatM / 60) + (FloatS / 3600));
54 |
55 | return result;
56 | }
57 |
58 | public Float getLatitude() {
59 | return latitude;
60 | }
61 |
62 | public Float getLongitude() {
63 | return longitude;
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/android/src/main/java/com/reactnative/ivpusic/imagepicker/IvpusicImagePickerFileProvider.java:
--------------------------------------------------------------------------------
1 | package com.reactnative.ivpusic.imagepicker;
2 |
3 | import androidx.core.content.FileProvider;
4 |
5 | /**
6 | * A custom {@code FileProvider} prevents manifest {@code } name collisions.
7 | */
8 | public class IvpusicImagePickerFileProvider extends FileProvider {
9 | }
--------------------------------------------------------------------------------
/android/src/main/java/com/reactnative/ivpusic/imagepicker/PickerPackage.java:
--------------------------------------------------------------------------------
1 | package com.reactnative.ivpusic.imagepicker;
2 |
3 | import androidx.annotation.NonNull;
4 | import androidx.annotation.Nullable;
5 |
6 | import com.facebook.react.ReactPackage;
7 | import com.facebook.react.TurboReactPackage;
8 | import com.facebook.react.bridge.JavaScriptModule;
9 | import com.facebook.react.bridge.NativeModule;
10 | import com.facebook.react.bridge.ReactApplicationContext;
11 | import com.facebook.react.module.model.ReactModuleInfo;
12 | import com.facebook.react.module.model.ReactModuleInfoProvider;
13 | import com.facebook.react.uimanager.ViewManager;
14 |
15 | import java.util.ArrayList;
16 | import java.util.Collections;
17 | import java.util.HashMap;
18 | import java.util.List;
19 | import java.util.Map;
20 |
21 | import javax.annotation.Nonnull;
22 |
23 | /**
24 | * Created by ipusic on 5/16/16.
25 | */
26 | public class PickerPackage extends TurboReactPackage {
27 | @Override
28 | @Nonnull
29 | public List createNativeModules(@Nonnull ReactApplicationContext reactContext) {
30 | List modules = new ArrayList<>();
31 | modules.add(new PickerModule(reactContext));
32 | return modules;
33 | }
34 |
35 | @Nullable
36 | @Override
37 | public NativeModule getModule(@NonNull String name, @NonNull ReactApplicationContext reactContext) {
38 | if (name.equals(ImageCropPicker.NAME)) {
39 | return new PickerModule(reactContext);
40 | } else {
41 | return null;
42 | }
43 | }
44 |
45 | @Override
46 | public ReactModuleInfoProvider getReactModuleInfoProvider() {
47 | return () -> {
48 | final Map moduleInfos = new HashMap<>();
49 | boolean isTurboModule = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED;
50 | moduleInfos.put(
51 | ImageCropPicker.NAME,
52 | new ReactModuleInfo(
53 | ImageCropPicker.NAME,
54 | ImageCropPicker.NAME,
55 | false,
56 | false,
57 | false,
58 | isTurboModule
59 | ));
60 | return moduleInfos;
61 | };
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/android/src/main/java/com/reactnative/ivpusic/imagepicker/RealPathUtil.java:
--------------------------------------------------------------------------------
1 | package com.reactnative.ivpusic.imagepicker;
2 |
3 | import android.annotation.TargetApi;
4 | import android.content.ContentUris;
5 | import android.content.Context;
6 | import android.database.Cursor;
7 | import android.net.Uri;
8 | import android.os.Build;
9 | import android.os.Environment;
10 | import android.provider.DocumentsContract;
11 | import android.provider.MediaStore;
12 |
13 | import java.io.File;
14 | import java.io.FileOutputStream;
15 | import java.io.IOException;
16 | import java.io.InputStream;
17 |
18 | class RealPathUtil {
19 | @TargetApi(Build.VERSION_CODES.KITKAT)
20 | static String getRealPathFromURI(final Context context, final Uri uri) throws IOException {
21 |
22 | final boolean isKitKat = Build.VERSION.SDK_INT == Build.VERSION_CODES.KITKAT;
23 |
24 | // DocumentProvider
25 | if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {
26 | // ExternalStorageProvider
27 | if (isExternalStorageDocument(uri)) {
28 | final String docId = DocumentsContract.getDocumentId(uri);
29 | final String[] split = docId.split(":");
30 | final String type = split[0];
31 |
32 | if ("primary".equalsIgnoreCase(type)) {
33 | return Environment.getExternalStorageDirectory() + "/" + split[1];
34 | } else {
35 | final int splitIndex = docId.indexOf(':', 1);
36 | final String tag = docId.substring(0, splitIndex);
37 | final String path = docId.substring(splitIndex + 1);
38 |
39 | String nonPrimaryVolume = getPathToNonPrimaryVolume(context, tag);
40 | if (nonPrimaryVolume != null) {
41 | String result = nonPrimaryVolume + "/" + path;
42 | File file = new File(result);
43 | if (file.exists() && file.canRead()) {
44 | return result;
45 | }
46 | return null;
47 | }
48 | }
49 | }
50 | // DownloadsProvider
51 | else if (isDownloadsDocument(uri)) {
52 | final String id = DocumentsContract.getDocumentId(uri);
53 | final Uri contentUri = ContentUris.withAppendedId(
54 | Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));
55 |
56 | return getDataColumn(context, contentUri, null, null);
57 | }
58 | // MediaProvider
59 | else if (isMediaDocument(uri)) {
60 | final String docId = DocumentsContract.getDocumentId(uri);
61 | final String[] split = docId.split(":");
62 | final String type = split[0];
63 |
64 | Uri contentUri = null;
65 | if ("image".equals(type)) {
66 | contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
67 | } else if ("video".equals(type)) {
68 | contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
69 | } else if ("audio".equals(type)) {
70 | contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
71 | }
72 |
73 | final String selection = "_id=?";
74 | final String[] selectionArgs = new String[] {
75 | split[1]
76 | };
77 |
78 | return getDataColumn(context, contentUri, selection, selectionArgs);
79 | }
80 | }
81 | // MediaStore (and general)
82 | else if ("content".equalsIgnoreCase(uri.getScheme())) {
83 | // Return the remote address
84 | if (isGooglePhotosUri(uri))
85 | return uri.getLastPathSegment();
86 | return getDataColumn(context, uri, null, null);
87 | }
88 | // File
89 | else if ("file".equalsIgnoreCase(uri.getScheme())) {
90 | return uri.getPath();
91 | }
92 |
93 | return null;
94 | }
95 |
96 | /**
97 | * If an image/video has been selected from a cloud storage, this method
98 | * should be call to download the file in the cache folder.
99 | *
100 | * @param context The context
101 | * @param fileName donwloaded file's name
102 | * @param uri file's URI
103 | * @return file that has been written
104 | */
105 | private static File writeToFile(Context context, String fileName, Uri uri) {
106 | String tmpDir = context.getCacheDir() + "/react-native-image-crop-picker";
107 | Boolean created = new File(tmpDir).mkdir();
108 | fileName = fileName.substring(fileName.lastIndexOf('/') + 1);
109 | File path = new File(tmpDir);
110 | File file = new File(path, fileName);
111 | try {
112 | FileOutputStream oos = new FileOutputStream(file);
113 | byte[] buf = new byte[8192];
114 | InputStream is = context.getContentResolver().openInputStream(uri);
115 | int c = 0;
116 | while ((c = is.read(buf, 0, buf.length)) > 0) {
117 | oos.write(buf, 0, c);
118 | oos.flush();
119 | }
120 | oos.close();
121 | is.close();
122 | } catch (Exception e) {
123 | e.printStackTrace();
124 | }
125 | return file;
126 | }
127 |
128 | /**
129 | * Get the value of the data column for this Uri. This is useful for
130 | * MediaStore Uris, and other file-based ContentProviders.
131 | *
132 | * @param context The context.
133 | * @param uri The Uri to query.
134 | * @param selection (Optional) Filter used in the query.
135 | * @param selectionArgs (Optional) Selection arguments used in the query.
136 | * @return The value of the _data column, which is typically a file path.
137 | */
138 | private static String getDataColumn(Context context, Uri uri, String selection,
139 | String[] selectionArgs) {
140 |
141 | Cursor cursor = null;
142 | final String[] projection = {
143 | MediaStore.MediaColumns.DATA,
144 | MediaStore.MediaColumns.DISPLAY_NAME,
145 | };
146 |
147 | try {
148 | cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs,
149 | null);
150 | if (cursor != null && cursor.moveToFirst()) {
151 | // Fall back to writing to file if _data column does not exist
152 | final int index = cursor.getColumnIndex(MediaStore.MediaColumns.DATA);
153 | String path = index > -1 ? cursor.getString(index) : null;
154 | if (path != null) {
155 | return cursor.getString(index);
156 | } else {
157 | final int indexDisplayName = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DISPLAY_NAME);
158 | String fileName = cursor.getString(indexDisplayName);
159 | File fileWritten = writeToFile(context, fileName, uri);
160 | return fileWritten.getAbsolutePath();
161 | }
162 | }
163 | } finally {
164 | if (cursor != null)
165 | cursor.close();
166 | }
167 | return null;
168 | }
169 |
170 |
171 | /**
172 | * @param uri The Uri to check.
173 | * @return Whether the Uri authority is ExternalStorageProvider.
174 | */
175 | private static boolean isExternalStorageDocument(Uri uri) {
176 | return "com.android.externalstorage.documents".equals(uri.getAuthority());
177 | }
178 |
179 | /**
180 | * @param uri The Uri to check.
181 | * @return Whether the Uri authority is DownloadsProvider.
182 | */
183 | private static boolean isDownloadsDocument(Uri uri) {
184 | return "com.android.providers.downloads.documents".equals(uri.getAuthority());
185 | }
186 |
187 | /**
188 | * @param uri The Uri to check.
189 | * @return Whether the Uri authority is MediaProvider.
190 | */
191 | private static boolean isMediaDocument(Uri uri) {
192 | return "com.android.providers.media.documents".equals(uri.getAuthority());
193 | }
194 |
195 | /**
196 | * @param uri The Uri to check.
197 | * @return Whether the Uri authority is Google Photos.
198 | */
199 | private static boolean isGooglePhotosUri(Uri uri) {
200 | return "com.google.android.apps.photos.content".equals(uri.getAuthority());
201 | }
202 |
203 | @TargetApi(Build.VERSION_CODES.KITKAT)
204 | private static String getPathToNonPrimaryVolume(Context context, String tag) {
205 | File[] volumes = context.getExternalCacheDirs();
206 | if (volumes != null) {
207 | for (File volume : volumes) {
208 | if (volume != null) {
209 | String path = volume.getAbsolutePath();
210 | if (path != null) {
211 | int index = path.indexOf(tag);
212 | if (index != -1) {
213 | return path.substring(0, index) + tag;
214 | }
215 | }
216 | }
217 | }
218 | }
219 | return null;
220 | }
221 |
222 | }
223 |
--------------------------------------------------------------------------------
/android/src/main/java/com/reactnative/ivpusic/imagepicker/ResultCollector.java:
--------------------------------------------------------------------------------
1 | package com.reactnative.ivpusic.imagepicker;
2 |
3 | import android.util.Log;
4 |
5 | import com.facebook.react.bridge.Promise;
6 | import com.facebook.react.bridge.WritableArray;
7 | import com.facebook.react.bridge.WritableMap;
8 | import com.facebook.react.bridge.WritableNativeArray;
9 |
10 | import java.util.concurrent.atomic.AtomicInteger;
11 |
12 | /**
13 | * Created by ipusic on 12/28/16.
14 | */
15 |
16 | class ResultCollector {
17 | private Promise promise;
18 | private int waitCount;
19 | private boolean multiple;
20 | private AtomicInteger waitCounter;
21 | private WritableArray arrayResult;
22 | private boolean resultSent;
23 |
24 | synchronized void setup(Promise promise, boolean multiple) {
25 | this.promise = promise;
26 | this.multiple = multiple;
27 |
28 | this.resultSent = false;
29 | this.waitCount = 0;
30 | this.waitCounter = new AtomicInteger(0);
31 |
32 | if (multiple) {
33 | this.arrayResult = new WritableNativeArray();
34 | }
35 | }
36 |
37 | // if user has provided "multiple" option, we will wait for X number of result to come,
38 | // and also return result as an array
39 | synchronized void setWaitCount(int waitCount) {
40 | this.waitCount = waitCount;
41 | this.waitCounter = new AtomicInteger(0);
42 | }
43 |
44 | synchronized private boolean isRequestValid() {
45 | if (resultSent) {
46 | Log.w("image-crop-picker", "Skipping result, already sent...");
47 | return false;
48 | }
49 |
50 | if (promise == null) {
51 | Log.w("image-crop-picker", "Trying to notify success but promise is not set");
52 | return false;
53 | }
54 |
55 | return true;
56 | }
57 |
58 | synchronized void notifySuccess(WritableMap result) {
59 | if (!isRequestValid()) {
60 | return;
61 | }
62 |
63 | if (multiple) {
64 | arrayResult.pushMap(result);
65 | int currentCount = waitCounter.addAndGet(1);
66 |
67 | if (currentCount == waitCount) {
68 | promise.resolve(arrayResult);
69 | resultSent = true;
70 | }
71 | } else {
72 | promise.resolve(result);
73 | resultSent = true;
74 | }
75 | }
76 |
77 | synchronized void notifyProblem(String code, String message) {
78 | if (!isRequestValid()) {
79 | return;
80 | }
81 |
82 | Log.e("image-crop-picker", "Promise rejected. " + message);
83 | promise.reject(code, message);
84 | resultSent = true;
85 | }
86 |
87 | synchronized void notifyProblem(String code, Throwable throwable) {
88 | if (!isRequestValid()) {
89 | return;
90 | }
91 |
92 | Log.e("image-crop-picker", "Promise rejected. " + throwable.getMessage());
93 | promise.reject(code, throwable);
94 | resultSent = true;
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/android/src/main/res/xml/ivpusic_imagepicker_provider_paths.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/android/src/newArch/java/com/reactnative/ivpusic/imagepicker/PickerModule.java:
--------------------------------------------------------------------------------
1 | package com.reactnative.ivpusic.imagepicker;
2 |
3 | import com.facebook.react.bridge.Promise;
4 | import com.facebook.react.bridge.ReactApplicationContext;
5 | import com.facebook.react.bridge.ReactMethod;
6 | import com.facebook.react.bridge.ReadableMap;
7 | import com.facebook.react.module.annotations.ReactModule;
8 |
9 | @ReactModule(name = ImageCropPicker.NAME)
10 | public class PickerModule extends NativeImageCropPickerSpec {
11 | private final ImageCropPicker picker;
12 |
13 | public PickerModule(ReactApplicationContext reactContext) {
14 | super(reactContext);
15 | picker = new ImageCropPicker(reactContext);
16 | }
17 |
18 | @Override
19 | public void openPicker(ReadableMap options, Promise promise) {
20 | picker.openPicker(options, promise);
21 | }
22 |
23 | @Override
24 | public void openCamera(ReadableMap options, Promise promise) {
25 | picker.openCamera(options, promise);
26 | }
27 |
28 | @Override
29 | public void openCropper(ReadableMap options, Promise promise) {
30 | picker.openCropper(options, promise);
31 | }
32 |
33 | @Override
34 | public void clean(Promise promise) {
35 | picker.clean(promise);
36 | }
37 |
38 | @Override
39 | public void cleanSingle(String path, Promise promise) {
40 | picker.cleanSingle(path, promise);
41 | }
42 | }
--------------------------------------------------------------------------------
/android/src/oldArch/java/com/reactnative/ivpusic/imagepicker/PickerModule.java:
--------------------------------------------------------------------------------
1 | package com.reactnative.ivpusic.imagepicker;
2 |
3 | import androidx.annotation.NonNull;
4 |
5 | import com.facebook.react.bridge.Promise;
6 | import com.facebook.react.bridge.ReactApplicationContext;
7 | import com.facebook.react.bridge.ReactContextBaseJavaModule;
8 | import com.facebook.react.bridge.ReactMethod;
9 | import com.facebook.react.bridge.ReadableMap;
10 |
11 | public class PickerModule extends ReactContextBaseJavaModule {
12 | private final ImageCropPicker picker;
13 |
14 | public PickerModule(ReactApplicationContext reactContext) {
15 | super(reactContext);
16 | picker = new ImageCropPicker(reactContext);
17 | }
18 |
19 | @NonNull
20 | @Override
21 | public String getName() {
22 | return ImageCropPicker.NAME;
23 | }
24 |
25 | @ReactMethod
26 | public void openPicker(ReadableMap options, Promise promise) {
27 | picker.openPicker(options, promise);
28 | }
29 |
30 | @ReactMethod
31 | public void openCamera(ReadableMap options, Promise promise) {
32 | picker.openCamera(options, promise);
33 | }
34 |
35 | @ReactMethod
36 | public void openCropper(ReadableMap options, Promise promise) {
37 | picker.openCropper(options, promise);
38 | }
39 |
40 | @ReactMethod
41 | public void clean(Promise promise) {
42 | picker.clean(promise);
43 | }
44 |
45 | @ReactMethod
46 | public void cleanSingle(String path, Promise promise) {
47 | picker.cleanSingle(path, promise);
48 | }
49 | }
--------------------------------------------------------------------------------
/android/src/test/test.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/images/ios_circular_crop.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivpusic/react-native-image-crop-picker/748898a3d8ee1af82a333780f1f9bb6c62439d28/images/ios_circular_crop.png
--------------------------------------------------------------------------------
/images/ios_multiple_pick_v2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivpusic/react-native-image-crop-picker/748898a3d8ee1af82a333780f1f9bb6c62439d28/images/ios_multiple_pick_v2.png
--------------------------------------------------------------------------------
/images/ios_normal_crop.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivpusic/react-native-image-crop-picker/748898a3d8ee1af82a333780f1f9bb6c62439d28/images/ios_normal_crop.png
--------------------------------------------------------------------------------
/images/ios_single_pick_v2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivpusic/react-native-image-crop-picker/748898a3d8ee1af82a333780f1f9bb6c62439d28/images/ios_single_pick_v2.png
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | import ImageCropPicker from "./src/NativeImageCropPicker";
2 |
3 | export default ImageCropPicker;
4 | export const openPicker = ImageCropPicker.openPicker;
5 | export const openCamera = ImageCropPicker.openCamera;
6 | export const openCropper = ImageCropPicker.openCropper;
7 | export const clean = ImageCropPicker.clean;
8 | export const cleanSingle = ImageCropPicker.cleanSingle;
9 |
--------------------------------------------------------------------------------
/ios/ImageCropPickerSDK/QBImagePicker.framework/Headers/QBImagePicker.h:
--------------------------------------------------------------------------------
1 | //
2 | // QBImagePicker.h
3 | // QBImagePicker
4 | //
5 | // Created by Katsuma Tanaka on 2015/04/03.
6 | // Copyright (c) 2015 Katsuma Tanaka. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | //! Project version number for QBImagePicker.
12 | FOUNDATION_EXPORT double QBImagePickerVersionNumber;
13 |
14 | //! Project version string for QBImagePicker.
15 | FOUNDATION_EXPORT const unsigned char QBImagePickerVersionString[];
16 |
17 | // In this header, you should import all the public headers of your framework using statements like #import
18 | #import
19 |
--------------------------------------------------------------------------------
/ios/ImageCropPickerSDK/QBImagePicker.framework/Headers/QBImagePickerController.h:
--------------------------------------------------------------------------------
1 | //
2 | // QBImagePickerController.h
3 | // QBImagePicker
4 | //
5 | // Created by Katsuma Tanaka on 2015/04/03.
6 | // Copyright (c) 2015 Katsuma Tanaka. All rights reserved.
7 | //
8 |
9 | #import
10 | #import
11 |
12 | @class QBImagePickerController;
13 |
14 | @protocol QBImagePickerControllerDelegate
15 |
16 | @optional
17 | - (void)qb_imagePickerController:(QBImagePickerController *)imagePickerController didFinishPickingAssets:(NSArray *)assets;
18 | - (void)qb_imagePickerControllerDidCancel:(QBImagePickerController *)imagePickerController;
19 |
20 | - (BOOL)qb_imagePickerController:(QBImagePickerController *)imagePickerController shouldSelectAsset:(PHAsset *)asset;
21 | - (void)qb_imagePickerController:(QBImagePickerController *)imagePickerController didSelectAsset:(PHAsset *)asset;
22 | - (void)qb_imagePickerController:(QBImagePickerController *)imagePickerController didDeselectAsset:(PHAsset *)asset;
23 |
24 | @end
25 |
26 | typedef NS_ENUM(NSUInteger, QBImagePickerMediaType) {
27 | QBImagePickerMediaTypeAny = 0,
28 | QBImagePickerMediaTypeImage,
29 | QBImagePickerMediaTypeVideo
30 | };
31 |
32 | @interface QBImagePickerController : UIViewController
33 |
34 | @property (nonatomic, weak) id delegate;
35 |
36 | @property (nonatomic, strong, readonly) NSMutableOrderedSet *selectedAssets;
37 |
38 | @property (nonatomic, copy) NSArray *assetCollectionSubtypes;
39 | @property (nonatomic, assign) QBImagePickerMediaType mediaType;
40 |
41 | @property (nonatomic, assign) BOOL allowsMultipleSelection;
42 | @property (nonatomic, assign) NSUInteger minimumNumberOfSelection;
43 | @property (nonatomic, assign) NSUInteger maximumNumberOfSelection;
44 |
45 | @property (nonatomic, copy) NSString *prompt;
46 | @property (nonatomic, assign) BOOL showsNumberOfSelectedAssets;
47 |
48 | @property (nonatomic, assign) NSUInteger numberOfColumnsInPortrait;
49 | @property (nonatomic, assign) NSUInteger numberOfColumnsInLandscape;
50 |
51 | @end
52 |
--------------------------------------------------------------------------------
/ios/ImageCropPickerSDK/QBImagePicker.framework/Info.plist:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivpusic/react-native-image-crop-picker/748898a3d8ee1af82a333780f1f9bb6c62439d28/ios/ImageCropPickerSDK/QBImagePicker.framework/Info.plist
--------------------------------------------------------------------------------
/ios/ImageCropPickerSDK/QBImagePicker.framework/Modules/module.modulemap:
--------------------------------------------------------------------------------
1 | framework module QBImagePicker {
2 | umbrella header "QBImagePicker.h"
3 |
4 | export *
5 | module * { export * }
6 | }
7 |
--------------------------------------------------------------------------------
/ios/ImageCropPickerSDK/QBImagePicker.framework/QBImagePicker:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivpusic/react-native-image-crop-picker/748898a3d8ee1af82a333780f1f9bb6c62439d28/ios/ImageCropPickerSDK/QBImagePicker.framework/QBImagePicker
--------------------------------------------------------------------------------
/ios/ImageCropPickerSDK/QBImagePicker.framework/QBImagePicker.storyboardc/Info.plist:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivpusic/react-native-image-crop-picker/748898a3d8ee1af82a333780f1f9bb6c62439d28/ios/ImageCropPickerSDK/QBImagePicker.framework/QBImagePicker.storyboardc/Info.plist
--------------------------------------------------------------------------------
/ios/ImageCropPickerSDK/QBImagePicker.framework/QBImagePicker.storyboardc/QBAlbumsNavigationController.nib:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivpusic/react-native-image-crop-picker/748898a3d8ee1af82a333780f1f9bb6c62439d28/ios/ImageCropPickerSDK/QBImagePicker.framework/QBImagePicker.storyboardc/QBAlbumsNavigationController.nib
--------------------------------------------------------------------------------
/ios/ImageCropPickerSDK/QBImagePicker.framework/QBImagePicker.storyboardc/QBAlbumsViewController.nib:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivpusic/react-native-image-crop-picker/748898a3d8ee1af82a333780f1f9bb6c62439d28/ios/ImageCropPickerSDK/QBImagePicker.framework/QBImagePicker.storyboardc/QBAlbumsViewController.nib
--------------------------------------------------------------------------------
/ios/ImageCropPickerSDK/QBImagePicker.framework/QBImagePicker.storyboardc/QBAssetsViewController.nib:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivpusic/react-native-image-crop-picker/748898a3d8ee1af82a333780f1f9bb6c62439d28/ios/ImageCropPickerSDK/QBImagePicker.framework/QBImagePicker.storyboardc/QBAssetsViewController.nib
--------------------------------------------------------------------------------
/ios/ImageCropPickerSDK/QBImagePicker.framework/QBImagePicker.storyboardc/QL5-wR-LYt-view-66K-TS-Yoc.nib:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivpusic/react-native-image-crop-picker/748898a3d8ee1af82a333780f1f9bb6c62439d28/ios/ImageCropPickerSDK/QBImagePicker.framework/QBImagePicker.storyboardc/QL5-wR-LYt-view-66K-TS-Yoc.nib
--------------------------------------------------------------------------------
/ios/ImageCropPickerSDK/QBImagePicker.framework/QBImagePicker.storyboardc/QiH-NZ-ZGN-view-sD2-zK-ryo.nib:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivpusic/react-native-image-crop-picker/748898a3d8ee1af82a333780f1f9bb6c62439d28/ios/ImageCropPickerSDK/QBImagePicker.framework/QBImagePicker.storyboardc/QiH-NZ-ZGN-view-sD2-zK-ryo.nib
--------------------------------------------------------------------------------
/ios/ImageCropPickerSDK/QBImagePicker.framework/_CodeSignature/CodeResources:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | files
6 |
7 | Headers/QBImagePicker.h
8 |
9 | wIb/otiZ7bd2vyPJQF6JEeoqhqo=
10 |
11 | Headers/QBImagePickerController.h
12 |
13 | Pj/03SZs3R39/KDJC/Sw28hOcV4=
14 |
15 | Info.plist
16 |
17 | IcCz/8UZ07kkFONGwju3BBUrdSA=
18 |
19 | Modules/module.modulemap
20 |
21 | b8XazA/6z0jSXdJ08gOuLFgiplM=
22 |
23 | QBImagePicker.storyboardc/Info.plist
24 |
25 | iwZHbHPu3m3FYRI+FCDLbHeFs44=
26 |
27 | QBImagePicker.storyboardc/QBAlbumsNavigationController.nib
28 |
29 | 5MCnX6u0y0SAVdmtiddUomh9GyY=
30 |
31 | QBImagePicker.storyboardc/QBAlbumsViewController.nib
32 |
33 | pY80pANgQzeIQuYM9GWFeoXUSxQ=
34 |
35 | QBImagePicker.storyboardc/QBAssetsViewController.nib
36 |
37 | 7+OaszKW0bhc6RotWxC0o0SijKw=
38 |
39 | QBImagePicker.storyboardc/QL5-wR-LYt-view-66K-TS-Yoc.nib
40 |
41 | 0xNFW/713RpJkWqwnLEP8bUWcuI=
42 |
43 | QBImagePicker.storyboardc/QiH-NZ-ZGN-view-sD2-zK-ryo.nib
44 |
45 | Fj2aIfr+Es6yrxOSQzP/3Uhvvvs=
46 |
47 | de.lproj/QBImagePicker.strings
48 |
49 | hash
50 |
51 | aEwah75TRZyK1k7zsKbitGOHsEE=
52 |
53 | optional
54 |
55 |
56 | en.lproj/QBImagePicker.strings
57 |
58 | hash
59 |
60 | /bN8mAXwM04zgDQj19s7yTHxKQs=
61 |
62 | optional
63 |
64 |
65 | es.lproj/QBImagePicker.strings
66 |
67 | hash
68 |
69 | 3E8xykBQDKx9XRx4cigrfFeoUwo=
70 |
71 | optional
72 |
73 |
74 | ja.lproj/QBImagePicker.strings
75 |
76 | hash
77 |
78 | 7j4cVfYmTo9Yfo4fA9g4AvzTLhw=
79 |
80 | optional
81 |
82 |
83 | pl.lproj/QBImagePicker.strings
84 |
85 | hash
86 |
87 | LfadkhKMCL8TGzZnnEP7Pbsb0I4=
88 |
89 | optional
90 |
91 |
92 | zh-Hans.lproj/QBImagePicker.strings
93 |
94 | hash
95 |
96 | 0F5a3/dLVWvW3skcaXrrOpnhPv0=
97 |
98 | optional
99 |
100 |
101 |
102 | files2
103 |
104 | Headers/QBImagePicker.h
105 |
106 | hash
107 |
108 | wIb/otiZ7bd2vyPJQF6JEeoqhqo=
109 |
110 | hash2
111 |
112 | Fh9fdGZCY2P54hZbKvAZwwcML6IHufU9QAmHXrcmAMI=
113 |
114 |
115 | Headers/QBImagePickerController.h
116 |
117 | hash
118 |
119 | Pj/03SZs3R39/KDJC/Sw28hOcV4=
120 |
121 | hash2
122 |
123 | WcCD5/uhcGaZMLBPYHrRY/JkiB7BPQZqn5rkufhmY8c=
124 |
125 |
126 | Modules/module.modulemap
127 |
128 | hash
129 |
130 | b8XazA/6z0jSXdJ08gOuLFgiplM=
131 |
132 | hash2
133 |
134 | t0ZEP5nTTzs177dyaKMwGF/sZUJu1h9MPbMCcGQ7acw=
135 |
136 |
137 | QBImagePicker.storyboardc/Info.plist
138 |
139 | hash
140 |
141 | iwZHbHPu3m3FYRI+FCDLbHeFs44=
142 |
143 | hash2
144 |
145 | gyFhkTx7M92K1jKJpSG0Yl9R+mQfrd/YtnmTaP54ukY=
146 |
147 |
148 | QBImagePicker.storyboardc/QBAlbumsNavigationController.nib
149 |
150 | hash
151 |
152 | 5MCnX6u0y0SAVdmtiddUomh9GyY=
153 |
154 | hash2
155 |
156 | SLNRGZnuwERXFNcJLu1791ZVDMDsNnnk49Xb01ZjoZo=
157 |
158 |
159 | QBImagePicker.storyboardc/QBAlbumsViewController.nib
160 |
161 | hash
162 |
163 | pY80pANgQzeIQuYM9GWFeoXUSxQ=
164 |
165 | hash2
166 |
167 | KiZiF6NMbTf2YFOEQs4U1Yef9CSUk8GUiApZAjwtnOM=
168 |
169 |
170 | QBImagePicker.storyboardc/QBAssetsViewController.nib
171 |
172 | hash
173 |
174 | 7+OaszKW0bhc6RotWxC0o0SijKw=
175 |
176 | hash2
177 |
178 | PLJdoPEFJT4ItZgiMWCnK0GDoCTxbI/2wAwBBb8l3wM=
179 |
180 |
181 | QBImagePicker.storyboardc/QL5-wR-LYt-view-66K-TS-Yoc.nib
182 |
183 | hash
184 |
185 | 0xNFW/713RpJkWqwnLEP8bUWcuI=
186 |
187 | hash2
188 |
189 | ey42W/ZWm6W0Eea8Q4i9o79eTvpujgSK8HU9PTkbS/4=
190 |
191 |
192 | QBImagePicker.storyboardc/QiH-NZ-ZGN-view-sD2-zK-ryo.nib
193 |
194 | hash
195 |
196 | Fj2aIfr+Es6yrxOSQzP/3Uhvvvs=
197 |
198 | hash2
199 |
200 | 0iH5b4oLNN+sXyFq/BdGICtJzSnj4ll873t0puG4aqM=
201 |
202 |
203 | de.lproj/QBImagePicker.strings
204 |
205 | hash
206 |
207 | aEwah75TRZyK1k7zsKbitGOHsEE=
208 |
209 | hash2
210 |
211 | 5NH6glXlP7txoHgxKL83/BqWApGAb0poqKByJ1yo+9c=
212 |
213 | optional
214 |
215 |
216 | en.lproj/QBImagePicker.strings
217 |
218 | hash
219 |
220 | /bN8mAXwM04zgDQj19s7yTHxKQs=
221 |
222 | hash2
223 |
224 | xZGH0lOWeKlYEMMZNToG0j+vQVTgUTNoydCOJBG+Kjs=
225 |
226 | optional
227 |
228 |
229 | es.lproj/QBImagePicker.strings
230 |
231 | hash
232 |
233 | 3E8xykBQDKx9XRx4cigrfFeoUwo=
234 |
235 | hash2
236 |
237 | T0LWvjKc9Wmuxznj7gCFXRNeGYuFiF92kDcjOVI/WPo=
238 |
239 | optional
240 |
241 |
242 | ja.lproj/QBImagePicker.strings
243 |
244 | hash
245 |
246 | 7j4cVfYmTo9Yfo4fA9g4AvzTLhw=
247 |
248 | hash2
249 |
250 | jxfNgX8MVlO7C53RGOjJwPc1dcSj9DxTyWW8N37BkaE=
251 |
252 | optional
253 |
254 |
255 | pl.lproj/QBImagePicker.strings
256 |
257 | hash
258 |
259 | LfadkhKMCL8TGzZnnEP7Pbsb0I4=
260 |
261 | hash2
262 |
263 | BQCDVBKWaLio8bCJuurR2oc3ENu7K8c6N9ECEh98owU=
264 |
265 | optional
266 |
267 |
268 | zh-Hans.lproj/QBImagePicker.strings
269 |
270 | hash
271 |
272 | 0F5a3/dLVWvW3skcaXrrOpnhPv0=
273 |
274 | hash2
275 |
276 | smMz2/UyQzPo54Zq6lLJj+H42kPbfO4Bfy0iP1jCyf8=
277 |
278 | optional
279 |
280 |
281 |
282 | rules
283 |
284 | ^
285 |
286 | ^.*\.lproj/
287 |
288 | optional
289 |
290 | weight
291 | 1000
292 |
293 | ^.*\.lproj/locversion.plist$
294 |
295 | omit
296 |
297 | weight
298 | 1100
299 |
300 | ^version.plist$
301 |
302 |
303 | rules2
304 |
305 | .*\.dSYM($|/)
306 |
307 | weight
308 | 11
309 |
310 | ^
311 |
312 | weight
313 | 20
314 |
315 | ^(.*/)?\.DS_Store$
316 |
317 | omit
318 |
319 | weight
320 | 2000
321 |
322 | ^(Frameworks|SharedFrameworks|PlugIns|Plug-ins|XPCServices|Helpers|MacOS|Library/(Automator|Spotlight|LoginItems))/
323 |
324 | nested
325 |
326 | weight
327 | 10
328 |
329 | ^.*
330 |
331 | ^.*\.lproj/
332 |
333 | optional
334 |
335 | weight
336 | 1000
337 |
338 | ^.*\.lproj/locversion.plist$
339 |
340 | omit
341 |
342 | weight
343 | 1100
344 |
345 | ^Info\.plist$
346 |
347 | omit
348 |
349 | weight
350 | 20
351 |
352 | ^PkgInfo$
353 |
354 | omit
355 |
356 | weight
357 | 20
358 |
359 | ^[^/]+$
360 |
361 | nested
362 |
363 | weight
364 | 10
365 |
366 | ^embedded\.provisionprofile$
367 |
368 | weight
369 | 20
370 |
371 | ^version\.plist$
372 |
373 | weight
374 | 20
375 |
376 |
377 |
378 |
379 |
--------------------------------------------------------------------------------
/ios/ImageCropPickerSDK/QBImagePicker.framework/de.lproj/QBImagePicker.strings:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivpusic/react-native-image-crop-picker/748898a3d8ee1af82a333780f1f9bb6c62439d28/ios/ImageCropPickerSDK/QBImagePicker.framework/de.lproj/QBImagePicker.strings
--------------------------------------------------------------------------------
/ios/ImageCropPickerSDK/QBImagePicker.framework/en.lproj/QBImagePicker.strings:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivpusic/react-native-image-crop-picker/748898a3d8ee1af82a333780f1f9bb6c62439d28/ios/ImageCropPickerSDK/QBImagePicker.framework/en.lproj/QBImagePicker.strings
--------------------------------------------------------------------------------
/ios/ImageCropPickerSDK/QBImagePicker.framework/es.lproj/QBImagePicker.strings:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivpusic/react-native-image-crop-picker/748898a3d8ee1af82a333780f1f9bb6c62439d28/ios/ImageCropPickerSDK/QBImagePicker.framework/es.lproj/QBImagePicker.strings
--------------------------------------------------------------------------------
/ios/ImageCropPickerSDK/QBImagePicker.framework/ja.lproj/QBImagePicker.strings:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivpusic/react-native-image-crop-picker/748898a3d8ee1af82a333780f1f9bb6c62439d28/ios/ImageCropPickerSDK/QBImagePicker.framework/ja.lproj/QBImagePicker.strings
--------------------------------------------------------------------------------
/ios/ImageCropPickerSDK/QBImagePicker.framework/pl.lproj/QBImagePicker.strings:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivpusic/react-native-image-crop-picker/748898a3d8ee1af82a333780f1f9bb6c62439d28/ios/ImageCropPickerSDK/QBImagePicker.framework/pl.lproj/QBImagePicker.strings
--------------------------------------------------------------------------------
/ios/ImageCropPickerSDK/QBImagePicker.framework/zh-Hans.lproj/QBImagePicker.strings:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivpusic/react-native-image-crop-picker/748898a3d8ee1af82a333780f1f9bb6c62439d28/ios/ImageCropPickerSDK/QBImagePicker.framework/zh-Hans.lproj/QBImagePicker.strings
--------------------------------------------------------------------------------
/ios/PrivacyInfo.xcprivacy:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | NSPrivacyAccessedAPITypes
6 |
7 |
8 | NSPrivacyAccessedAPITypeReasons
9 |
10 | 3B52.1
11 |
12 | NSPrivacyAccessedAPIType
13 | NSPrivacyAccessedAPICategoryFileTimestamp
14 |
15 |
16 | NSPrivacyCollectedDataTypes
17 |
18 |
19 | NSPrivacyCollectedDataType
20 | NSPrivacyCollectedDataTypePhotosorVideos
21 | NSPrivacyCollectedDataTypeLinked
22 |
23 | NSPrivacyCollectedDataTypeTracking
24 |
25 | NSPrivacyCollectedDataTypePurposes
26 |
27 | NSPrivacyCollectedDataTypePurposeAppFunctionality
28 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/ios/QBImagePicker/.gitignore:
--------------------------------------------------------------------------------
1 | # Created by https://www.gitignore.io
2 |
3 | ### OSX ###
4 | .DS_Store
5 | .AppleDouble
6 | .LSOverride
7 |
8 | # Icon must end with two \r
9 | Icon
10 |
11 | # Thumbnails
12 | ._*
13 |
14 | # Files that might appear in the root of a volume
15 | .DocumentRevisions-V100
16 | .fseventsd
17 | .Spotlight-V100
18 | .TemporaryItems
19 | .Trashes
20 | .VolumeIcon.icns
21 |
22 | # Directories potentially created on remote AFP share
23 | .AppleDB
24 | .AppleDesktop
25 | Network Trash Folder
26 | Temporary Items
27 | .apdisk
28 |
29 |
30 | ### Xcode ###
31 | build/
32 | *.pbxuser
33 | !default.pbxuser
34 | *.mode1v3
35 | !default.mode1v3
36 | *.mode2v3
37 | !default.mode2v3
38 | *.perspectivev3
39 | !default.perspectivev3
40 | xcuserdata
41 | *.xccheckout
42 | *.moved-aside
43 | DerivedData
44 | *.xcuserstate
45 |
46 |
47 | ### Objective-C ###
48 | # Xcode
49 | #
50 | build/
51 | *.pbxuser
52 | !default.pbxuser
53 | *.mode1v3
54 | !default.mode1v3
55 | *.mode2v3
56 | !default.mode2v3
57 | *.perspectivev3
58 | !default.perspectivev3
59 | xcuserdata
60 | *.xccheckout
61 | *.moved-aside
62 | DerivedData
63 | *.hmap
64 | *.ipa
65 | *.xcuserstate
66 |
67 | # CocoaPods
68 | #
69 | # We recommend against adding the Pods directory to your .gitignore. However
70 | # you should judge for yourself, the pros and cons are mentioned at:
71 | # http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control
72 | #
73 | # Pods/
74 |
75 | # Carthage
76 | #
77 | # Add this line if you want to avoid checking in source code from Carthage dependencies.
78 | # Carthage/Checkouts
79 |
80 | Carthage/Build
81 |
--------------------------------------------------------------------------------
/ios/QBImagePicker/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2015 Katsuma Tanaka
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4 |
5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6 |
7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
8 |
--------------------------------------------------------------------------------
/ios/QBImagePicker/QBImagePicker.xcodeproj/xcshareddata/xcschemes/QBImagePicker.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
29 |
35 |
36 |
37 |
38 |
39 |
44 |
45 |
47 |
53 |
54 |
55 |
56 |
57 |
63 |
64 |
65 |
66 |
67 |
68 |
78 |
79 |
85 |
86 |
87 |
88 |
89 |
90 |
96 |
97 |
103 |
104 |
105 |
106 |
108 |
109 |
112 |
113 |
114 |
--------------------------------------------------------------------------------
/ios/QBImagePicker/QBImagePicker/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 3.4.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | $(CURRENT_PROJECT_VERSION)
23 | NSPrincipalClass
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/ios/QBImagePicker/QBImagePicker/QBAlbumCell.h:
--------------------------------------------------------------------------------
1 | //
2 | // QBAlbumCell.h
3 | // QBImagePicker
4 | //
5 | // Created by Katsuma Tanaka on 2015/04/03.
6 | // Copyright (c) 2015 Katsuma Tanaka. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface QBAlbumCell : UITableViewCell
12 |
13 | @property (weak, nonatomic) IBOutlet UIImageView *imageView1;
14 | @property (weak, nonatomic) IBOutlet UIImageView *imageView2;
15 | @property (weak, nonatomic) IBOutlet UIImageView *imageView3;
16 | @property (weak, nonatomic) IBOutlet UILabel *titleLabel;
17 | @property (weak, nonatomic) IBOutlet UILabel *countLabel;
18 |
19 | @property (nonatomic, assign) CGFloat borderWidth;
20 |
21 | @end
22 |
--------------------------------------------------------------------------------
/ios/QBImagePicker/QBImagePicker/QBAlbumCell.m:
--------------------------------------------------------------------------------
1 | //
2 | // QBAlbumCell.m
3 | // QBImagePicker
4 | //
5 | // Created by Katsuma Tanaka on 2015/04/03.
6 | // Copyright (c) 2015 Katsuma Tanaka. All rights reserved.
7 | //
8 |
9 | #import "QBAlbumCell.h"
10 |
11 | @implementation QBAlbumCell
12 |
13 | - (void)setBorderWidth:(CGFloat)borderWidth
14 | {
15 | _borderWidth = borderWidth;
16 |
17 | self.imageView1.layer.borderColor = [[UIColor whiteColor] CGColor];
18 | self.imageView1.layer.borderWidth = borderWidth;
19 |
20 | self.imageView2.layer.borderColor = [[UIColor whiteColor] CGColor];
21 | self.imageView2.layer.borderWidth = borderWidth;
22 |
23 | self.imageView3.layer.borderColor = [[UIColor whiteColor] CGColor];
24 | self.imageView3.layer.borderWidth = borderWidth;
25 | }
26 |
27 | @end
28 |
--------------------------------------------------------------------------------
/ios/QBImagePicker/QBImagePicker/QBAlbumsViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // QBAlbumsViewController.h
3 | // QBImagePicker
4 | //
5 | // Created by Katsuma Tanaka on 2015/04/03.
6 | // Copyright (c) 2015 Katsuma Tanaka. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @class QBImagePickerController;
12 |
13 | @interface QBAlbumsViewController : UITableViewController
14 |
15 | @property (nonatomic, weak) QBImagePickerController *imagePickerController;
16 |
17 | @end
18 |
--------------------------------------------------------------------------------
/ios/QBImagePicker/QBImagePicker/QBAssetCell.h:
--------------------------------------------------------------------------------
1 | //
2 | // QBAssetCell.h
3 | // QBImagePicker
4 | //
5 | // Created by Katsuma Tanaka on 2015/04/03.
6 | // Copyright (c) 2015 Katsuma Tanaka. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @class QBVideoIndicatorView;
12 |
13 | @interface QBAssetCell : UICollectionViewCell
14 |
15 | @property (weak, nonatomic) IBOutlet UIImageView *imageView;
16 | @property (weak, nonatomic) IBOutlet QBVideoIndicatorView *videoIndicatorView;
17 |
18 | @property (nonatomic, assign) BOOL showsOverlayViewWhenSelected;
19 |
20 | @end
21 |
--------------------------------------------------------------------------------
/ios/QBImagePicker/QBImagePicker/QBAssetCell.m:
--------------------------------------------------------------------------------
1 | //
2 | // QBAssetCell.m
3 | // QBImagePicker
4 | //
5 | // Created by Katsuma Tanaka on 2015/04/03.
6 | // Copyright (c) 2015 Katsuma Tanaka. All rights reserved.
7 | //
8 |
9 | #import "QBAssetCell.h"
10 |
11 | @interface QBAssetCell ()
12 |
13 | @property (weak, nonatomic) IBOutlet UIView *overlayView;
14 |
15 | @end
16 |
17 | @implementation QBAssetCell
18 |
19 | - (void)setSelected:(BOOL)selected
20 | {
21 | [super setSelected:selected];
22 |
23 | // Show/hide overlay view
24 | self.overlayView.hidden = !(selected && self.showsOverlayViewWhenSelected);
25 | }
26 |
27 | @end
28 |
--------------------------------------------------------------------------------
/ios/QBImagePicker/QBImagePicker/QBAssetsViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // QBAssetsViewController.h
3 | // QBImagePicker
4 | //
5 | // Created by Katsuma Tanaka on 2015/04/03.
6 | // Copyright (c) 2015 Katsuma Tanaka. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @class QBImagePickerController;
12 | @class PHAssetCollection;
13 |
14 | @interface QBAssetsViewController : UICollectionViewController
15 |
16 | @property (nonatomic, weak) QBImagePickerController *imagePickerController;
17 | @property (nonatomic, strong) PHAssetCollection *assetCollection;
18 |
19 | @end
20 |
--------------------------------------------------------------------------------
/ios/QBImagePicker/QBImagePicker/QBCheckmarkView.h:
--------------------------------------------------------------------------------
1 | //
2 | // QBCheckmarkView.h
3 | // QBImagePicker
4 | //
5 | // Created by Katsuma Tanaka on 2015/04/03.
6 | // Copyright (c) 2015 Katsuma Tanaka. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | IB_DESIGNABLE
12 | @interface QBCheckmarkView : UIView
13 |
14 | @property (nonatomic, assign) IBInspectable CGFloat borderWidth;
15 | @property (nonatomic, assign) IBInspectable CGFloat checkmarkLineWidth;
16 |
17 | @property (nonatomic, strong) IBInspectable UIColor *borderColor;
18 | @property (nonatomic, strong) IBInspectable UIColor *bodyColor;
19 | @property (nonatomic, strong) IBInspectable UIColor *checkmarkColor;
20 |
21 | @end
22 |
--------------------------------------------------------------------------------
/ios/QBImagePicker/QBImagePicker/QBCheckmarkView.m:
--------------------------------------------------------------------------------
1 | //
2 | // QBCheckmarkView.m
3 | // QBImagePicker
4 | //
5 | // Created by Katsuma Tanaka on 2015/04/03.
6 | // Copyright (c) 2015 Katsuma Tanaka. All rights reserved.
7 | //
8 |
9 | #import "QBCheckmarkView.h"
10 |
11 | @implementation QBCheckmarkView
12 |
13 | - (void)awakeFromNib
14 | {
15 | [super awakeFromNib];
16 |
17 | // Set default values
18 | self.borderWidth = 1.0;
19 | self.checkmarkLineWidth = 1.2;
20 |
21 | self.borderColor = [UIColor whiteColor];
22 | self.bodyColor = [UIColor colorWithRed:(20.0 / 255.0) green:(111.0 / 255.0) blue:(223.0 / 255.0) alpha:1.0];
23 | self.checkmarkColor = [UIColor whiteColor];
24 |
25 | // Set shadow
26 | self.layer.shadowColor = [[UIColor grayColor] CGColor];
27 | self.layer.shadowOffset = CGSizeMake(0, 0);
28 | self.layer.shadowOpacity = 0.6;
29 | self.layer.shadowRadius = 2.0;
30 | }
31 |
32 | - (void)drawRect:(CGRect)rect
33 | {
34 | // Border
35 | [self.borderColor setFill];
36 | [[UIBezierPath bezierPathWithOvalInRect:self.bounds] fill];
37 |
38 | // Body
39 | [self.bodyColor setFill];
40 | [[UIBezierPath bezierPathWithOvalInRect:CGRectInset(self.bounds, self.borderWidth, self.borderWidth)] fill];
41 |
42 | // Checkmark
43 | UIBezierPath *checkmarkPath = [UIBezierPath bezierPath];
44 | checkmarkPath.lineWidth = self.checkmarkLineWidth;
45 |
46 | [checkmarkPath moveToPoint:CGPointMake(CGRectGetWidth(self.bounds) * (6.0 / 24.0), CGRectGetHeight(self.bounds) * (12.0 / 24.0))];
47 | [checkmarkPath addLineToPoint:CGPointMake(CGRectGetWidth(self.bounds) * (10.0 / 24.0), CGRectGetHeight(self.bounds) * (16.0 / 24.0))];
48 | [checkmarkPath addLineToPoint:CGPointMake(CGRectGetWidth(self.bounds) * (18.0 / 24.0), CGRectGetHeight(self.bounds) * (8.0 / 24.0))];
49 |
50 | [self.checkmarkColor setStroke];
51 | [checkmarkPath stroke];
52 | }
53 |
54 | @end
55 |
--------------------------------------------------------------------------------
/ios/QBImagePicker/QBImagePicker/QBImagePicker.h:
--------------------------------------------------------------------------------
1 | //
2 | // QBImagePicker.h
3 | // QBImagePicker
4 | //
5 | // Created by Katsuma Tanaka on 2015/04/03.
6 | // Copyright (c) 2015 Katsuma Tanaka. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | //! Project version number for QBImagePicker.
12 | FOUNDATION_EXPORT double QBImagePickerVersionNumber;
13 |
14 | //! Project version string for QBImagePicker.
15 | FOUNDATION_EXPORT const unsigned char QBImagePickerVersionString[];
16 |
17 | // In this header, you should import all the public headers of your framework using statements like #import
18 | #import
19 |
--------------------------------------------------------------------------------
/ios/QBImagePicker/QBImagePicker/QBImagePickerController.h:
--------------------------------------------------------------------------------
1 | //
2 | // QBImagePickerController.h
3 | // QBImagePicker
4 | //
5 | // Created by Katsuma Tanaka on 2015/04/03.
6 | // Copyright (c) 2015 Katsuma Tanaka. All rights reserved.
7 | //
8 |
9 | #import
10 | #import
11 |
12 | @class QBImagePickerController;
13 |
14 | @protocol QBImagePickerControllerDelegate
15 |
16 | @optional
17 | - (void)qb_imagePickerController:(QBImagePickerController *)imagePickerController didFinishPickingAssets:(NSArray *)assets;
18 | - (void)qb_imagePickerControllerDidCancel:(QBImagePickerController *)imagePickerController;
19 |
20 | - (BOOL)qb_imagePickerController:(QBImagePickerController *)imagePickerController shouldSelectAsset:(PHAsset *)asset;
21 | - (void)qb_imagePickerController:(QBImagePickerController *)imagePickerController didSelectAsset:(PHAsset *)asset;
22 | - (void)qb_imagePickerController:(QBImagePickerController *)imagePickerController didDeselectAsset:(PHAsset *)asset;
23 |
24 | @end
25 |
26 | typedef NS_ENUM(NSUInteger, QBImagePickerMediaType) {
27 | QBImagePickerMediaTypeAny = 0,
28 | QBImagePickerMediaTypeImage,
29 | QBImagePickerMediaTypeVideo
30 | };
31 |
32 | @interface QBImagePickerController : UIViewController
33 |
34 | @property (nonatomic, weak) id delegate;
35 |
36 | @property (nonatomic, strong, readonly) NSMutableOrderedSet *selectedAssets;
37 |
38 | @property (nonatomic, copy) NSArray *assetCollectionSubtypes;
39 | @property (nonatomic, assign) QBImagePickerMediaType mediaType;
40 |
41 | @property (nonatomic, assign) BOOL allowsMultipleSelection;
42 | @property (nonatomic, assign) NSUInteger minimumNumberOfSelection;
43 | @property (nonatomic, assign) NSUInteger maximumNumberOfSelection;
44 | @property (nonatomic, strong) NSString* sortOrder;
45 |
46 | @property (nonatomic, copy) NSString *prompt;
47 | @property (nonatomic, assign) BOOL showsNumberOfSelectedAssets;
48 |
49 | @property (nonatomic, assign) NSUInteger numberOfColumnsInPortrait;
50 | @property (nonatomic, assign) NSUInteger numberOfColumnsInLandscape;
51 |
52 | @end
53 |
--------------------------------------------------------------------------------
/ios/QBImagePicker/QBImagePicker/QBImagePickerController.m:
--------------------------------------------------------------------------------
1 | //
2 | // QBImagePickerController.m
3 | // QBImagePicker
4 | //
5 | // Created by Katsuma Tanaka on 2015/04/03.
6 | // Copyright (c) 2015 Katsuma Tanaka. All rights reserved.
7 | //
8 |
9 | #import "QBImagePickerController.h"
10 | #import
11 |
12 | // ViewControllers
13 | #import "QBAlbumsViewController.h"
14 |
15 | @interface QBImagePickerController ()
16 |
17 | @property (nonatomic, strong) UINavigationController *albumsNavigationController;
18 |
19 | @property (nonatomic, strong) NSBundle *assetBundle;
20 |
21 | @end
22 |
23 | @implementation QBImagePickerController
24 |
25 | - (instancetype)init
26 | {
27 | self = [super init];
28 |
29 | if (self) {
30 | // Set default values
31 | self.assetCollectionSubtypes = @[
32 | @(PHAssetCollectionSubtypeSmartAlbumUserLibrary),
33 | @(PHAssetCollectionSubtypeAlbumMyPhotoStream),
34 | @(PHAssetCollectionSubtypeSmartAlbumPanoramas),
35 | @(PHAssetCollectionSubtypeSmartAlbumVideos),
36 | @(PHAssetCollectionSubtypeSmartAlbumBursts)
37 | ];
38 | self.minimumNumberOfSelection = 1;
39 | self.numberOfColumnsInPortrait = 4;
40 | self.numberOfColumnsInLandscape = 7;
41 |
42 | _selectedAssets = [NSMutableOrderedSet orderedSet];
43 |
44 | // Get asset bundle
45 | self.assetBundle = [NSBundle bundleForClass:[self class]];
46 | NSString *bundlePath = [self.assetBundle pathForResource:@"QBImagePicker" ofType:@"bundle"];
47 | if (bundlePath) {
48 | self.assetBundle = [NSBundle bundleWithPath:bundlePath];
49 | }
50 |
51 | [self setUpAlbumsViewController];
52 |
53 | // Set instance
54 | QBAlbumsViewController *albumsViewController = (QBAlbumsViewController *)self.albumsNavigationController.topViewController;
55 | albumsViewController.imagePickerController = self;
56 | }
57 |
58 | return self;
59 | }
60 |
61 | - (void)setUpAlbumsViewController
62 | {
63 | // Add QBAlbumsViewController as a child
64 | UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"QBImagePicker" bundle:self.assetBundle];
65 | UINavigationController *navigationController = [storyboard instantiateViewControllerWithIdentifier:@"QBAlbumsNavigationController"];
66 |
67 | [self addChildViewController:navigationController];
68 |
69 | navigationController.view.frame = self.view.bounds;
70 | [self.view addSubview:navigationController.view];
71 |
72 | [navigationController didMoveToParentViewController:self];
73 |
74 | self.albumsNavigationController = navigationController;
75 | }
76 |
77 | @end
78 |
--------------------------------------------------------------------------------
/ios/QBImagePicker/QBImagePicker/QBSlomoIconView.h:
--------------------------------------------------------------------------------
1 | //
2 | // QBSlomoIconView.h
3 | // QBImagePicker
4 | //
5 | // Created by Julien Chaumond on 22/04/2015.
6 | // Copyright (c) 2015 Katsuma Tanaka. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | IB_DESIGNABLE
12 | @interface QBSlomoIconView : UIView
13 |
14 | @property (nonatomic, strong) IBInspectable UIColor *iconColor;
15 |
16 | @end
17 |
--------------------------------------------------------------------------------
/ios/QBImagePicker/QBImagePicker/QBSlomoIconView.m:
--------------------------------------------------------------------------------
1 | //
2 | // QBSlomoIconView.m
3 | // QBImagePicker
4 | //
5 | // Created by Julien Chaumond on 22/04/2015.
6 | // Copyright (c) 2015 Katsuma Tanaka. All rights reserved.
7 | //
8 |
9 | #import "QBSlomoIconView.h"
10 |
11 | @implementation QBSlomoIconView
12 |
13 | - (void)awakeFromNib
14 | {
15 | [super awakeFromNib];
16 |
17 | // Set default values
18 | self.iconColor = [UIColor whiteColor];
19 | }
20 |
21 | - (void)drawRect:(CGRect)rect
22 | {
23 | [self.iconColor setStroke];
24 |
25 | CGFloat width = 2.2;
26 | CGRect insetRect = CGRectInset(rect, width / 2, width / 2);
27 |
28 | // Draw dashed circle
29 | UIBezierPath* circlePath = [UIBezierPath bezierPathWithOvalInRect:insetRect];
30 | circlePath.lineWidth = width;
31 | CGFloat ovalPattern[] = {0.75, 0.75};
32 | [circlePath setLineDash:ovalPattern count:2 phase:0];
33 | [circlePath stroke];
34 | }
35 |
36 | @end
37 |
--------------------------------------------------------------------------------
/ios/QBImagePicker/QBImagePicker/QBVideoIconView.h:
--------------------------------------------------------------------------------
1 | //
2 | // QBVideoIconView.h
3 | // QBImagePicker
4 | //
5 | // Created by Katsuma Tanaka on 2015/04/04.
6 | // Copyright (c) 2015 Katsuma Tanaka. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | IB_DESIGNABLE
12 | @interface QBVideoIconView : UIView
13 |
14 | @property (nonatomic, strong) IBInspectable UIColor *iconColor;
15 |
16 | @end
17 |
--------------------------------------------------------------------------------
/ios/QBImagePicker/QBImagePicker/QBVideoIconView.m:
--------------------------------------------------------------------------------
1 | //
2 | // QBVideoIconView.m
3 | // QBImagePicker
4 | //
5 | // Created by Katsuma Tanaka on 2015/04/04.
6 | // Copyright (c) 2015 Katsuma Tanaka. All rights reserved.
7 | //
8 |
9 | #import "QBVideoIconView.h"
10 |
11 | @implementation QBVideoIconView
12 |
13 | - (void)awakeFromNib
14 | {
15 | [super awakeFromNib];
16 |
17 | // Set default values
18 | self.iconColor = [UIColor whiteColor];
19 | }
20 |
21 | - (void)drawRect:(CGRect)rect
22 | {
23 | [self.iconColor setFill];
24 |
25 | // Draw triangle
26 | UIBezierPath *trianglePath = [UIBezierPath bezierPath];
27 | [trianglePath moveToPoint:CGPointMake(CGRectGetMaxX(self.bounds), CGRectGetMinY(self.bounds))];
28 | [trianglePath addLineToPoint:CGPointMake(CGRectGetMaxX(self.bounds), CGRectGetMaxY(self.bounds))];
29 | [trianglePath addLineToPoint:CGPointMake(CGRectGetMaxX(self.bounds) - CGRectGetMidY(self.bounds), CGRectGetMidY(self.bounds))];
30 | [trianglePath closePath];
31 | [trianglePath fill];
32 |
33 | // Draw rounded square
34 | UIBezierPath *squarePath = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(CGRectGetMinX(self.bounds), CGRectGetMinY(self.bounds), CGRectGetWidth(self.bounds) - CGRectGetMidY(self.bounds) - 1.0, CGRectGetHeight(self.bounds)) cornerRadius:2.0];
35 | [squarePath fill];
36 | }
37 |
38 | @end
39 |
--------------------------------------------------------------------------------
/ios/QBImagePicker/QBImagePicker/QBVideoIndicatorView.h:
--------------------------------------------------------------------------------
1 | //
2 | // QBVideoIndicatorView.h
3 | // QBImagePicker
4 | //
5 | // Created by Katsuma Tanaka on 2015/04/04.
6 | // Copyright (c) 2015 Katsuma Tanaka. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | #import "QBVideoIconView.h"
12 | #import "QBSlomoIconView.h"
13 |
14 | @interface QBVideoIndicatorView : UIView
15 |
16 | @property (nonatomic, weak) IBOutlet UILabel *timeLabel;
17 | @property (nonatomic, weak) IBOutlet QBVideoIconView *videoIcon;
18 | @property (nonatomic, weak) IBOutlet QBSlomoIconView *slomoIcon;
19 |
20 |
21 | @end
22 |
--------------------------------------------------------------------------------
/ios/QBImagePicker/QBImagePicker/QBVideoIndicatorView.m:
--------------------------------------------------------------------------------
1 | //
2 | // QBVideoIndicatorView.m
3 | // QBImagePicker
4 | //
5 | // Created by Katsuma Tanaka on 2015/04/04.
6 | // Copyright (c) 2015 Katsuma Tanaka. All rights reserved.
7 | //
8 |
9 | #import "QBVideoIndicatorView.h"
10 |
11 | @implementation QBVideoIndicatorView
12 |
13 | - (void)awakeFromNib
14 | {
15 | [super awakeFromNib];
16 |
17 | // Add gradient layer
18 | CAGradientLayer *gradientLayer = [CAGradientLayer layer];
19 | gradientLayer.frame = self.bounds;
20 | gradientLayer.colors = @[
21 | (__bridge id)[[UIColor clearColor] CGColor],
22 | (__bridge id)[[UIColor blackColor] CGColor]
23 | ];
24 |
25 | [self.layer insertSublayer:gradientLayer atIndex:0];
26 | }
27 |
28 | @end
29 |
--------------------------------------------------------------------------------
/ios/QBImagePicker/QBImagePicker/da.lproj/QBImagePicker.strings:
--------------------------------------------------------------------------------
1 | /*
2 | QBImagePicker.strings
3 | QBImagePicker
4 | */
5 |
6 | "albums.title" = "Billeder";
7 |
8 | "assets.footer.photo" = "%ld Billede";
9 | "assets.footer.photos" = "%ld Billeder";
10 | "assets.footer.video" = "%ld Video";
11 | "assets.footer.videos" = "%ld Videoer";
12 | "assets.footer.photo-and-video" = "%ld Billede, %ld Video";
13 | "assets.footer.photos-and-video" = "%ld Billeder, %ld Video";
14 | "assets.footer.photo-and-videos" = "%ld Billede, %ld Videoer";
15 | "assets.footer.photos-and-videos" = "%ld Billeder, %ld Videoer";
16 |
17 | "assets.toolbar.item-selected" = "%ld Valgt objekt";
18 | "assets.toolbar.items-selected" = "%ld Udvalgte genstande";
19 |
20 | "permission.help" = "Du har givet adgang til et begrænset antal udvalgte billeder og videoer.";
21 | "permission.manage" = "HÅNDTERE";
22 | "permission.title" = "For at få adgang til alle dine billeder i appen skal du give adgang til hele dit bibliotek i din enheds indstillinger.";
23 | "permission.choose_more" = "Vælg flere billeder";
24 | "permission.change_settings" = "Ændre indstillinger";
25 | "permission.cancel" = "Annuller";
26 |
--------------------------------------------------------------------------------
/ios/QBImagePicker/QBImagePicker/de.lproj/QBImagePicker.strings:
--------------------------------------------------------------------------------
1 | /*
2 | QBImagePicker.strings
3 | QBImagePicker
4 |
5 | Created by Katsuma Tanaka on 2015/04/03.
6 | Copyright (c) 2015 Katsuma Tanaka. All rights reserved.
7 | */
8 |
9 | "albums.title" = "Fotos";
10 |
11 | "assets.footer.photo" = "%ld Foto";
12 | "assets.footer.photos" = "%ld Fotos";
13 | "assets.footer.video" = "%ld Video";
14 | "assets.footer.videos" = "%ld Videos";
15 | "assets.footer.photo-and-video" = "%ld Foto, %ld Video";
16 | "assets.footer.photos-and-video" = "%ld Fotos, %ld Video";
17 | "assets.footer.photo-and-videos" = "%ld Foto, %ld Videos";
18 | "assets.footer.photos-and-videos" = "%ld Fotos, %ld Videos";
19 |
20 | "assets.toolbar.item-selected" = "%ld Element ausgewählt";
21 | "assets.toolbar.items-selected" = "%ld Elemente ausgewählt";
22 |
23 | "permission.help" = "Sie haben einer begrenzten Anzahl ausgewählter Fotos und Videos die Erlaubnis erteilt.";
24 | "permission.manage" = "VERWALTEN";
25 | "permission.title" = "Um auf alle Ihre Fotos in der App zuzugreifen, geben Sie in den Geräteeinstellungen Zugriff auf Ihre vollständige Bibliothek.";
26 | "permission.choose_more" = "Weitere Fotos auswählen";
27 | "permission.change_settings" = "Einstellungen ändern";
28 | "permission.cancel" = "Abbrechen";
29 |
--------------------------------------------------------------------------------
/ios/QBImagePicker/QBImagePicker/en.lproj/QBImagePicker.strings:
--------------------------------------------------------------------------------
1 | /*
2 | QBImagePicker.strings
3 | QBImagePicker
4 |
5 | Created by Katsuma Tanaka on 2015/04/03.
6 | Copyright (c) 2015 Katsuma Tanaka. All rights reserved.
7 | */
8 |
9 | "albums.title" = "Photos";
10 |
11 | "assets.footer.photo" = "%ld Photo";
12 | "assets.footer.photos" = "%ld Photos";
13 | "assets.footer.video" = "%ld Video";
14 | "assets.footer.videos" = "%ld Videos";
15 | "assets.footer.photo-and-video" = "%ld Photo, %ld Video";
16 | "assets.footer.photos-and-video" = "%ld Photos, %ld Video";
17 | "assets.footer.photo-and-videos" = "%ld Photo, %ld Videos";
18 | "assets.footer.photos-and-videos" = "%ld Photos, %ld Videos";
19 |
20 | "assets.toolbar.item-selected" = "%ld Item Selected";
21 | "assets.toolbar.items-selected" = "%ld Items Selected";
22 |
23 | "permission.help" = "You have given permission to a limited number of selected photos and videos.";
24 | "permission.manage" = "MANAGE";
25 | "permission.title" = "To access all your photos in the app, give access to your full library in the device settings.";
26 | "permission.choose_more" = "Select More Photos";
27 | "permission.change_settings" = "Change Settings";
28 | "permission.cancel" = "Cancel";
29 |
--------------------------------------------------------------------------------
/ios/QBImagePicker/QBImagePicker/es.lproj/QBImagePicker.strings:
--------------------------------------------------------------------------------
1 | /*
2 | QBImagePicker.strings
3 | QBImagePicker
4 |
5 | Created by Katsuma Tanaka on 2015/04/03.
6 | Copyright (c) 2015 Katsuma Tanaka. All rights reserved.
7 | */
8 |
9 | "albums.title" = "Fotos";
10 |
11 | "assets.footer.photo" = "%ld Foto";
12 | "assets.footer.photos" = "%ld Fotos";
13 | "assets.footer.video" = "%ld Video";
14 | "assets.footer.videos" = "%ld Videos";
15 | "assets.footer.photo-and-video" = "%ld Foto, %ld Video";
16 | "assets.footer.photos-and-video" = "%ld Fotos, %ld Video";
17 | "assets.footer.photo-and-videos" = "%ld Foto, %ld Videos";
18 | "assets.footer.photos-and-videos" = "%ld Fotos, %ld Videos";
19 |
20 | "assets.toolbar.item-selected" = "%ld items seleccionados";
21 | "assets.toolbar.items-selected" = "%ld items seleccionados";
22 |
23 | "permission.help" = "Ha otorgado permiso a un número limitado de fotos y videos seleccionados.";
24 | "permission.manage" = "ADMINISTRAR";
25 | "permission.title" = "Para acceder a todas sus fotos en la aplicación, dé acceso a su biblioteca completa en la configuración del dispositivo.";
26 | "permission.choose_more" = "Seleccionar más fotos";
27 | "permission.change_settings" = "Cambiar configuración";
28 | "permission.cancel" = "Cancelar";
29 |
--------------------------------------------------------------------------------
/ios/QBImagePicker/QBImagePicker/fi.lproj/QBImagePicker.strings:
--------------------------------------------------------------------------------
1 | /*
2 | QBImagePicker.strings
3 | QBImagePicker
4 | */
5 |
6 | "albums.title" = "Kuvia";
7 |
8 | "assets.footer.photo" = "%ld Kuva";
9 | "assets.footer.photos" = "%ld Kuvia";
10 | "assets.footer.video" = "%ld Video";
11 | "assets.footer.videos" = "%ld Videoita";
12 | "assets.footer.photo-and-video" = "%ld Kuva, %ld Video";
13 | "assets.footer.photos-and-video" = "%ld Kuvia, %ld Video";
14 | "assets.footer.photo-and-videos" = "%ld Kuva, %ld Videoita";
15 | "assets.footer.photos-and-videos" = "%ld Kuvia, %ld Videoita";
16 |
17 | "assets.toolbar.item-selected" = "%ld Valittu objekti";
18 | "assets.toolbar.items-selected" = "%ld Valitut kohteet";
19 |
20 | "permission.help" = "Olet myöntänyt pääsyn rajoitettuun määrään valittuja kuvia ja videoita.";
21 | "permission.manage" = "KÄSITTELE";
22 | "permission.title" = "Jos haluat käyttää kaikkia sovelluksessa olevia kuviasi, anna käyttöoikeus koko kirjastoosi laitteesi asetuksista.";
23 | "permission.choose_more" = "Valitse lisää kuvia";
24 | "permission.change_settings" = "Vaihda asetuksia";
25 | "permission.cancel" = "Peruuttaa";
26 |
--------------------------------------------------------------------------------
/ios/QBImagePicker/QBImagePicker/fr.lproj/QBImagePicker.strings:
--------------------------------------------------------------------------------
1 | /*
2 | QBImagePicker.strings
3 | QBImagePicker
4 |
5 | Created by Gareth McCall on 2018/01/17.
6 | MIT License - Copyright (c) 2018 Ivan Pusic, et al
7 | */
8 |
9 | "albums.title" = "Photos";
10 |
11 | "assets.footer.photo" = "%ld Photo";
12 | "assets.footer.photos" = "%ld Photos";
13 | "assets.footer.video" = "%ld Vidéo";
14 | "assets.footer.videos" = "%ld Vidéos";
15 | "assets.footer.photo-and-video" = "%ld Photo, %ld Vidéo";
16 | "assets.footer.photos-and-video" = "%ld Photos, %ld Vidéo";
17 | "assets.footer.photo-and-videos" = "%ld Photo, %ld Vidéos";
18 | "assets.footer.photos-and-videos" = "%ld Photos, %ld Vidéos";
19 |
20 | "assets.toolbar.item-selected" = "%ld Élément Sélectionné";
21 | "assets.toolbar.items-selected" = "%ld Éléments Sélectionnés";
22 |
23 | "permission.help" = "Vous avez autorisé un nombre limité de photos et de vidéos sélectionnées.";
24 | "permission.manage" = "GÉRER";
25 | "permission.title" = "Pour accéder à toutes vos photos dans l'application, donnez accès à votre bibliothèque complète dans les paramètres de l'appareil.";
26 | "permission.choose_more" = "Sélectionner plus de photos" ;
27 | "permission.change_settings" = "Modifier les paramètres" ;
28 | "permission.cancel" = "Annuler" ;
29 |
--------------------------------------------------------------------------------
/ios/QBImagePicker/QBImagePicker/it.lproj/QBImagePicker.strings:
--------------------------------------------------------------------------------
1 | /*
2 | QBImagePicker.strings
3 | QBImagePicker
4 |
5 | Created by Seungyeob Song on 2020/11/10.
6 | Copyright (c) 2020 Seungyeob Song. All rights reserved.
7 | */
8 |
9 | "albums.title" = "Foto";
10 |
11 | "assets.footer.photo" = "%ld Foto";
12 | "assets.footer.photos" = "%ld Foto";
13 | "assets.footer.video" = "%ld Video";
14 | "assets.footer.videos" = "%ld Video";
15 | "assets.footer.photo-and-video" = "%ld Foto, %ld Video";
16 | "assets.footer.photos-and-video" = "%ld Foto, %ld Video";
17 | "assets.footer.photo-and-videos" = "%ld Foto, %ld Video";
18 | "assets.footer.photos-and-videos" = "%ld Foto, %ld Video";
19 |
20 | "assets.toolbar.item-selected" = "%ld Elemento Selezionato";
21 | "assets.toolbar.items-selected" = "%ld Elementi Selezionati";
22 |
23 | "permission.help" = "Hai autorizzato un numero limitato di foto e video selezionati.";
24 | "permission.manage" = "GESTISCI";
25 | "permission.title" = "Per accedere a tutte le tue foto nell'app, concedi l'accesso alla tua libreria completa nelle impostazioni del dispositivo.";
26 | "permission.choose_more" = "Seleziona altre foto";
27 | "permission.change_settings" = "Cambia impostazioni";
28 | "permission.cancel" = "Annulla";
29 |
--------------------------------------------------------------------------------
/ios/QBImagePicker/QBImagePicker/ja.lproj/QBImagePicker.strings:
--------------------------------------------------------------------------------
1 | /*
2 | QBImagePicker.strings
3 | QBImagePicker
4 |
5 | Created by Katsuma Tanaka on 2015/04/03.
6 | Copyright (c) 2015 Katsuma Tanaka. All rights reserved.
7 | */
8 |
9 | "albums.title" = "アルバム";
10 |
11 | "assets.footer.photo" = "写真: %ld枚";
12 | "assets.footer.photos" = "写真: %ld枚";
13 | "assets.footer.video" = "ビデオ: %ld本";
14 | "assets.footer.videos" = "ビデオ: %ld本";
15 | "assets.footer.photo-and-video" = "写真: %ld枚、ビデオ%ld本";
16 | "assets.footer.photos-and-video" = "写真: %ld枚、ビデオ%ld本";
17 | "assets.footer.photo-and-videos" = "写真: %ld枚、ビデオ%ld本";
18 | "assets.footer.photos-and-videos" = "写真: %ld枚、ビデオ%ld本";
19 |
20 | "assets.toolbar.item-selected" = "%ld 項目を選択中";
21 | "assets.toolbar.items-selected" = "%ld 項目を選択中";
22 |
23 | "permission.help" = "選択した限られた数の写真とビデオに許可を与えました。";
24 | "permission.manage" = "管理";
25 | "permission.title" = "アプリ内のすべての写真にアクセスするには、デバイス設定でライブラリ全体へのアクセスを許可します。";
26 | "permission.choose_more" = "写真をもっと選択";
27 | "permission.change_settings" = "設定の変更";
28 | "permission.cancel" = "キャンセル";
29 |
--------------------------------------------------------------------------------
/ios/QBImagePicker/QBImagePicker/ko.lproj/QBImagePicker.strings:
--------------------------------------------------------------------------------
1 | /*
2 | QBImagePicker.strings
3 | QBImagePicker
4 |
5 | Created by Katsuma Tanaka on 2015/04/03.
6 | Copyright (c) 2015 Katsuma Tanaka. All rights reserved.
7 | */
8 |
9 | "albums.title" = "사진";
10 |
11 | "assets.footer.photo" = "%ld 사진";
12 | "assets.footer.photos" = "%ld 사진";
13 | "assets.footer.video" = "%ld 비디오";
14 | "assets.footer.videos" = "%ld 비디오";
15 | "assets.footer.photo-and-video" = "%ld 사진, %ld 비디오";
16 | "assets.footer.photos-and-video" = "%ld 사진, %ld 비디오";
17 | "assets.footer.photo-and-videos" = "%ld 사진, %ld 비디오";
18 | "assets.footer.photos-and-videos" = "%ld 사진, %ld 비디오";
19 |
20 | "assets.toolbar.item-selected" = "%ld 선택된 아이템";
21 | "assets.toolbar.items-selected" = "%ld 선택된 아이템";
22 |
23 | "permission.help" = "선택한 사진 및 비디오의 제한된 수에 대한 권한을 부여했습니다.";
24 | "permission.manage" = "관리";
25 | "permission.title" = "앱에 있는 모든 사진에 접근하려면 기기 설정에서 전체 보관함에 접근 권한을 부여하십시오.";
26 | "permission.choose_more" = "추가 사진 선택";
27 | "permission.change_settings" = "설정 변경";
28 | "permission.cancel" = "취소";
29 |
--------------------------------------------------------------------------------
/ios/QBImagePicker/QBImagePicker/nb.lproj/QBImagePicker.strings:
--------------------------------------------------------------------------------
1 | /*
2 | QBImagePicker.strings
3 | QBImagePicker
4 |
5 | Created by Katsuma Tanaka on 2015/04/03.
6 | Copyright (c) 2015 Katsuma Tanaka. All rights reserved.
7 | */
8 |
9 | "albums.title" = "Bilder";
10 |
11 | "assets.footer.photo" = "%ld bilde";
12 | "assets.footer.photos" = "%ld bilder";
13 | "assets.footer.video" = "%ld video";
14 | "assets.footer.videos" = "%ld videoer";
15 | "assets.footer.photo-and-video" = "%ld bilde, %ld video";
16 | "assets.footer.photos-and-video" = "%ld bilder, %ld video";
17 | "assets.footer.photo-and-videos" = "%ld bilde, %ld videoer";
18 | "assets.footer.photos-and-videos" = "%ld bilder, %ld videoer";
19 |
20 | "assets.toolbar.item-selected" = "%ld objekt valgt";
21 | "assets.toolbar.items-selected" = "%ld objekter valgt";
22 |
23 | "permission.help" = "Du har gitt tilgang til et begrenset utvalg av bilder og videoer.";
24 | "permission.manage" = "ENDRE";
25 | "permission.title" = "For å gi tilgang til alle bildene dine i appen, må du gi full tilgang til biblioteket fra enhetsinnstillingene.";
26 | "permission.choose_more" = "Velg flere bilder";
27 | "permission.change_settings" = "Endre innstillinger";
28 | "permission.cancel" = "Avbryt";
29 |
--------------------------------------------------------------------------------
/ios/QBImagePicker/QBImagePicker/nl.lproj/QBImagePicker.strings:
--------------------------------------------------------------------------------
1 | /*
2 | QBImagePicker.strings
3 | QBImagePicker
4 |
5 | Created by Marijn Hosten on 2023/04/18.
6 | */
7 |
8 | "albums.title" = "Fotos";
9 |
10 | "assets.footer.photo" = "%ld Foto";
11 | "assets.footer.photos" = "%ld Fotos";
12 | "assets.footer.video" = "%ld Video";
13 | "assets.footer.videos" = "%ld Videos";
14 | "assets.footer.photo-and-video" = "%ld Foto, %ld Video";
15 | "assets.footer.photos-and-video" = "%ld Fotos, %ld Video";
16 | "assets.footer.photo-and-videos" = "%ld Foto, %ld Videos";
17 | "assets.footer.photos-and-videos" = "%ld Fotos, %ld Videos";
18 |
19 | "assets.toolbar.item-selected" = "%ld Item Geselecteerd";
20 | "assets.toolbar.items-selected" = "%ld Items Geselecteerd";
21 |
22 | "permission.help" = "U heeft toestemming gegeven om een gelimiteerd aantal fotos en videos te gebruiken.";
23 | "permission.manage" = "BEHEER";
24 | "permission.title" = "Om toegang te hebben tot alle fotos moet u toestemming geven in de instellingen van uw toestel.";
25 | "permission.choose_more" = "Kies Meer Fotos";
26 | "permission.change_settings" = "Wijzig Instellingen";
27 | "permission.cancel" = "Annuleer";
28 |
--------------------------------------------------------------------------------
/ios/QBImagePicker/QBImagePicker/pl.lproj/QBImagePicker.strings:
--------------------------------------------------------------------------------
1 | /*
2 | QBImagePicker.strings
3 | QBImagePicker
4 |
5 | Created by Katsuma Tanaka on 2015/04/03.
6 | Copyright (c) 2015 Katsuma Tanaka. All rights reserved.
7 | */
8 |
9 | "albums.title" = "Zdjęcia";
10 |
11 | "assets.footer.photo" = "%ld zdjęcie";
12 | "assets.footer.photos" = "Zdjęć: %ld";
13 | "assets.footer.video" = "%ld wideo";
14 | "assets.footer.videos" = "Wideo: %ld";
15 | "assets.footer.photo-and-video" = "%ld zdjęcie, %ld wideo";
16 | "assets.footer.photos-and-video" = "Zdjęć: %ld, %ld wideo";
17 | "assets.footer.photo-and-videos" = "%ld zdjęcie, %ld wideo";
18 | "assets.footer.photos-and-videos" = "Zdjęć: %ld, %ld wideo";
19 |
20 | "assets.toolbar.item-selected" = "%ld zaznaczona rzecz";
21 | "assets.toolbar.items-selected" = "Zaznaczonych rzeczy: %ld";
22 |
23 | "permission.help" = "Zezwolono na ograniczoną liczbę wybranych zdjęć i filmów.";
24 | "permission.manage" = "ZARZĄDZAJ";
25 | "permission.title" = "Aby uzyskać dostęp do wszystkich swoich zdjęć w aplikacji, zezwól na dostęp do pełnej biblioteki w ustawieniach urządzenia.";
26 | "permission.choose_more" = "Wybierz więcej zdjęć";
27 | "permission.change_settings" = "Zmień ustawienia";
28 | "permission.cancel" = "Anuluj";
29 |
--------------------------------------------------------------------------------
/ios/QBImagePicker/QBImagePicker/pt.lproj/QBImagePicker.strings:
--------------------------------------------------------------------------------
1 | /*
2 | QBImagePicker.strings
3 | QBImagePicker
4 |
5 | Created by Seungyeob Song on 2020/11/10.
6 | Copyright (c) 2020 Seungyeob Song. All rights reserved.
7 | */
8 |
9 | "albums.title" = "Fotos";
10 |
11 | "assets.footer.photo" = "%ld Foto";
12 | "assets.footer.photos" = "%ld Fotos";
13 | "assets.footer.video" = "%ld Vídeo";
14 | "assets.footer.videos" = "%ld Vídeos";
15 | "assets.footer.photo-and-video" = "%ld Foto, %ld Vídeo";
16 | "assets.footer.photos-and-video" = "%ld Fotos, %ld Vídeo";
17 | "assets.footer.photo-and-videos" = "%ld Foto, %ld Vídeos";
18 | "assets.footer.photos-and-videos" = "%ld Fotos, %ld Vídeos";
19 |
20 | "assets.toolbar.item-selected" = "%ld Item Selecionado";
21 | "assets.toolbar.items-selected" = "%ld Itens Selecionados";
22 |
23 | "permission.help" = "Você deu permissão a um número limitado de fotos e vídeos selecionados.";
24 | "permission.manage" = "GERENCIAR";
25 | "permission.title" = "Para acessar todas as suas fotos no aplicativo, dê acesso à sua biblioteca completa nas configurações do dispositivo.";
26 | "permission.choose_more" = "Selecionar mais fotos";
27 | "permission.change_settings" = "Alterar configurações";
28 | "permission.cancel" = "Cancelar";
29 |
--------------------------------------------------------------------------------
/ios/QBImagePicker/QBImagePicker/ro.lproj/QBImagePicker.strings:
--------------------------------------------------------------------------------
1 | /*
2 | QBImagePicker.strings
3 | QBImagePicker
4 |
5 | Created by Anton Cojocaru on 2021/05/28.
6 | Copyright (c) 2021 Anton Cojocaru. All rights reserved.
7 | */
8 |
9 | "albums.title" = "Poze";
10 |
11 | "assets.footer.photo" = "%ld Poză";
12 | "assets.footer.photos" = "%ld Poze";
13 | "assets.footer.video" = "%ld Clip";
14 | "assets.footer.videos" = "%ld Clipuri";
15 | "assets.footer.photo-and-video" = "%ld Poză, %ld Clip";
16 | "assets.footer.photos-and-video" = "%ld Poze, %ld Clip";
17 | "assets.footer.photo-and-videos" = "%ld Poză, %ld Clipuri";
18 | "assets.footer.photos-and-videos" = "%ld Poze, %ld Clipuri";
19 |
20 | "assets.toolbar.item-selected" = "%ld Element Selectat";
21 | "assets.toolbar.items-selected" = "%ld Elemente Selectate";
22 |
23 | "permission.help" = "Ați acordat permisiunea unui număr limitat de fotografii și videoclipuri selectate.";
24 | "permission.manage" = "GESTIONARE";
25 | "permission.title" = "Pentru a vă accesa toate fotografiile din aplicație, acordați acces la biblioteca completă în setările dispozitivului.";
26 | "permission.choose_more" = "Selectați mai multe fotografii";
27 | "permission.change_settings" = "Schimbați setările";
28 | "permission.cancel" = "Anulați";
29 |
--------------------------------------------------------------------------------
/ios/QBImagePicker/QBImagePicker/ru.lproj/QBImagePicker.strings:
--------------------------------------------------------------------------------
1 | /*
2 | QBImagePicker.strings
3 | QBImagePicker
4 |
5 | Created by Yaroslav Bunyaev on 2020/10/04.
6 | Copyright (c) 2020 Yaroslav Bunyaev. All rights reserved.
7 | */
8 |
9 | "albums.title" = "Фотографии";
10 |
11 | "assets.footer.photo" = "%ld Фото";
12 | "assets.footer.photos" = "%ld Фото";
13 | "assets.footer.video" = "%ld Видео";
14 | "assets.footer.videos" = "%ld Видео";
15 | "assets.footer.photo-and-video" = "%ld Фото, %ld Видео";
16 | "assets.footer.photos-and-video" = "%ld Фото, %ld Видео";
17 | "assets.footer.photo-and-videos" = "%ld Фото, %ld Видео";
18 | "assets.footer.photos-and-videos" = "%ld Фото, %ld Видео";
19 |
20 | "assets.toolbar.item-selected" = "%ld Элемент выбран";
21 | "assets.toolbar.items-selected" = "%ld Элементы выбраны";
22 |
23 | "permission.help" = "Вы дали разрешение на ограниченное количество выбранных фотографий и видео.";
24 | "permission.manage" = "УПРАВЛЕНИЕ";
25 | "permission.title" = "Чтобы получить доступ ко всем своим фотографиям в приложении, предоставьте доступ к полной библиотеке в настройках устройства.";
26 | "permission.choose_more" = "Выбрать больше фотографий";
27 | "permission.change_settings" = "Изменить настройки";
28 | "permission.cancel" = "Отменить";
29 |
--------------------------------------------------------------------------------
/ios/QBImagePicker/QBImagePicker/sv.lproj/QBImagePicker.strings:
--------------------------------------------------------------------------------
1 | /*
2 | QBImagePicker.strings
3 | QBImagePicker
4 |
5 | Created by Marina Skripnik on 2021/10/07.
6 | Copyright (c) 2021 Marina Skripnik. All rights reserved.
7 | */
8 |
9 | "albums.title" = "Bilder";
10 |
11 | "assets.footer.photo" = "%ld Bild";
12 | "assets.footer.photos" = "%ld Bilder";
13 | "assets.footer.video" = "%ld Video";
14 | "assets.footer.videos" = "%ld Videor";
15 | "assets.footer.photo-and-video" = "%ld Bild, %ld Video";
16 | "assets.footer.photos-and-video" = "%ld Bilder, %ld Video";
17 | "assets.footer.photo-and-videos" = "%ld Bild, %ld Videor";
18 | "assets.footer.photos-and-videos" = "%ld Bilder, %ld Videor";
19 |
20 | "assets.toolbar.item-selected" = "%ld Markerad Objekt";
21 | "assets.toolbar.items-selected" = "%ld Markerade Objekt";
22 |
23 | "permission.help" = "Du har gett åtkomst till ett begränsat antal utvalda bilder och videor.";
24 | "permission.manage" = "HANTERA";
25 | "permission.title" = "För att komma åt alla dina foton i appen, ge åtkomst till ditt fulla bibliotek i enhetens inställningar.";
26 | "permission.choose_more" = "Välj fler foton";
27 | "permission.change_settings" = "Ändra inställningar";
28 | "permission.cancel" = "Avbryt";
29 |
--------------------------------------------------------------------------------
/ios/QBImagePicker/QBImagePicker/tr.lproj/QBImagePicker.strings:
--------------------------------------------------------------------------------
1 | /*
2 | QBImagePicker.strings
3 | QBImagePicker
4 |
5 | Created by Katsuma Tanaka on 2015/04/03.
6 | Copyright (c) 2015 Katsuma Tanaka. All rights reserved.
7 | */
8 |
9 | "albums.title" = "Fotoğraflar";
10 |
11 | "assets.footer.photo" = "%ld Fotoğraf";
12 | "assets.footer.photos" = "%ld Fotoğraf";
13 | "assets.footer.video" = "%ld Video";
14 | "assets.footer.videos" = "%ld Video";
15 | "assets.footer.photo-and-video" = "%ld Fotoğraf, %ld Video";
16 | "assets.footer.photos-and-video" = "%ld Fotoğraf, %ld Video";
17 | "assets.footer.photo-and-videos" = "%ld Fotoğraf, %ld Video";
18 | "assets.footer.photos-and-videos" = "%ld Fotoğraf, %ld Video";
19 |
20 | "assets.toolbar.item-selected" = "%ld Adet Seçildi";
21 | "assets.toolbar.items-selected" = "%ld Adet Seçildi";
22 |
23 | "permission.help" = "Sınırlı sayıda seçili fotoğraf ve videoya izin verdiniz.";
24 | "permission.manage" = "YÖNET";
25 | "permission.title" = "Uygulamadaki tüm fotoğraflarınıza erişmek için cihaz ayarlarından tam kitaplığınıza erişim izni verin.";
26 | "permission.choose_more" = "Daha Fazla Fotoğraf Seç";
27 | "permission.change_settings" = "Ayarları Değiştir";
28 | "permission.cancel" = "İptal";
29 |
--------------------------------------------------------------------------------
/ios/QBImagePicker/QBImagePicker/uk.lproj/QBImagePicker.strings:
--------------------------------------------------------------------------------
1 | /*
2 | QBImagePicker.strings
3 | QBImagePicker
4 |
5 | Created by Marina Skripnik on 2021/10/07.
6 | Copyright (c) 2021 Marina Skripnik. All rights reserved.
7 | */
8 |
9 | "albums.title" = "Фотографії";
10 |
11 | "assets.footer.photo" = "%ld Фото";
12 | "assets.footer.photos" = "%ld Фото";
13 | "assets.footer.video" = "%ld Відео";
14 | "assets.footer.videos" = "%ld Відео";
15 | "assets.footer.photo-and-video" = "%ld Фото, %ld Відео";
16 | "assets.footer.photos-and-video" = "%ld Фото, %ld Відео";
17 | "assets.footer.photo-and-videos" = "%ld Фото, %ld Відео";
18 | "assets.footer.photos-and-videos" = "%ld Фото, %ld Відео";
19 |
20 | "assets.toolbar.item-selected" = "Вибрано %ld Елемент";
21 | "assets.toolbar.items-selected" = "Вибрано %ld Елементи";
22 |
23 | "permission.help" = "Ви дали дозвіл на обмежену кількість вибраних фотографій і відео.";
24 | "permission.manage" = "КЕРУВАТИ";
25 | "permission.title" = "Щоб отримати доступ до всіх своїх фотографій у програмі, надайте доступ до повної бібліотеки в налаштуваннях пристрою.";
26 | "permission.choose_more" = "Вибрати більше фотографій";
27 | "permission.change_settings" = "Змінити налаштування";
28 | "permission.cancel" = "Скасувати";
29 |
--------------------------------------------------------------------------------
/ios/QBImagePicker/QBImagePicker/vi.lproj/QBImagePicker.strings:
--------------------------------------------------------------------------------
1 | /*
2 | QBImagePicker.strings
3 | QBImagePicker
4 |
5 | Created by Pham Ngoc Thach on 2022/08/26.
6 | Copyright (c) 2022 Pham Ngoc Thach. All rights reserved.
7 | */
8 |
9 | "albums.title" = "Ảnh";
10 |
11 | "assets.footer.photo" = "%ld Ảnh";
12 | "assets.footer.photos" = "%ld Ảnh";
13 | "assets.footer.video" = "%ld Video";
14 | "assets.footer.videos" = "%ld Video";
15 | "assets.footer.photo-and-video" = "%ld Ảnh, %ld Video";
16 | "assets.footer.photos-and-video" = "%ld Ảnh, %ld Video";
17 | "assets.footer.photo-and-videos" = "%ld Ảnh, %ld Video";
18 | "assets.footer.photos-and-videos" = "%ld Ảnh, %ld Video";
19 |
20 | "assets.toolbar.item-selected" = "Đã chọn %ld mục";
21 | "assets.toolbar.items-selected" = "Đã chọn %ld mục";
22 |
23 | "permission.help" = "Bạn đã cấp quyền truy cập vào số lượng ảnh và video có hạn.";
24 | "permission.manage" = "QUẢN LÝ";
25 | "permission.title" = "Để truy cập tất cả ảnh trong ứng dụng, hãy cấp quyền truy cập vào toàn bộ thư viện của bạn trong cài đặt thiết bị.";
26 | "permission.choose_more" = "Chọn Nhiều Ảnh";
27 | "permission.change_settings" = "Đổi Cài đặt";
28 | "permission.cancel" = "Hủy bỏ";
--------------------------------------------------------------------------------
/ios/QBImagePicker/QBImagePicker/zh-Hans.lproj/QBImagePicker.strings:
--------------------------------------------------------------------------------
1 | /*
2 | QBImagePicker.strings
3 | QBImagePicker
4 |
5 | Created by Katsuma Tanaka on 2015/04/03.
6 | Copyright (c) 2015 Katsuma Tanaka. All rights reserved.
7 | */
8 |
9 | "albums.title" = "照片";
10 |
11 | "assets.footer.photo" = "共%ld张照片";
12 | "assets.footer.photos" = "共%ld张照片";
13 | "assets.footer.video" = "共%ld个视频";
14 | "assets.footer.videos" = "共%ld个视频";
15 | "assets.footer.photo-and-video" = "共%ld 张照片, %ld 个视频";
16 | "assets.footer.photos-and-video" = "共%ld 张照片, %ld 个视频";
17 | "assets.footer.photo-and-videos" = "共%ld 张照片, %ld 个视频";
18 | "assets.footer.photos-and-videos" = "共%ld 张照片, %ld 个视频";
19 |
20 | "assets.toolbar.item-selected" = "选择了%ld项";
21 | "assets.toolbar.items-selected" = "选择了%ld项";
22 |
23 | "permission.help" = "您已授予有限数量的选定照片和视频的权限。";
24 | "permission.manage" = "管理";
25 | "permission.title" = "要访问您在应用程序中的所有照片,请在设备设置中授予访问您的完整图库的权限。";
26 | "permission.choose_more" = "选择更多照片";
27 | "permission.change_settings" = "更改设置";
28 | "permission.cancel" = "取消";
29 |
--------------------------------------------------------------------------------
/ios/QBImagePicker/QBImagePicker/zh-Hant.lproj/QBImagePicker.strings:
--------------------------------------------------------------------------------
1 | /*
2 | QBImagePicker.strings
3 | QBImagePicker
4 |
5 | Created by Seungyeob Song on 2020/11/10.
6 | Copyright (c) 2020 Seungyeob Song. All rights reserved.
7 | */
8 |
9 | "albums.title" = "照片";
10 |
11 | "assets.footer.photo" = "共%ld張照片";
12 | "assets.footer.photos" = "共%ld張照片";
13 | "assets.footer.video" = "共%ld個視頻";
14 | "assets.footer.videos" = "共%ld個視頻";
15 | "assets.footer.photo-and-video" = "共%ld 張照片, %ld 個視頻";
16 | "assets.footer.photos-and-video" = "共%ld 張照片, %ld 個視頻";
17 | "assets.footer.photo-and-videos" = "共%ld 張照片, %ld 個視頻";
18 | "assets.footer.photos-and-videos" = "共%ld 張照片, %ld 個視頻";
19 |
20 | "assets.toolbar.item-selected" = "選擇了%ld項";
21 | "assets.toolbar.items-selected" = "選擇了%ld項";
22 |
23 | "permission.help" = "您已授予有限數量的選定照片和視頻的權限。";
24 | "permission.manage" = "管理";
25 | "permission.title" = "要訪問您在應用程序中的所有照片,請在設備設置中授予訪問您的完整圖庫的權限。";
26 | "permission.choose_more" = "選擇更多照片";
27 | "permission.change_settings" = "更改設置";
28 | "permission.cancel" = "取消";
29 |
--------------------------------------------------------------------------------
/ios/QBImagePicker/QBImagePickerController.podspec:
--------------------------------------------------------------------------------
1 | Pod::Spec.new do |s|
2 | s.name = "QBImagePickerController"
3 | s.version = "3.4.0"
4 | s.summary = "A clone of UIImagePickerController with multiple selection support."
5 | s.homepage = "https://github.com/questbeat/QBImagePicker"
6 | s.license = "MIT"
7 | s.author = { "questbeat" => "questbeat@gmail.com" }
8 | s.source = { :git => "https://github.com/questbeat/QBImagePicker.git", :tag => s.version.to_s }
9 | s.social_media_url = "https://twitter.com/questbeat"
10 | s.source_files = "QBImagePicker/*.{h,m}"
11 | s.exclude_files = "QBImagePicker/QBImagePicker.h"
12 | s.resource_bundles = { "QBImagePicker" => "QBImagePicker/*.{lproj,storyboard}" }
13 | s.platform = :ios, "8.0"
14 | s.requires_arc = true
15 | s.frameworks = "Photos"
16 | end
17 |
--------------------------------------------------------------------------------
/ios/src/Compression.h:
--------------------------------------------------------------------------------
1 | //
2 | // Compression.h
3 | // imageCropPicker
4 | //
5 | // Created by Ivan Pusic on 12/24/16.
6 | // Copyright © 2016 Ivan Pusic. All rights reserved.
7 | //
8 |
9 | #import
10 | #import
11 | #import
12 |
13 | @interface ImageResult : NSObject
14 |
15 | @property NSData *data;
16 | @property NSNumber *width;
17 | @property NSNumber *height;
18 | @property NSString *mime;
19 | @property UIImage *image;
20 |
21 | @end
22 |
23 | @interface VideoResult : NSObject
24 |
25 | @end
26 |
27 | @interface Compression : NSObject
28 |
29 | - (ImageResult*) compressImage:(UIImage*)image withOptions:(NSDictionary*)options;
30 | - (void)compressVideo:(NSURL*)inputURL
31 | outputURL:(NSURL*)outputURL
32 | withOptions:(NSDictionary*)options
33 | handler:(void (^)(AVAssetExportSession*))handler;
34 |
35 | @property NSDictionary *exportPresets;
36 |
37 | @end
38 |
--------------------------------------------------------------------------------
/ios/src/Compression.m:
--------------------------------------------------------------------------------
1 | //
2 | // Compression.m
3 | // imageCropPicker
4 | //
5 | // Created by Ivan Pusic on 12/24/16.
6 | // Copyright © 2016 Ivan Pusic. All rights reserved.
7 | //
8 |
9 | #import "Compression.h"
10 |
11 | @implementation Compression
12 |
13 | - (instancetype)init {
14 | NSMutableDictionary *dic = [[NSMutableDictionary alloc] initWithDictionary:@{
15 | @"640x480": AVAssetExportPreset640x480,
16 | @"960x540": AVAssetExportPreset960x540,
17 | @"1280x720": AVAssetExportPreset1280x720,
18 | @"1920x1080": AVAssetExportPreset1920x1080,
19 | @"LowQuality": AVAssetExportPresetLowQuality,
20 | @"MediumQuality": AVAssetExportPresetMediumQuality,
21 | @"HighestQuality": AVAssetExportPresetHighestQuality,
22 | @"Passthrough": AVAssetExportPresetPassthrough,
23 | }];
24 |
25 | if (@available(iOS 9.0, *)) {
26 | [dic addEntriesFromDictionary:@{@"3840x2160": AVAssetExportPreset3840x2160}];
27 | } else {
28 | // Fallback on earlier versions
29 | }
30 |
31 | self.exportPresets = dic;
32 |
33 | return self;
34 | }
35 |
36 | - (ImageResult*) compressImageDimensions:(UIImage*)image
37 | compressImageMaxWidth:(CGFloat)maxWidth
38 | compressImageMaxHeight:(CGFloat)maxHeight
39 | intoResult:(ImageResult*)result {
40 |
41 | CGFloat oldWidth = image.size.width;
42 | CGFloat oldHeight = image.size.height;
43 |
44 | CGFloat widthScale = maxWidth / oldWidth;
45 | CGFloat heightScale = maxHeight / oldHeight;
46 | CGFloat scaleFactor = MIN(widthScale, heightScale);
47 |
48 | CGFloat newWidth = oldWidth * scaleFactor;
49 | CGFloat newHeight = oldHeight * scaleFactor;
50 |
51 | CGSize newSize = CGSizeMake(newWidth, newHeight);
52 |
53 | UIGraphicsImageRendererFormat *format = [[UIGraphicsImageRendererFormat alloc] init];
54 | format.scale = image.scale;
55 |
56 | UIGraphicsImageRenderer *renderer = [[UIGraphicsImageRenderer alloc] initWithSize:newSize format:format];
57 | UIImage *resizedImage = [renderer imageWithActions:^(UIGraphicsImageRendererContext * _Nonnull rendererContext) {
58 | [image drawInRect:CGRectMake(0, 0, newSize.width, newSize.height)];
59 | }];
60 |
61 | result.width = @(newWidth);
62 | result.height = @(newHeight);
63 | result.image = resizedImage;
64 |
65 | return result;
66 | }
67 |
68 | - (ImageResult*) compressImage:(UIImage*)image
69 | withOptions:(NSDictionary*)options {
70 |
71 | ImageResult *result = [[ImageResult alloc] init];
72 | result.width = @(image.size.width);
73 | result.height = @(image.size.height);
74 | result.image = image;
75 | result.mime = @"image/jpeg";
76 |
77 | NSNumber *compressImageMaxWidth = [options valueForKey:@"compressImageMaxWidth"];
78 | NSNumber *compressImageMaxHeight = [options valueForKey:@"compressImageMaxHeight"];
79 |
80 | // determine if it is necessary to resize image
81 | BOOL shouldResizeWidth = (compressImageMaxWidth != nil && [compressImageMaxWidth floatValue] < image.size.width);
82 | BOOL shouldResizeHeight = (compressImageMaxHeight != nil && [compressImageMaxHeight floatValue] < image.size.height);
83 |
84 | if (shouldResizeWidth || shouldResizeHeight) {
85 | CGFloat maxWidth = compressImageMaxWidth != nil ? [compressImageMaxWidth floatValue] : image.size.width;
86 | CGFloat maxHeight = compressImageMaxHeight != nil ? [compressImageMaxHeight floatValue] : image.size.height;
87 |
88 | [self compressImageDimensions:image
89 | compressImageMaxWidth:maxWidth
90 | compressImageMaxHeight:maxHeight
91 | intoResult:result];
92 | }
93 |
94 | // parse desired image quality
95 | NSNumber *compressQuality = [options valueForKey:@"compressImageQuality"];
96 | if (compressQuality == nil) {
97 | compressQuality = [NSNumber numberWithFloat:0.8];
98 | }
99 |
100 | // convert image to jpeg representation
101 | result.data = UIImageJPEGRepresentation(result.image, [compressQuality floatValue]);
102 |
103 | return result;
104 | }
105 |
106 | - (void)compressVideo:(NSURL*)inputURL
107 | outputURL:(NSURL*)outputURL
108 | withOptions:(NSDictionary*)options
109 | handler:(void (^)(AVAssetExportSession*))handler {
110 |
111 | NSString *presetKey = [options valueForKey:@"compressVideoPreset"];
112 | if (presetKey == nil) {
113 | presetKey = @"MediumQuality";
114 | }
115 |
116 | NSString *preset = [self.exportPresets valueForKey:presetKey];
117 | if (preset == nil) {
118 | preset = AVAssetExportPresetMediumQuality;
119 | }
120 |
121 | [[NSFileManager defaultManager] removeItemAtURL:outputURL error:nil];
122 | AVURLAsset *asset = [AVURLAsset URLAssetWithURL:inputURL options:nil];
123 | AVAssetExportSession *exportSession = [[AVAssetExportSession alloc] initWithAsset:asset presetName:preset];
124 | exportSession.shouldOptimizeForNetworkUse = YES;
125 | exportSession.outputURL = outputURL;
126 | exportSession.outputFileType = AVFileTypeMPEG4;
127 |
128 | [exportSession exportAsynchronouslyWithCompletionHandler:^(void) {
129 | handler(exportSession);
130 | }];
131 | }
132 |
133 | @end
134 |
--------------------------------------------------------------------------------
/ios/src/ImageCropPicker.h:
--------------------------------------------------------------------------------
1 | //
2 | // ImageManager.h
3 | //
4 | // Created by Ivan Pusic on 5/4/16.
5 | // Copyright © 2016 Facebook. All rights reserved.
6 | //
7 |
8 | #ifndef RN_IMAGE_CROP_PICKER_h
9 | #define RN_IMAGE_CROP_PICKER_h
10 |
11 | #import
12 |
13 | #if __has_include()
14 | #import
15 | #import
16 | #import
17 | #import
18 | #import
19 | #else
20 | #import "RCTBridgeModule.h"
21 | #import "RCTImageURLLoader.h"
22 | #import "RCTImageShadowView.h"
23 | #import "RCTImageView.h"
24 | #import "RCTImageLoaderProtocol.h"
25 | #endif
26 |
27 | #ifdef RCT_NEW_ARCH_ENABLED
28 | #import
29 | #endif
30 |
31 | #if __has_include("QBImagePicker.h")
32 | #import "QBImagePicker.h"
33 | #elif __has_include()
34 | #import
35 | #elif __has_include("QBImagePickerController.h") // local QBImagePickerController subspec
36 | #import "QBImagePickerController.h"
37 | #else
38 | #import "QBImagePicker/QBImagePicker.h"
39 | #endif
40 |
41 |
42 | #import
43 |
44 | #import "UIImage+Resize.h"
45 | #import "UIImage+Extension.h"
46 | #import "Compression.h"
47 | #import
48 |
49 | @interface ImageCropPicker : NSObject<
50 | UIImagePickerControllerDelegate,
51 | UINavigationControllerDelegate,
52 | RCTBridgeModule,
53 | QBImagePickerControllerDelegate,
54 | TOCropViewControllerDelegate>
55 |
56 | typedef enum selectionMode {
57 | CAMERA,
58 | CROPPING,
59 | PICKER
60 | } SelectionMode;
61 |
62 | @property (nonatomic, strong) NSMutableDictionary *croppingFile;
63 | @property (nonatomic, strong) NSDictionary *defaultOptions;
64 | @property (nonatomic, strong) Compression *compression;
65 | @property (nonatomic, retain) NSMutableDictionary *options;
66 | @property (nonatomic, strong) RCTPromiseResolveBlock resolve;
67 | @property (nonatomic, strong) RCTPromiseRejectBlock reject;
68 | @property SelectionMode currentSelectionMode;
69 |
70 | @end
71 |
72 | #endif
73 |
--------------------------------------------------------------------------------
/ios/src/UIImage+Extension.h:
--------------------------------------------------------------------------------
1 | //
2 | // UIImage+Extension.h
3 | // Pods
4 | //
5 | // Created by Ivan Pusic on 09/05/2020.
6 | //
7 |
8 | #ifndef UIImage_Extension_h
9 | #define UIImage_Extension_h
10 |
11 | #import
12 |
13 | @interface UIImage (fixOrientation)
14 |
15 | - (UIImage *)fixOrientation;
16 |
17 | @end
18 |
19 | #endif /* UIImage_Extension_h */
20 |
--------------------------------------------------------------------------------
/ios/src/UIImage+Extension.m:
--------------------------------------------------------------------------------
1 | //
2 | // UIImage+Extension.m
3 | // DoubleConversion
4 | //
5 | // Created by Ivan Pusic on 09/05/2020.
6 | //
7 |
8 | #import "UIImage+Extension.h"
9 |
10 | @implementation UIImage (fixOrientation)
11 |
12 | - (UIImage *)fixOrientation
13 | {
14 | // No-op if the orientation is already correct.
15 | if (self.imageOrientation == UIImageOrientationUp) {
16 | return self;
17 | }
18 |
19 | // We need to calculate the proper transformation to make the image upright.
20 | // We do it in 2 steps: Rotate if Left/Right/Down, and then flip if Mirrored.
21 | CGAffineTransform transform = CGAffineTransformIdentity;
22 |
23 | switch (self.imageOrientation) {
24 | case UIImageOrientationDown:
25 | case UIImageOrientationDownMirrored:
26 | transform = CGAffineTransformTranslate(transform, self.size.width, self.size.height);
27 | transform = CGAffineTransformRotate(transform, M_PI);
28 | break;
29 |
30 | case UIImageOrientationLeft:
31 | case UIImageOrientationLeftMirrored:
32 | transform = CGAffineTransformTranslate(transform, self.size.width, 0);
33 | transform = CGAffineTransformRotate(transform, M_PI_2);
34 | break;
35 |
36 | case UIImageOrientationRight:
37 | case UIImageOrientationRightMirrored:
38 | transform = CGAffineTransformTranslate(transform, 0, self.size.height);
39 | transform = CGAffineTransformRotate(transform, -M_PI_2);
40 | break;
41 | case UIImageOrientationUp:
42 | case UIImageOrientationUpMirrored:
43 | break;
44 | }
45 |
46 | switch (self.imageOrientation) {
47 | case UIImageOrientationUpMirrored:
48 | case UIImageOrientationDownMirrored:
49 | transform = CGAffineTransformTranslate(transform, self.size.width, 0);
50 | transform = CGAffineTransformScale(transform, -1, 1);
51 | break;
52 |
53 | case UIImageOrientationLeftMirrored:
54 | case UIImageOrientationRightMirrored:
55 | transform = CGAffineTransformTranslate(transform, self.size.height, 0);
56 | transform = CGAffineTransformScale(transform, -1, 1);
57 | break;
58 | case UIImageOrientationUp:
59 | case UIImageOrientationDown:
60 | case UIImageOrientationLeft:
61 | case UIImageOrientationRight:
62 | break;
63 | }
64 |
65 | // Now we draw the underlying CGImage into a new context, applying the transform
66 | // calculated above.
67 | CGContextRef ctx = CGBitmapContextCreate(NULL, self.size.width, self.size.height,
68 | CGImageGetBitsPerComponent(self.CGImage), 0,
69 | CGImageGetColorSpace(self.CGImage),
70 | CGImageGetBitmapInfo(self.CGImage));
71 | CGContextConcatCTM(ctx, transform);
72 | switch (self.imageOrientation) {
73 | case UIImageOrientationLeft:
74 | case UIImageOrientationLeftMirrored:
75 | case UIImageOrientationRight:
76 | case UIImageOrientationRightMirrored:
77 | CGContextDrawImage(ctx, CGRectMake(0, 0, self.size.height, self.size.width), self.CGImage);
78 | break;
79 |
80 | default:
81 | CGContextDrawImage(ctx, CGRectMake(0, 0, self.size.width, self.size.height), self.CGImage);
82 | break;
83 | }
84 |
85 | // And now we just create a new UIImage from the drawing context.
86 | CGImageRef cgimg = CGBitmapContextCreateImage(ctx);
87 | UIImage *img = [UIImage imageWithCGImage:cgimg];
88 | CGContextRelease(ctx);
89 | CGImageRelease(cgimg);
90 |
91 | return img;
92 | }
93 |
94 | @end
95 |
--------------------------------------------------------------------------------
/ios/src/UIImage+Resize.h:
--------------------------------------------------------------------------------
1 | /***********************************************************************************
2 | *
3 | * Copyright (c) 2010 Olivier Halligon
4 | *
5 | * Permission is hereby granted, free of charge, to any person obtaining a copy
6 | * of this software and associated documentation files (the "Software"), to deal
7 | * in the Software without restriction, including without limitation the rights
8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | * copies of the Software, and to permit persons to whom the Software is
10 | * furnished to do so, subject to the following conditions:
11 | *
12 | * The above copyright notice and this permission notice shall be included in
13 | * all copies or substantial portions of the Software.
14 | *
15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | * THE SOFTWARE.
22 | *
23 | ***********************************************************************************
24 | *
25 | * Any comment or suggestion welcome. Referencing this project in your AboutBox is appreciated.
26 | * Please tell me if you use this class so we can cross-reference our projects.
27 | *
28 | ***********************************************************************************/
29 |
30 |
31 | #import
32 | #import
33 |
34 | @interface UIImage(ResizeCategory)
35 | -(UIImage*)resizedImageToSize:(CGSize)dstSize;
36 | -(UIImage*)resizedImageToFitInSize:(CGSize)boundingSize scaleIfSmaller:(BOOL)scale;
37 | @end
38 |
--------------------------------------------------------------------------------
/ios/src/UIImage+Resize.m:
--------------------------------------------------------------------------------
1 | //
2 | // UIImage+Resize.m
3 | //
4 | // Created by Olivier Halligon on 12/08/09.
5 | // Copyright 2009 AliSoftware. All rights reserved.
6 | //
7 |
8 | #import "UIImage+Resize.h"
9 |
10 | @implementation UIImage (ResizeCategory)
11 |
12 | -(UIImage*)resizedImageToSize:(CGSize)dstSize
13 | {
14 | CGImageRef imgRef = self.CGImage;
15 | // the below values are regardless of orientation : for UIImages from Camera, width>height (landscape)
16 | CGSize srcSize = CGSizeMake(CGImageGetWidth(imgRef), CGImageGetHeight(imgRef)); // not equivalent to self.size (which is dependant on the imageOrientation)!
17 |
18 | /* Don't resize if we already meet the required destination size. */
19 | if (CGSizeEqualToSize(srcSize, dstSize)) {
20 | return self;
21 | }
22 |
23 | CGFloat scaleRatio = dstSize.width / srcSize.width;
24 | UIImageOrientation orient = self.imageOrientation;
25 | CGAffineTransform transform = CGAffineTransformIdentity;
26 | switch(orient) {
27 |
28 | case UIImageOrientationUp: //EXIF = 1
29 | transform = CGAffineTransformIdentity;
30 | break;
31 |
32 | case UIImageOrientationUpMirrored: //EXIF = 2
33 | transform = CGAffineTransformMakeTranslation(srcSize.width, 0.0);
34 | transform = CGAffineTransformScale(transform, -1.0, 1.0);
35 | break;
36 |
37 | case UIImageOrientationDown: //EXIF = 3
38 | transform = CGAffineTransformMakeTranslation(srcSize.width, srcSize.height);
39 | transform = CGAffineTransformRotate(transform, M_PI);
40 | break;
41 |
42 | case UIImageOrientationDownMirrored: //EXIF = 4
43 | transform = CGAffineTransformMakeTranslation(0.0, srcSize.height);
44 | transform = CGAffineTransformScale(transform, 1.0, -1.0);
45 | break;
46 |
47 | case UIImageOrientationLeftMirrored: //EXIF = 5
48 | dstSize = CGSizeMake(dstSize.height, dstSize.width);
49 | transform = CGAffineTransformMakeTranslation(srcSize.height, srcSize.width);
50 | transform = CGAffineTransformScale(transform, -1.0, 1.0);
51 | transform = CGAffineTransformRotate(transform, 3.0 * M_PI_2);
52 | break;
53 |
54 | case UIImageOrientationLeft: //EXIF = 6
55 | dstSize = CGSizeMake(dstSize.height, dstSize.width);
56 | transform = CGAffineTransformMakeTranslation(0.0, srcSize.width);
57 | transform = CGAffineTransformRotate(transform, 3.0 * M_PI_2);
58 | break;
59 |
60 | case UIImageOrientationRightMirrored: //EXIF = 7
61 | dstSize = CGSizeMake(dstSize.height, dstSize.width);
62 | transform = CGAffineTransformMakeScale(-1.0, 1.0);
63 | transform = CGAffineTransformRotate(transform, M_PI_2);
64 | break;
65 |
66 | case UIImageOrientationRight: //EXIF = 8
67 | dstSize = CGSizeMake(dstSize.height, dstSize.width);
68 | transform = CGAffineTransformMakeTranslation(srcSize.height, 0.0);
69 | transform = CGAffineTransformRotate(transform, M_PI_2);
70 | break;
71 |
72 | default:
73 | [NSException raise:NSInternalInconsistencyException format:@"Invalid image orientation"];
74 |
75 | }
76 |
77 | /////////////////////////////////////////////////////////////////////////////
78 | // The actual resize: draw the image on a new context, applying a transform matrix
79 | UIGraphicsBeginImageContextWithOptions(dstSize, NO, self.scale);
80 |
81 | CGContextRef context = UIGraphicsGetCurrentContext();
82 |
83 | if (!context) {
84 | return nil;
85 | }
86 |
87 | if (orient == UIImageOrientationRight || orient == UIImageOrientationLeft) {
88 | CGContextScaleCTM(context, -scaleRatio, scaleRatio);
89 | CGContextTranslateCTM(context, -srcSize.height, 0);
90 | } else {
91 | CGContextScaleCTM(context, scaleRatio, -scaleRatio);
92 | CGContextTranslateCTM(context, 0, -srcSize.height);
93 | }
94 |
95 | CGContextConcatCTM(context, transform);
96 |
97 | // we use srcSize (and not dstSize) as the size to specify is in user space (and we use the CTM to apply a scaleRatio)
98 | CGContextDrawImage(UIGraphicsGetCurrentContext(), CGRectMake(0, 0, srcSize.width, srcSize.height), imgRef);
99 | UIImage* resizedImage = UIGraphicsGetImageFromCurrentImageContext();
100 | UIGraphicsEndImageContext();
101 |
102 | return resizedImage;
103 | }
104 |
105 |
106 |
107 | /////////////////////////////////////////////////////////////////////////////
108 |
109 |
110 |
111 | -(UIImage*)resizedImageToFitInSize:(CGSize)boundingSize scaleIfSmaller:(BOOL)scale
112 | {
113 | // get the image size (independant of imageOrientation)
114 | CGImageRef imgRef = self.CGImage;
115 | CGSize srcSize = CGSizeMake(CGImageGetWidth(imgRef), CGImageGetHeight(imgRef)); // not equivalent to self.size (which depends on the imageOrientation)!
116 |
117 | // adjust boundingSize to make it independant on imageOrientation too for farther computations
118 | UIImageOrientation orient = self.imageOrientation;
119 | switch (orient) {
120 | case UIImageOrientationLeft:
121 | case UIImageOrientationRight:
122 | case UIImageOrientationLeftMirrored:
123 | case UIImageOrientationRightMirrored:
124 | boundingSize = CGSizeMake(boundingSize.height, boundingSize.width);
125 | break;
126 | default:
127 | // NOP
128 | break;
129 | }
130 |
131 | // Compute the target CGRect in order to keep aspect-ratio
132 | CGSize dstSize;
133 |
134 | if ( !scale && (srcSize.width < boundingSize.width) && (srcSize.height < boundingSize.height) ) {
135 | //NSLog(@"Image is smaller, and we asked not to scale it in this case (scaleIfSmaller:NO)");
136 | dstSize = srcSize; // no resize (we could directly return 'self' here, but we draw the image anyway to take image orientation into account)
137 | } else {
138 | CGFloat wRatio = boundingSize.width / srcSize.width;
139 | CGFloat hRatio = boundingSize.height / srcSize.height;
140 |
141 | if (wRatio < hRatio) {
142 | //NSLog(@"Width imposed, Height scaled ; ratio = %f",wRatio);
143 | dstSize = CGSizeMake(boundingSize.width, floorf(srcSize.height * wRatio));
144 | } else {
145 | //NSLog(@"Height imposed, Width scaled ; ratio = %f",hRatio);
146 | dstSize = CGSizeMake(floorf(srcSize.width * hRatio), boundingSize.height);
147 | }
148 | }
149 |
150 | return [self resizedImageToSize:dstSize];
151 | }
152 |
153 | @end
154 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-native-image-crop-picker",
3 | "version": "0.50.1",
4 | "description": "Select single or multiple images, with cropping option",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1",
8 | "prepublish": "rm -rf android/build"
9 | },
10 | "repository": {
11 | "type": "git",
12 | "url": "git+https://github.com/ivpusic/react-native-image-crop-picker.git"
13 | },
14 | "keywords": [
15 | "react",
16 | "native",
17 | "react-native",
18 | "image",
19 | "picker",
20 | "crop",
21 | "cropping",
22 | "multiple",
23 | "camera"
24 | ],
25 | "author": "Ivan Pusic",
26 | "license": "MIT",
27 | "bugs": {
28 | "url": "https://github.com/ivpusic/react-native-image-crop-picker/issues"
29 | },
30 | "homepage": "https://github.com/ivpusic/react-native-image-crop-picker#readme",
31 | "peerDependencies": {
32 | "react": "*",
33 | "react-native": "*"
34 | },
35 | "codegenConfig": {
36 | "name": "RNCImageCropPickerSpec",
37 | "type": "modules",
38 | "jsSrcsDir": "src",
39 | "android": {
40 | "javaPackageName": "com.reactnative.ivpusic.imagepicker"
41 | }
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/src/NativeImageCropPicker.ts:
--------------------------------------------------------------------------------
1 | import { TurboModule, TurboModuleRegistry } from "react-native";
2 |
3 | export type PickerResponse = {
4 | path: string;
5 | localIdentifier?: string;
6 | sourceURL?: string;
7 | filename?: string;
8 | width: number;
9 | height: number;
10 | mime: string;
11 | size: number;
12 | duration?: number;
13 | data?: string;
14 | exif?: {
15 | [key: string]: string;
16 | };
17 | cropRect?: {
18 | width: number;
19 | height: number;
20 | x: number;
21 | y: number;
22 | };
23 | creationDate?: string;
24 | modificationDate?: string;
25 | };
26 |
27 | export type PickerOptions = {
28 | mediaType?: string;
29 | multiple?: boolean;
30 | includeBase64?: boolean;
31 | includeExif?: boolean;
32 | cropping?: boolean;
33 | width?: number;
34 | height?: number;
35 | cropperActiveWidgetColor?: string;
36 | cropperStatusBarColor?: string;
37 | cropperToolbarColor?: string;
38 | cropperToolbarTitle?: string;
39 | cropperToolbarWidgetColor?: string;
40 | cropperCircleOverlay?: boolean;
41 | freeStyleCropEnabled?: boolean;
42 | showCropGuidelines?: boolean;
43 | showCropFrame?: boolean;
44 | hideBottomControls?: boolean;
45 | enableRotationGesture?: boolean;
46 | disableCropperColorSetters?: boolean;
47 | useFrontCamera?: boolean;
48 | };
49 |
50 | export interface Spec extends TurboModule {
51 | openPicker(options: PickerOptions): Promise;
52 | openCamera(options: PickerOptions): Promise;
53 | openCropper(options: PickerOptions): Promise;
54 | clean(): Promise;
55 | cleanSingle(path: string): Promise;
56 | }
57 |
58 | export default TurboModuleRegistry.getEnforcing(
59 | "RNCImageCropPicker"
60 | ) as Spec;
61 |
--------------------------------------------------------------------------------
/yarn.lock:
--------------------------------------------------------------------------------
1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
2 | # yarn lockfile v1
3 |
4 |
5 |
--------------------------------------------------------------------------------