Skip to content

Commit 63a49f4

Browse files
committed
fix [#39](#39) and add feature for [#42](#42) / [#38](#38)
1 parent 6ec5a2b commit 63a49f4

File tree

221 files changed

+10454
-66
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

221 files changed

+10454
-66
lines changed

README.md

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ __C.UIAction.init(title: Swift.String, image: __C.UIImage?, identifier: __C.UIAc
4747

4848
Here are some related issues in the RN repo: [Issue 30202](https://github.com/facebook/react-native/pull/30202) and [Issue 29178](https://github.com/facebook/react-native/pull/29178). This bug could be fixed in a future version of react native, but a workaround I've found is to do the following:
4949

50+
<img src="./files/resolve-error-iOS.png">
51+
5052
1. Open your `ios/project.xcworkspace` project.
5153
2. In the project navigator panel (located on the right side of Xcode), select your project group (i.e. the item with the blueprint icon).
5254
3. The Xcode project editor should appear. In the left panel, under the "Project" section, select your project (if it isn't already selected).
@@ -61,18 +63,22 @@ Here are some related issues in the RN repo: [Issue 30202](https://github.com/fa
6163
- Try clearing out Xcode's `derivedData` directory: `rm -rf ~/Library/Developer/Xcode/DerivedData/*` (check out this [gist](https://gist.github.com/maciekish/66b6deaa7bc979d0a16c50784e16d697) for instructions on how to clean up Xcode)
6264
- Try clearing out the `Cocoapods` cache: `rm -rf "${HOME}/Library/Caches/CocoaPods"` (and then try running `pod install` again).
6365

64-
<img src="./files/resolve-error-iOS.png">
65-
6666
### Android
6767

68+
> Add this lines in `settings.gradle` then `Sync Project with Gradle Files`
69+
70+
```
71+
include ':picture_library'
72+
project(':picture_library').projectDir = new File(rootProject.projectDir, '../node_modules/@baronha/react-native-multiple-image-picker/picture_library')
73+
```
74+
6875
> Add Permission in `AndroidManifest.xml`
6976
7077
```xml
7178
<uses-permission android:name="android.permission.CAMERA" />
7279
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
7380
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
7481
```
75-
7682
## Usage
7783

7884
See [options](#Options)
@@ -121,8 +127,9 @@ const response = await MultipleImagePicker.openPicker(options);
121127
| emptyMessage | string | No albums | iOS | Show string when gallery empty |
122128
| maximumMessageTitle | string | Notification | iOS | The title of the alert when the user chooses to exceed the specified number of pictures |
123129
| messageTitleButton | string | Notification | iOS | The title of button in the alert when the user chooses to exceed the specified number of pictures |
124-
| maximumMessage | string | You have selected the maximum number of media allowed | iOS | The description of the alert when the user chooses to exceed the specified number of pictures |
125130
| tapHereToChange | string | Tap here to change | iOS | The sub-title in navigation bar (under albums's name in iOS) |
131+
| maximumMessage | string | You have selected the maximum number of media allowed | Both | The description of the alert when the user chooses to exceed the specified number of pictures |
132+
| maximumVideoMessage | string | You have selected the maximum number of media allowed | Both | The description of the alert when the user chooses to exceed the specified number of videos |
126133

127134
#### selectedAssets (Important)
128135

@@ -150,7 +157,6 @@ Get an Array value only. If you want React Native Multiple Image Picker to re-se
150157
- [ ] Typescript.
151158
- [ ] (Bug) Record Video (iOS).
152159
- [ ] Video Compression.
153-
- [x] iCloud.
154160

155161
## Performance
156162

android/build.gradle

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
buildscript {
22
// Buildscript is evaluated before everything else so we can't use getExtOrDefault
3-
def kotlin_version = rootProject.ext.has('kotlinVersion') ? rootProject.ext.get('kotlinVersion') : project.properties['MultipleImagePicker_kotlinVersion']
3+
def kotlin_version = "1.4.32"
44

55
repositories {
66
google()
@@ -121,15 +121,13 @@ repositories {
121121
}
122122
}
123123

124-
def kotlin_version = getExtOrDefault('kotlinVersion')
124+
def kotlin_version = "1.4.32"
125125

126126
dependencies {
127127
// noinspection GradleDynamicVersion
128128
api 'com.facebook.react:react-native:+'
129129
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
130-
implementation ('com.github.LuckSiege.PictureSelector:picture_library:v2.6.0'){
131-
exclude group: 'com.github.LuckSiege.PictureSelector', module: 'ucrop'
132-
}
130+
implementation project(":picture_library")
133131
implementation 'com.github.bumptech.glide:glide:4.12.0'
134132
annotationProcessor 'com.github.bumptech.glide:compiler:4.12.0'
135133
}

android/src/main/java/com/reactnativemultipleimagepicker/MultipleImagePickerModule.kt

Lines changed: 77 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import com.luck.picture.lib.config.PictureConfig
1414
import com.luck.picture.lib.config.PictureMimeType
1515
import com.luck.picture.lib.engine.PictureSelectorEngine
1616
import com.luck.picture.lib.entity.LocalMedia
17+
import com.luck.picture.lib.entity.LocalMedia.parseLocalMedia
1718
import com.luck.picture.lib.listener.OnResultCallbackListener
1819
import com.luck.picture.lib.style.PictureParameterStyle
1920
import java.io.File
@@ -24,7 +25,8 @@ import java.util.*
2425

2526

2627
@Suppress("INCOMPATIBLE_ENUM_COMPARISON", "UNCHECKED_CAST")
27-
class MultipleImagePickerModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaModule(reactContext), IApp {
28+
class MultipleImagePickerModule(reactContext: ReactApplicationContext) :
29+
ReactContextBaseJavaModule(reactContext), IApp {
2830

2931
override fun getName(): String {
3032
return "MultipleImagePicker"
@@ -41,6 +43,8 @@ class MultipleImagePickerModule(reactContext: ReactApplicationContext) : ReactCo
4143
private var isExportThumbnail: Boolean = false
4244
private var maxVideo: Int = 20
4345
private var isCamera: Boolean = true
46+
private var maximumMessage: String = ""
47+
private var maximumVideoMessage: String = ""
4448

4549
@ReactMethod
4650
fun openPicker(options: ReadableMap?, promise: Promise): Unit {
@@ -49,56 +53,59 @@ class MultipleImagePickerModule(reactContext: ReactApplicationContext) : ReactCo
4953
setConfiguration(options)
5054

5155
PictureSelector.create(activity)
52-
.openGallery(if (mediaType == "video") PictureMimeType.ofVideo() else if (mediaType == "image") PictureMimeType.ofImage() else PictureMimeType.ofAll())
53-
.loadImageEngine(GlideEngine.createGlideEngine())
54-
.maxSelectNum(maxSelectedAssets)
55-
.imageSpanCount(numberOfColumn)
56-
.isZoomAnim(true)
57-
.isPageStrategy(true, 50)
58-
.isWithVideoImage(true)
59-
.videoMaxSecond(maxVideoDuration)
60-
.maxVideoSelectNum(if (maxVideo != 20) maxVideo else maxSelectedAssets)
61-
.isMaxSelectEnabledMask(true)
62-
.selectionData(selectedAssets)
63-
.setPictureStyle(mPictureParameterStyle)
64-
.isPreviewImage(isPreview)
65-
.isPreviewVideo(isPreview)
66-
.isCamera(isCamera)
67-
.isReturnEmpty(true)
68-
.selectionMode(if (singleSelectedMode) PictureConfig.SINGLE else PictureConfig.MULTIPLE)
69-
.forResult(object : OnResultCallbackListener<Any?> {
70-
override fun onResult(result: MutableList<Any?>?) {
71-
//check difference
72-
if (singleSelectedMode) {
73-
val singleLocalMedia: WritableArray = WritableNativeArray()
74-
val media: WritableMap = createAttachmentResponse(result?.get(0) as LocalMedia)
75-
singleLocalMedia.pushMap(media)
76-
promise.resolve(singleLocalMedia)
77-
return
78-
}
79-
val localMedia: WritableArray = WritableNativeArray()
80-
if (result?.size == 0) {
81-
promise.resolve(localMedia)
82-
return
83-
}
84-
if (result?.size == selectedAssets.size && (result[result.size - 1] as LocalMedia).id == (selectedAssets[selectedAssets.size - 1].id)) {
85-
return
86-
}
87-
if (result != null) {
88-
for (i in 0 until result.size) {
89-
val item: LocalMedia = result[i] as LocalMedia
90-
println("item: $item")
91-
val media: WritableMap = createAttachmentResponse(item)
92-
localMedia.pushMap(media)
93-
}
94-
}
56+
.openGallery(if (mediaType == "video") PictureMimeType.ofVideo() else if (mediaType == "image") PictureMimeType.ofImage() else PictureMimeType.ofAll())
57+
.loadImageEngine(GlideEngine.createGlideEngine())
58+
.maxSelectNum(maxSelectedAssets)
59+
.imageSpanCount(numberOfColumn)
60+
.isZoomAnim(true)
61+
.isPageStrategy(true, 50)
62+
.isWithVideoImage(true)
63+
.videoMaxSecond(maxVideoDuration)
64+
.maxVideoSelectNum(if (maxVideo != 20) maxVideo else maxSelectedAssets)
65+
.isMaxSelectEnabledMask(true)
66+
.selectionData(selectedAssets)
67+
.setPictureStyle(mPictureParameterStyle)
68+
.isPreviewImage(isPreview)
69+
.isPreviewVideo(isPreview)
70+
.isCamera(isCamera)
71+
.isReturnEmpty(true)
72+
.maximumMessage(maximumMessage)
73+
.maximumVideoMessage(maximumVideoMessage)
74+
.selectionMode(if (singleSelectedMode) PictureConfig.SINGLE else PictureConfig.MULTIPLE)
75+
.forResult(object : OnResultCallbackListener<LocalMedia?> {
76+
override fun onResult(result: MutableList<LocalMedia?>?) {
77+
//check difference
78+
if (singleSelectedMode) {
79+
val singleLocalMedia: WritableArray = WritableNativeArray()
80+
val media: WritableMap =
81+
createAttachmentResponse(result?.get(0) as LocalMedia)
82+
singleLocalMedia.pushMap(media)
83+
promise.resolve(singleLocalMedia)
84+
return
85+
}
86+
val localMedia: WritableArray = WritableNativeArray()
87+
if (result?.size == 0) {
9588
promise.resolve(localMedia)
89+
return
9690
}
97-
98-
override fun onCancel() {
99-
promise.reject("user cancel")
91+
if (result?.size == selectedAssets.size && (result[result.size - 1] as LocalMedia).id == (selectedAssets[selectedAssets.size - 1].id)) {
92+
return
10093
}
101-
})
94+
if (result != null) {
95+
for (i in 0 until result.size) {
96+
val item: LocalMedia = result[i] as LocalMedia
97+
println("item: $item")
98+
val media: WritableMap = createAttachmentResponse(item)
99+
localMedia.pushMap(media)
100+
}
101+
}
102+
promise.resolve(localMedia)
103+
}
104+
105+
override fun onCancel() {
106+
promise.reject("user cancel")
107+
}
108+
})
102109
}
103110

104111
private fun setConfiguration(options: ReadableMap?) {
@@ -114,6 +121,8 @@ class MultipleImagePickerModule(reactContext: ReactApplicationContext) : ReactCo
114121
maxVideo = options.getInt("maxVideo")
115122
mPictureParameterStyle = getStyle(options)
116123
isCamera = options.getBoolean("usedCameraButton")
124+
maximumMessage = options.getString("maximumMessage").toString()
125+
maximumVideoMessage = options.getString("maximumVideoMessage").toString()
117126
}
118127
}
119128

@@ -145,7 +154,8 @@ class MultipleImagePickerModule(reactContext: ReactApplicationContext) : ReactCo
145154
if (options?.hasKey("selectedAssets")!!) {
146155
val assetsType = options.getType("selectedAssets")
147156
if (assetsType == ReadableType.Array) {
148-
val assets: ReadableNativeArray = options.getArray("selectedAssets") as ReadableNativeArray
157+
val assets: ReadableNativeArray =
158+
options.getArray("selectedAssets") as ReadableNativeArray
149159
if (assets.size() > 0) {
150160
val list = mutableListOf<LocalMedia>()
151161
for (i in 0 until assets.size()) {
@@ -177,7 +187,22 @@ class MultipleImagePickerModule(reactContext: ReactApplicationContext) : ReactCo
177187
val height: Int = asset.getInt("height")
178188
val size: Long = asset.getDouble("size").toLong()
179189
val bucketId: Long = asset.getDouble("bucketId").toLong()
180-
val localMedia = LocalMedia(id, path, realPath, fileName, parentFolderName, duration, chooseModel, mimeType, width, height, size, bucketId)
190+
val dateAddedColumn: Long = Date().time.toLong()
191+
val localMedia = parseLocalMedia(
192+
id,
193+
path,
194+
realPath,
195+
fileName,
196+
parentFolderName,
197+
duration,
198+
chooseModel,
199+
mimeType,
200+
width,
201+
height,
202+
size,
203+
bucketId,
204+
dateAddedColumn
205+
)
181206
return localMedia
182207
}
183208

@@ -212,9 +237,9 @@ class MultipleImagePickerModule(reactContext: ReactApplicationContext) : ReactCo
212237
retriever.setDataSource(filePath)
213238
val image = retriever.getFrameAtTime(1000000, MediaMetadataRetriever.OPTION_CLOSEST_SYNC)
214239

215-
val fullPath: String = reactApplicationContext.applicationContext.cacheDir.absolutePath.toString() + "/thumbnails"
240+
val fullPath: String =
241+
reactApplicationContext.applicationContext.cacheDir.absolutePath.toString() + "/thumbnails"
216242
try {
217-
val dir = fullPath.let { createDirIfNotExists(it) }
218243
var fOut: OutputStream? = null
219244
val fileName = "thumb-" + UUID.randomUUID().toString() + ".jpeg"
220245
print("fileName $fileName")

example/android/app/src/main/AndroidManifest.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
2+
xmlns:tools="http://schemas.android.com/tools"
23
package="com.example.reactnativemultipleimagepicker">
34

45
<uses-permission android:name="android.permission.INTERNET" />
@@ -25,6 +26,7 @@
2526
</intent-filter>
2627
</activity>
2728
<activity android:name="com.facebook.react.devsupport.DevSettingsActivity" />
29+
2830
</application>
2931

3032
</manifest>

example/android/build.gradle

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@
33
buildscript {
44
ext {
55
buildToolsVersion = "29.0.2"
6-
minSdkVersion = 19
7-
compileSdkVersion = 29
8-
targetSdkVersion = 29
6+
minSdkVersion = 21
7+
compileSdkVersion = 30
8+
targetSdkVersion = 30
99
}
1010
repositories {
1111
google()

example/android/settings.gradle

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,8 @@ rootProject.name = 'MultipleImagePickerExample'
22
apply from: file("../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesSettingsGradle(settings)
33
include ':app'
44

5+
include ':picture_library'
6+
project(':picture_library').projectDir = new File(rootProject.projectDir, '../../picture_library')
7+
58
include ':reactnativemultipleimagepicker'
69
project(':reactnativemultipleimagepicker').projectDir = new File(rootProject.projectDir, '../../android')

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@baronha/react-native-multiple-image-picker",
3-
"version": "0.4.1",
3+
"version": "0.4.5",
44
"description": "react-native-multiple-image-picker enables application to pick images and videos from multiple smart album in iOS/Android, similar to the current facebook app.",
55
"main": "lib/commonjs/index",
66
"module": "lib/module/index",
@@ -11,6 +11,7 @@
1111
"src",
1212
"lib",
1313
"android",
14+
"picture_library",
1415
"ios",
1516
"cpp",
1617
"react-native-multiple-image-picker.podspec",

picture_library/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/build

picture_library/build.gradle

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
apply plugin: 'com.android.library'
2+
apply from: "config.gradle"
3+
4+
android {
5+
compileSdkVersion cfgs.compileSdkVersion
6+
7+
defaultConfig {
8+
minSdkVersion cfgs.minSdkVersion
9+
targetSdkVersion cfgs.targetSdkVersion
10+
versionCode cfgs.versionCode
11+
versionName cfgs.versionName
12+
13+
vectorDrawables.useSupportLibrary = true
14+
}
15+
16+
compileOptions {
17+
sourceCompatibility JavaVersion.VERSION_1_8
18+
targetCompatibility JavaVersion.VERSION_1_8
19+
}
20+
21+
buildTypes {
22+
release {
23+
minifyEnabled false
24+
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
25+
}
26+
}
27+
lintOptions {
28+
abortOnError false
29+
}
30+
31+
resourcePrefix 'ucrop_'
32+
}
33+
34+
apply from: './publish.gradle'
35+
36+
dependencies {
37+
implementation "androidx.appcompat:appcompat:${cfgs.version_appcompat}"
38+
implementation "androidx.recyclerview:recyclerview:${cfgs.version_recyclerview}"
39+
implementation "androidx.activity:activity:${cfgs.activity_version}"
40+
implementation "androidx.fragment:fragment:${cfgs.fragment_version}"
41+
implementation "androidx.concurrent:concurrent-futures:${cfgs.futures_version}"
42+
implementation "androidx.annotation:annotation-experimental:${cfgs.experimental_version}"
43+
implementation "androidx.exifinterface:exifinterface:${cfgs.androidx_exifinterface_version}"
44+
implementation "androidx.localbroadcastmanager:localbroadcastmanager:${cfgs.localbroadcastmanager}"
45+
implementation "androidx.camera:camera-view:${cfgs.camerax_view}"
46+
implementation "androidx.transition:transition:${cfgs.androidx_transition_version}"
47+
implementation "androidx.camera:camera-lifecycle:${cfgs.camerax_version}"
48+
}

0 commit comments

Comments
 (0)