expo-image-picker 13.2.1 → 13.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +15 -2
- package/android/build.gradle +8 -6
- package/android/src/main/java/expo/modules/imagepicker/ImagePickerModule.kt +22 -14
- package/android/src/main/java/expo/modules/imagepicker/ImagePickerOptions.kt +3 -0
- package/android/src/main/java/expo/modules/imagepicker/ImagePickerResponse.kt +33 -23
- package/android/src/main/java/expo/modules/imagepicker/ImagePickerUtils.kt +108 -0
- package/android/src/main/java/expo/modules/imagepicker/MediaHandler.kt +20 -8
- package/android/src/main/java/expo/modules/imagepicker/contracts/CameraContract.kt +10 -2
- package/android/src/main/java/expo/modules/imagepicker/contracts/ContractsUtils.kt +1 -7
- package/android/src/main/java/expo/modules/imagepicker/contracts/CropImageContract.kt +20 -25
- package/android/src/main/java/expo/modules/imagepicker/contracts/ImageLibraryContract.kt +18 -4
- package/build/ImagePicker.d.ts +1 -1
- package/build/ImagePicker.js +1 -1
- package/build/ImagePicker.js.map +1 -1
- package/build/ImagePicker.types.d.ts +11 -0
- package/build/ImagePicker.types.d.ts.map +1 -1
- package/build/ImagePicker.types.js.map +1 -1
- package/ios/ImagePickerExceptions.swift +6 -0
- package/ios/ImagePickerResponse.swift +4 -0
- package/ios/MediaHandler.swift +36 -33
- package/package.json +2 -2
- package/src/ImagePicker.ts +1 -1
- package/src/ImagePicker.types.ts +11 -0
package/CHANGELOG.md
CHANGED
|
@@ -10,6 +10,19 @@
|
|
|
10
10
|
|
|
11
11
|
### 💡 Others
|
|
12
12
|
|
|
13
|
+
## 13.3.0 — 2022-07-16
|
|
14
|
+
|
|
15
|
+
### 🎉 New features
|
|
16
|
+
|
|
17
|
+
- On iOS 14+ added support for selection limit and on iOS 15+ for ordered selection. ([#18142](https://github.com/expo/expo/pull/18142), [#18143](https://github.com/expo/expo/pull/18143) by [@barthap](https://github.com/barthap))
|
|
18
|
+
- The picker now resolves media library asset ID. ([#18236](https://github.com/expo/expo/pull/18236), [#18185](https://github.com/expo/expo/pull/18185) by [@barthap](https://github.com/barthap))
|
|
19
|
+
- On iOS, the picker now resolves file name and size and media library asset ID. ([#18179](https://github.com/expo/expo/pull/18179) by [@barthap](https://github.com/barthap))
|
|
20
|
+
- On Android added support for selecting multiple images/videos. ([#18161](https://github.com/expo/expo/pull/18161) by [@bbarthec](https://github.com/bbarthec))
|
|
21
|
+
|
|
22
|
+
### 🐛 Bug fixes
|
|
23
|
+
|
|
24
|
+
- On Android restored support for `allowsEditing` option that was disabled when migrating to `registerForActivityResult` mechanism. ([#17963](https://github.com/expo/expo/pull/17963) by [@bbarthec](https://github.com/bbarthec))
|
|
25
|
+
|
|
13
26
|
## 13.2.1 — 2022-07-11
|
|
14
27
|
|
|
15
28
|
_This version does not introduce any user-facing changes._
|
|
@@ -18,7 +31,7 @@ _This version does not introduce any user-facing changes._
|
|
|
18
31
|
|
|
19
32
|
### 🎉 New features
|
|
20
33
|
|
|
21
|
-
- On iOS 14+ added support for selecting multiple images/videos. ([#18102](https://github.com/expo/expo/pull/18102) by [@barthap](https://github.com/barthap))
|
|
34
|
+
- On iOS 14+ added support for selecting multiple images/videos. ([#18102](https://github.com/expo/expo/pull/18102), [#18138](https://github.com/expo/expo/pull/18138), [#18145](https://github.com/expo/expo/pull/18145) by [@barthap](https://github.com/barthap))
|
|
22
35
|
|
|
23
36
|
### 🐛 Bug fixes
|
|
24
37
|
|
|
@@ -26,7 +39,7 @@ _This version does not introduce any user-facing changes._
|
|
|
26
39
|
|
|
27
40
|
### 💡 Others
|
|
28
41
|
|
|
29
|
-
- On Android migrated to the new `registerForActivityResult` mechanism. ([#17671](https://github.com/expo/expo/pull/17671), ([#17987](https://github.com/expo/expo/pull/17987) by [@bbarthec](https://github.com/bbarthec))
|
|
42
|
+
- On Android migrated to the new `registerForActivityResult` mechanism. This migration disables `allowsEditing` option. ([#17671](https://github.com/expo/expo/pull/17671), ([#17987](https://github.com/expo/expo/pull/17987) by [@bbarthec](https://github.com/bbarthec))
|
|
30
43
|
- Native module on Android is now written in Kotlin using [Sweet API](https://docs.expo.dev/modules/module-api). ([#17668](https://github.com/expo/expo/pull/17668) by [@bbarthec](https://github.com/bbarthec))
|
|
31
44
|
- Migrated Expo modules definitions to the new naming convention. ([#17193](https://github.com/expo/expo/pull/17193) by [@tsapeta](https://github.com/tsapeta))
|
|
32
45
|
|
package/android/build.gradle
CHANGED
|
@@ -3,7 +3,7 @@ apply plugin: 'kotlin-android'
|
|
|
3
3
|
apply plugin: 'maven-publish'
|
|
4
4
|
|
|
5
5
|
group = 'host.exp.exponent'
|
|
6
|
-
version = '13.
|
|
6
|
+
version = '13.3.0'
|
|
7
7
|
|
|
8
8
|
buildscript {
|
|
9
9
|
def expoModulesCorePlugin = new File(project(":expo-modules-core").projectDir.absolutePath, "ExpoModulesCorePlugin.gradle")
|
|
@@ -74,7 +74,7 @@ android {
|
|
|
74
74
|
minSdkVersion safeExtGet("minSdkVersion", 21)
|
|
75
75
|
targetSdkVersion safeExtGet("targetSdkVersion", 31)
|
|
76
76
|
versionCode 22
|
|
77
|
-
versionName "13.
|
|
77
|
+
versionName "13.3.0"
|
|
78
78
|
}
|
|
79
79
|
lintOptions {
|
|
80
80
|
abortOnError false
|
|
@@ -84,9 +84,11 @@ android {
|
|
|
84
84
|
dependencies {
|
|
85
85
|
implementation project(':expo-modules-core')
|
|
86
86
|
|
|
87
|
-
implementation "
|
|
88
|
-
implementation
|
|
89
|
-
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.3")
|
|
90
|
-
implementation "com.github.CanHub:Android-Image-Cropper:1.1.1"
|
|
87
|
+
implementation "androidx.activity:activity-ktx:1.4.0"
|
|
88
|
+
implementation "androidx.appcompat:appcompat:1.4.2"
|
|
91
89
|
implementation "androidx.exifinterface:exifinterface:1.3.3"
|
|
90
|
+
implementation "com.github.CanHub:Android-Image-Cropper:4.3.0"
|
|
91
|
+
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:${getKotlinVersion()}"
|
|
92
|
+
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.3"
|
|
93
|
+
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.3"
|
|
92
94
|
}
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
@file:OptIn(ExperimentalContracts::class)
|
|
2
|
-
|
|
3
1
|
package expo.modules.imagepicker
|
|
4
2
|
|
|
5
3
|
import android.Manifest
|
|
@@ -10,6 +8,8 @@ import expo.modules.core.errors.ModuleNotFoundException
|
|
|
10
8
|
import android.os.OperationCanceledException
|
|
11
9
|
import expo.modules.imagepicker.contracts.CameraContract
|
|
12
10
|
import expo.modules.imagepicker.contracts.CameraContractOptions
|
|
11
|
+
import expo.modules.imagepicker.contracts.CropImageContract
|
|
12
|
+
import expo.modules.imagepicker.contracts.CropImageContractOptions
|
|
13
13
|
import expo.modules.imagepicker.contracts.ImageLibraryContract
|
|
14
14
|
import expo.modules.imagepicker.contracts.ImageLibraryContractOptions
|
|
15
15
|
import expo.modules.imagepicker.contracts.ImagePickerContractResult
|
|
@@ -24,7 +24,6 @@ import kotlinx.coroutines.Dispatchers
|
|
|
24
24
|
import kotlinx.coroutines.launch
|
|
25
25
|
import kotlinx.coroutines.suspendCancellableCoroutine
|
|
26
26
|
import kotlinx.coroutines.withContext
|
|
27
|
-
import kotlin.contracts.ExperimentalContracts
|
|
28
27
|
import kotlin.coroutines.resume
|
|
29
28
|
import kotlin.coroutines.resumeWithException
|
|
30
29
|
|
|
@@ -71,7 +70,7 @@ class ImagePickerModule : Module() {
|
|
|
71
70
|
launchContract({ imageLibraryLauncher.launch(contractOptions) }, options)
|
|
72
71
|
}
|
|
73
72
|
|
|
74
|
-
AsyncFunction("getPendingResultAsync") Coroutine {
|
|
73
|
+
AsyncFunction("getPendingResultAsync") Coroutine { ->
|
|
75
74
|
val (bareResult, options) = pendingMediaPickingResult ?: return@Coroutine null
|
|
76
75
|
|
|
77
76
|
pendingMediaPickingResult = null
|
|
@@ -90,6 +89,9 @@ class ImagePickerModule : Module() {
|
|
|
90
89
|
imageLibraryLauncher = appContext.registerForActivityResult(
|
|
91
90
|
ImageLibraryContract(this@ImagePickerModule),
|
|
92
91
|
) { input, result -> handleResultUponActivityDestruction(result, input.options) }
|
|
92
|
+
cropImageLauncher = appContext.registerForActivityResult(
|
|
93
|
+
CropImageContract(this@ImagePickerModule),
|
|
94
|
+
) { input, result -> handleResultUponActivityDestruction(result, input.options) }
|
|
93
95
|
}
|
|
94
96
|
}
|
|
95
97
|
}
|
|
@@ -106,6 +108,7 @@ class ImagePickerModule : Module() {
|
|
|
106
108
|
|
|
107
109
|
private lateinit var cameraLauncher: AppContextActivityResultLauncher<CameraContractOptions, ImagePickerContractResult>
|
|
108
110
|
private lateinit var imageLibraryLauncher: AppContextActivityResultLauncher<ImageLibraryContractOptions, ImagePickerContractResult>
|
|
111
|
+
private lateinit var cropImageLauncher: AppContextActivityResultLauncher<CropImageContractOptions, ImagePickerContractResult>
|
|
109
112
|
|
|
110
113
|
/**
|
|
111
114
|
* Stores result for an operation that has been interrupted by the activity destruction.
|
|
@@ -123,8 +126,18 @@ class ImagePickerModule : Module() {
|
|
|
123
126
|
options: ImagePickerOptions,
|
|
124
127
|
): Any {
|
|
125
128
|
return try {
|
|
126
|
-
|
|
127
|
-
|
|
129
|
+
var result = launchPicker(pickerLauncher)
|
|
130
|
+
if (
|
|
131
|
+
!options.allowsMultipleSelection &&
|
|
132
|
+
options.allowsEditing &&
|
|
133
|
+
result.data.size == 1 &&
|
|
134
|
+
result.data[0].first == MediaType.IMAGE
|
|
135
|
+
) {
|
|
136
|
+
result = launchPicker {
|
|
137
|
+
cropImageLauncher.launch(CropImageContractOptions(result.data[0].second, options))
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
mediaHandler.readExtras(result.data, options)
|
|
128
141
|
} catch (cause: OperationCanceledException) {
|
|
129
142
|
ImagePickerCancelledResponse()
|
|
130
143
|
}
|
|
@@ -145,9 +158,9 @@ class ImagePickerModule : Module() {
|
|
|
145
158
|
*/
|
|
146
159
|
private suspend fun launchPicker(
|
|
147
160
|
pickerLauncher: suspend () -> ImagePickerContractResult,
|
|
148
|
-
):
|
|
161
|
+
): ImagePickerContractResult.Success = withContext(Dispatchers.Main) {
|
|
149
162
|
when (val pickingResult = pickerLauncher()) {
|
|
150
|
-
is ImagePickerContractResult.Success -> pickingResult
|
|
163
|
+
is ImagePickerContractResult.Success -> pickingResult
|
|
151
164
|
is ImagePickerContractResult.Cancelled -> throw OperationCanceledException()
|
|
152
165
|
}
|
|
153
166
|
}
|
|
@@ -191,15 +204,10 @@ class ImagePickerModule : Module() {
|
|
|
191
204
|
// endregion
|
|
192
205
|
}
|
|
193
206
|
|
|
194
|
-
internal enum class PickingSource {
|
|
195
|
-
CAMERA,
|
|
196
|
-
IMAGE_LIBRARY
|
|
197
|
-
}
|
|
198
|
-
|
|
199
207
|
/**
|
|
200
208
|
* Simple data structure to hold the data that has to be preserved after the Activity is destroyed.
|
|
201
209
|
*/
|
|
202
210
|
internal data class PendingMediaPickingResult(
|
|
203
|
-
val data: Pair<MediaType, Uri
|
|
211
|
+
val data: List<Pair<MediaType, Uri>>,
|
|
204
212
|
val options: ImagePickerOptions
|
|
205
213
|
)
|
|
@@ -9,32 +9,42 @@ internal class ImagePickerCancelledResponse : Record {
|
|
|
9
9
|
val cancelled: Boolean = true
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
-
internal sealed class
|
|
13
|
-
@Field val type: MediaType,
|
|
14
|
-
@Field val uri: String,
|
|
15
|
-
@Field val width: Int,
|
|
16
|
-
@Field val height: Int,
|
|
17
|
-
) : Record {
|
|
12
|
+
internal sealed class ImagePickerResponse : Record {
|
|
18
13
|
@Field
|
|
19
14
|
val cancelled: Boolean = false
|
|
20
15
|
|
|
21
|
-
class
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
@Field val
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
16
|
+
sealed class Single(
|
|
17
|
+
@Field val type: MediaType,
|
|
18
|
+
@Field val uri: String,
|
|
19
|
+
@Field val width: Int,
|
|
20
|
+
@Field val height: Int,
|
|
21
|
+
@Field val assetId: String?,
|
|
22
|
+
) : ImagePickerResponse() {
|
|
23
|
+
class Image(
|
|
24
|
+
uri: String,
|
|
25
|
+
width: Int,
|
|
26
|
+
height: Int,
|
|
27
|
+
assetId: String?,
|
|
28
|
+
|
|
29
|
+
@Field val base64: String?,
|
|
30
|
+
@Field val exif: Bundle?
|
|
31
|
+
) : Single(MediaType.IMAGE, uri, width, height, assetId)
|
|
32
|
+
|
|
33
|
+
class Video(
|
|
34
|
+
uri: String,
|
|
35
|
+
width: Int,
|
|
36
|
+
height: Int,
|
|
37
|
+
assetId: String?,
|
|
38
|
+
|
|
39
|
+
@Field val duration: Int,
|
|
40
|
+
@Field val rotation: Int
|
|
41
|
+
) : Single(MediaType.VIDEO, uri, width, height, assetId)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
class Multiple(
|
|
45
|
+
@Field
|
|
46
|
+
val selected: List<Single>
|
|
47
|
+
) : ImagePickerResponse()
|
|
38
48
|
}
|
|
39
49
|
|
|
40
50
|
enum class MediaType(val value: String) {
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
package expo.modules.imagepicker
|
|
2
2
|
|
|
3
|
+
import android.content.ClipData
|
|
3
4
|
import android.content.ContentResolver
|
|
4
5
|
import android.content.Context
|
|
6
|
+
import android.content.Intent
|
|
5
7
|
import android.graphics.Bitmap
|
|
6
8
|
import android.media.MediaMetadataRetriever
|
|
7
9
|
import android.net.Uri
|
|
10
|
+
import android.provider.DocumentsContract
|
|
8
11
|
import android.util.Log
|
|
9
12
|
import android.webkit.MimeTypeMap
|
|
10
13
|
import androidx.core.content.FileProvider
|
|
@@ -100,6 +103,42 @@ internal fun MediaMetadataRetriever.extractInt(key: Int): Int {
|
|
|
100
103
|
return this.extractMetadata(key)?.toInt() ?: throw FailedToExtractVideoMetadataException()
|
|
101
104
|
}
|
|
102
105
|
|
|
106
|
+
/**
|
|
107
|
+
* [Iterable] implementation for [ClipData] items
|
|
108
|
+
*/
|
|
109
|
+
val ClipData.items: Iterable<ClipData.Item>
|
|
110
|
+
get() = object : Iterable<ClipData.Item> {
|
|
111
|
+
override fun iterator() = object : Iterator<ClipData.Item> {
|
|
112
|
+
var index = 0
|
|
113
|
+
val count = itemCount
|
|
114
|
+
|
|
115
|
+
override fun hasNext(): Boolean = index < count
|
|
116
|
+
|
|
117
|
+
override fun next(): ClipData.Item = getItemAt(index++)
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Gets all data that is associated with this [Intent].
|
|
123
|
+
* Original data order is preserved.
|
|
124
|
+
*
|
|
125
|
+
* Adapted from [androidx.activity.result.contract.ActivityResultContracts.GetMultipleContents.getClipDataUris]
|
|
126
|
+
*/
|
|
127
|
+
internal fun Intent.getAllDataUris(): List<Uri> {
|
|
128
|
+
// Use a LinkedHashSet to maintain any ordering that may be present in the ClipData
|
|
129
|
+
val resultSet = LinkedHashSet<Uri>()
|
|
130
|
+
|
|
131
|
+
data
|
|
132
|
+
?.let { resultSet.add(it) }
|
|
133
|
+
|
|
134
|
+
clipData
|
|
135
|
+
?.items
|
|
136
|
+
?.map { it.uri }
|
|
137
|
+
?.let { resultSet.addAll(it) }
|
|
138
|
+
|
|
139
|
+
return resultSet.toList()
|
|
140
|
+
}
|
|
141
|
+
|
|
103
142
|
/**
|
|
104
143
|
* Copy the media file from `sourceUri` to `destinationUri`.
|
|
105
144
|
*
|
|
@@ -168,3 +207,72 @@ internal suspend fun copyExifData(
|
|
|
168
207
|
throw FailedToWriteFileException(targetFile, cause)
|
|
169
208
|
}
|
|
170
209
|
}
|
|
210
|
+
|
|
211
|
+
/*
|
|
212
|
+
Getting asset ID (and metadata) on Android is not that obvious. When getting a `content://` URI
|
|
213
|
+
using `ACTION_GET_CONTENT` or `ACTION_OPEN_DOCUMENT` intents, there are 3 possible ways:
|
|
214
|
+
|
|
215
|
+
1. When the user selects a photo from **Images** section of the picker (on the left drawer)
|
|
216
|
+
In this case we get a URI from `com.android.providers.media.MediaDocumentsProvider`,
|
|
217
|
+
that inherits from `DocumentsProvider`. The URI looks like this:
|
|
218
|
+
```
|
|
219
|
+
com.android.providers.media.documents/document/image:56
|
|
220
|
+
```
|
|
221
|
+
In this case, the `56` is the ID we're looking for.
|
|
222
|
+
|
|
223
|
+
2. When the user selects a photo from **Downloads** section, another content provider is used:
|
|
224
|
+
`DownloadStorageProvider` which is a bit different, and also differs depending on Android version:
|
|
225
|
+
- On API 29+ it also inherits from `com.android.providers.downloads.DocumentsProvider`
|
|
226
|
+
and the URI looks like this:
|
|
227
|
+
```
|
|
228
|
+
com.android.providers.downloads.documents/document/msf:56
|
|
229
|
+
```
|
|
230
|
+
Where "msf" is abbr. of "media store file" and 56 is our asset ID
|
|
231
|
+
- On API <29 it looks similar:
|
|
232
|
+
```
|
|
233
|
+
com.android.providers.downloads.documents/document/128
|
|
234
|
+
```
|
|
235
|
+
but the 128 is an internal ID of downloads provider, unrelated to media store asset ID.
|
|
236
|
+
|
|
237
|
+
3. When the user selects a photo by browsing the filesystem, the URI looks like this:
|
|
238
|
+
```
|
|
239
|
+
com.android.externalstorage.documents/document/primary:Download:filename.jpg
|
|
240
|
+
```
|
|
241
|
+
No ID in this case
|
|
242
|
+
*/
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* Checks whether this [Uri] is a `com.android.providers.media.documents` provider uri
|
|
246
|
+
*/
|
|
247
|
+
internal val Uri.isMediaProviderUri
|
|
248
|
+
get() = this.authority == "com.android.providers.media.documents"
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* Checks whether this [Uri] is a `com.android.providers.downloads.documents` provider uri
|
|
252
|
+
*/
|
|
253
|
+
internal val Uri.isDownloadsProviderUri
|
|
254
|
+
get() = this.authority == "com.android.providers.downloads.documents"
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* Checks whether asset represented by this [Uri] can be queried in the media store
|
|
258
|
+
*/
|
|
259
|
+
internal val Uri.isMediaStoreAssetUri
|
|
260
|
+
get() = isMediaProviderUri || (
|
|
261
|
+
isDownloadsProviderUri &&
|
|
262
|
+
DocumentsContract
|
|
263
|
+
.getDocumentId(this)
|
|
264
|
+
.startsWith("msf:")
|
|
265
|
+
)
|
|
266
|
+
|
|
267
|
+
/**
|
|
268
|
+
* If the URI represents a media store asset, this returns its ID. Otherwise, returns `null`.
|
|
269
|
+
*
|
|
270
|
+
* See the detailed explanation above in this file (ImagePickerUtils.kt).
|
|
271
|
+
*/
|
|
272
|
+
internal fun Uri.getMediaStoreAssetId(): String? {
|
|
273
|
+
if (isMediaStoreAssetUri) {
|
|
274
|
+
val rawId = DocumentsContract.getDocumentId(this)
|
|
275
|
+
return if (rawId.contains(':')) rawId.split(':')[1] else rawId
|
|
276
|
+
}
|
|
277
|
+
return null
|
|
278
|
+
}
|
|
@@ -17,17 +17,27 @@ internal class MediaHandler(
|
|
|
17
17
|
get() = requireNotNull(appContextProvider.appContext.reactContext) { "React Application Context is null" }
|
|
18
18
|
|
|
19
19
|
internal suspend fun readExtras(
|
|
20
|
-
bareResult: Pair<MediaType, Uri
|
|
20
|
+
bareResult: List<Pair<MediaType, Uri>>,
|
|
21
21
|
options: ImagePickerOptions,
|
|
22
|
-
):
|
|
23
|
-
|
|
24
|
-
|
|
22
|
+
): ImagePickerResponse {
|
|
23
|
+
val results = bareResult.map { (mediaType, uri) ->
|
|
24
|
+
when (mediaType) {
|
|
25
|
+
MediaType.VIDEO -> handleVideo(uri)
|
|
26
|
+
MediaType.IMAGE -> handleImage(uri, options)
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return if (results.size == 1) {
|
|
31
|
+
results[0]
|
|
32
|
+
} else {
|
|
33
|
+
ImagePickerResponse.Multiple(results)
|
|
34
|
+
}
|
|
25
35
|
}
|
|
26
36
|
|
|
27
37
|
private suspend fun handleImage(
|
|
28
38
|
sourceUri: Uri,
|
|
29
39
|
options: ImagePickerOptions,
|
|
30
|
-
):
|
|
40
|
+
): ImagePickerResponse.Single.Image {
|
|
31
41
|
val exporter: ImageExporter = if (options.quality == ImagePickerConstants.MAXIMUM_QUALITY) {
|
|
32
42
|
RawImageExporter()
|
|
33
43
|
} else {
|
|
@@ -43,18 +53,19 @@ internal class MediaHandler(
|
|
|
43
53
|
val exif = options.exif.takeIf { it }
|
|
44
54
|
?.let { exportedImage.exif(context.contentResolver) }
|
|
45
55
|
|
|
46
|
-
return
|
|
56
|
+
return ImagePickerResponse.Single.Image(
|
|
47
57
|
uri = Uri.fromFile(outputFile).toString(),
|
|
48
58
|
width = exportedImage.width,
|
|
49
59
|
height = exportedImage.height,
|
|
50
60
|
base64 = base64,
|
|
51
61
|
exif = exif,
|
|
62
|
+
assetId = sourceUri.getMediaStoreAssetId()
|
|
52
63
|
)
|
|
53
64
|
}
|
|
54
65
|
|
|
55
66
|
private suspend fun handleVideo(
|
|
56
67
|
sourceUri: Uri,
|
|
57
|
-
):
|
|
68
|
+
): ImagePickerResponse.Single.Video {
|
|
58
69
|
val outputFile = createOutputFile(context.cacheDir, ".mp4")
|
|
59
70
|
copyFile(sourceUri, outputFile, context.contentResolver)
|
|
60
71
|
val outputUri = outputFile.toUri()
|
|
@@ -64,12 +75,13 @@ internal class MediaHandler(
|
|
|
64
75
|
setDataSource(context, outputUri)
|
|
65
76
|
}
|
|
66
77
|
|
|
67
|
-
|
|
78
|
+
ImagePickerResponse.Single.Video(
|
|
68
79
|
uri = outputUri.toString(),
|
|
69
80
|
width = metadataRetriever.extractInt(MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH),
|
|
70
81
|
height = metadataRetriever.extractInt(MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT),
|
|
71
82
|
duration = metadataRetriever.extractInt(MediaMetadataRetriever.METADATA_KEY_DURATION),
|
|
72
83
|
rotation = metadataRetriever.extractInt(MediaMetadataRetriever.METADATA_KEY_VIDEO_ROTATION),
|
|
84
|
+
assetId = sourceUri.getMediaStoreAssetId()
|
|
73
85
|
)
|
|
74
86
|
} catch (cause: FailedToExtractVideoMetadataException) {
|
|
75
87
|
throw FailedToExtractVideoMetadataException(outputFile, cause)
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
package expo.modules.imagepicker.contracts
|
|
2
2
|
|
|
3
3
|
import android.app.Activity
|
|
4
|
+
import android.content.ContentResolver
|
|
4
5
|
import android.content.Context
|
|
5
6
|
import android.content.Intent
|
|
6
7
|
import android.net.Uri
|
|
@@ -21,6 +22,11 @@ import java.io.Serializable
|
|
|
21
22
|
internal class CameraContract(
|
|
22
23
|
private val appContextProvider: AppContextProvider,
|
|
23
24
|
) : AppContextActivityResultContract<CameraContractOptions, ImagePickerContractResult> {
|
|
25
|
+
val contentResolver: ContentResolver
|
|
26
|
+
get() = requireNotNull(appContextProvider.appContext.reactContext) {
|
|
27
|
+
"React Application Context is null"
|
|
28
|
+
}.contentResolver
|
|
29
|
+
|
|
24
30
|
override fun createIntent(context: Context, input: CameraContractOptions): Intent =
|
|
25
31
|
Intent(input.options.mediaTypes.toCameraIntentAction())
|
|
26
32
|
.putExtra(MediaStore.EXTRA_OUTPUT, input.uri)
|
|
@@ -34,14 +40,16 @@ internal class CameraContract(
|
|
|
34
40
|
if (resultCode == Activity.RESULT_CANCELED) {
|
|
35
41
|
ImagePickerContractResult.Cancelled()
|
|
36
42
|
} else {
|
|
37
|
-
val contentResolver = requireNotNull(appContextProvider.appContext.reactContext) { "React Application Context is null. " }.contentResolver
|
|
38
43
|
val uri = input.uri
|
|
39
44
|
val type = uri.toMediaType(contentResolver)
|
|
40
|
-
ImagePickerContractResult.Success(type to uri)
|
|
45
|
+
ImagePickerContractResult.Success(listOf(type to uri))
|
|
41
46
|
}
|
|
42
47
|
}
|
|
43
48
|
|
|
44
49
|
internal data class CameraContractOptions(
|
|
50
|
+
/**
|
|
51
|
+
* Destination file in a form of content-[Uri] to save results coming from camera to.
|
|
52
|
+
*/
|
|
45
53
|
val uri: Uri,
|
|
46
54
|
val options: ImagePickerOptions,
|
|
47
55
|
) : Serializable
|
|
@@ -1,18 +1,12 @@
|
|
|
1
1
|
package expo.modules.imagepicker.contracts
|
|
2
2
|
|
|
3
3
|
import android.net.Uri
|
|
4
|
-
import androidx.activity.result.contract.ActivityResultContract
|
|
5
4
|
import expo.modules.imagepicker.MediaType
|
|
6
5
|
|
|
7
|
-
/**
|
|
8
|
-
* Alias for [androidx.activity.result.contract.ActivityResultContract] with required generic types already specified
|
|
9
|
-
*/
|
|
10
|
-
internal typealias ImagePickerContract = ActivityResultContract<Any?, ImagePickerContractResult>
|
|
11
|
-
|
|
12
6
|
/**
|
|
13
7
|
* Data required to be returned upon successful contract completion
|
|
14
8
|
*/
|
|
15
9
|
internal sealed class ImagePickerContractResult private constructor() {
|
|
16
10
|
class Cancelled : ImagePickerContractResult()
|
|
17
|
-
class Success(val data: Pair<MediaType, Uri
|
|
11
|
+
class Success(val data: List<Pair<MediaType, Uri>>) : ImagePickerContractResult()
|
|
18
12
|
}
|
|
@@ -12,44 +12,34 @@ import com.canhub.cropper.CropImageActivity
|
|
|
12
12
|
import com.canhub.cropper.CropImageOptions
|
|
13
13
|
import expo.modules.imagepicker.ImagePickerOptions
|
|
14
14
|
import expo.modules.imagepicker.MediaType
|
|
15
|
-
import expo.modules.imagepicker.PickingSource
|
|
16
15
|
import expo.modules.imagepicker.copyExifData
|
|
17
16
|
import expo.modules.imagepicker.createOutputFile
|
|
18
17
|
import expo.modules.imagepicker.toBitmapCompressFormat
|
|
19
18
|
import expo.modules.imagepicker.toImageFileExtension
|
|
19
|
+
import expo.modules.kotlin.activityresult.AppContextActivityResultContract
|
|
20
20
|
import expo.modules.kotlin.providers.AppContextProvider
|
|
21
21
|
import kotlinx.coroutines.runBlocking
|
|
22
|
+
import java.io.Serializable
|
|
22
23
|
|
|
23
24
|
internal class CropImageContract(
|
|
24
25
|
private val appContextProvider: AppContextProvider,
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
) : ImagePickerContract() {
|
|
29
|
-
override fun createIntent(context: Context, input: Any?) = Intent(context, CropImageActivity::class.java).apply {
|
|
30
|
-
// for [IMAGE_LIBRARY] we need to create a new file as up to this point we've been operating on the original media asset
|
|
31
|
-
// for [CAMERA] we do not have to do it as it's already been created at the beginning of the picking process
|
|
32
|
-
val needCreateNewFile = pickingSource == PickingSource.IMAGE_LIBRARY
|
|
33
|
-
val mediaType = expo.modules.imagepicker.getType(context.contentResolver, sourceUri)
|
|
34
|
-
|
|
26
|
+
) : AppContextActivityResultContract<CropImageContractOptions, ImagePickerContractResult> {
|
|
27
|
+
override fun createIntent(context: Context, input: CropImageContractOptions) = Intent(context, CropImageActivity::class.java).apply {
|
|
28
|
+
val mediaType = expo.modules.imagepicker.getType(context.contentResolver, input.sourceUri)
|
|
35
29
|
val compressFormat = mediaType.toBitmapCompressFormat()
|
|
36
|
-
|
|
37
|
-
val outputUri: Uri = if (needCreateNewFile) {
|
|
38
|
-
createOutputFile(context.cacheDir, compressFormat.toImageFileExtension()).toUri()
|
|
39
|
-
} else {
|
|
40
|
-
sourceUri
|
|
41
|
-
}
|
|
30
|
+
val outputUri = createOutputFile(context.cacheDir, compressFormat.toImageFileExtension()).toUri()
|
|
42
31
|
|
|
43
32
|
putExtra(
|
|
44
33
|
CropImage.CROP_IMAGE_EXTRA_BUNDLE,
|
|
45
34
|
bundleOf(
|
|
46
|
-
CropImage.CROP_IMAGE_EXTRA_SOURCE to sourceUri,
|
|
35
|
+
CropImage.CROP_IMAGE_EXTRA_SOURCE to input.sourceUri,
|
|
47
36
|
CropImage.CROP_IMAGE_EXTRA_OPTIONS to CropImageOptions().apply {
|
|
48
37
|
outputCompressFormat = compressFormat
|
|
49
|
-
outputCompressQuality = (
|
|
50
|
-
this.outputUri = outputUri
|
|
38
|
+
outputCompressQuality = (input.options.quality * 100).toInt()
|
|
51
39
|
|
|
52
|
-
this
|
|
40
|
+
this.customOutputUri = outputUri
|
|
41
|
+
|
|
42
|
+
input.options.aspect?.let { (x, y) ->
|
|
53
43
|
aspectRatioX = x
|
|
54
44
|
aspectRatioY = y
|
|
55
45
|
fixAspectRatio = true
|
|
@@ -62,14 +52,19 @@ internal class CropImageContract(
|
|
|
62
52
|
)
|
|
63
53
|
}
|
|
64
54
|
|
|
65
|
-
override fun parseResult(resultCode: Int, intent: Intent?): ImagePickerContractResult {
|
|
55
|
+
override fun parseResult(input: CropImageContractOptions, resultCode: Int, intent: Intent?): ImagePickerContractResult {
|
|
66
56
|
val result = intent?.getParcelableExtra<CropImage.ActivityResult?>(CropImage.CROP_IMAGE_EXTRA_RESULT)
|
|
67
57
|
if (resultCode == Activity.RESULT_CANCELED || result == null) {
|
|
68
58
|
return ImagePickerContractResult.Cancelled()
|
|
69
59
|
}
|
|
70
|
-
val targetUri = requireNotNull(result.
|
|
60
|
+
val targetUri = requireNotNull(result.uriContent)
|
|
71
61
|
val contentResolver = requireNotNull(appContextProvider.appContext.reactContext) { "React Application Context is null" }.contentResolver
|
|
72
|
-
runBlocking { copyExifData(sourceUri, targetUri.toFile(), contentResolver) }
|
|
73
|
-
return ImagePickerContractResult.Success(MediaType.IMAGE to targetUri)
|
|
62
|
+
runBlocking { copyExifData(input.sourceUri, targetUri.toFile(), contentResolver) }
|
|
63
|
+
return ImagePickerContractResult.Success(listOf(MediaType.IMAGE to targetUri))
|
|
74
64
|
}
|
|
75
65
|
}
|
|
66
|
+
|
|
67
|
+
internal data class CropImageContractOptions(
|
|
68
|
+
val sourceUri: Uri,
|
|
69
|
+
val options: ImagePickerOptions,
|
|
70
|
+
) : Serializable
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
package expo.modules.imagepicker.contracts
|
|
2
2
|
|
|
3
3
|
import android.app.Activity
|
|
4
|
+
import android.content.ContentResolver
|
|
4
5
|
import android.content.Context
|
|
5
6
|
import android.content.Intent
|
|
6
7
|
import android.net.Uri
|
|
7
8
|
import expo.modules.imagepicker.ImagePickerOptions
|
|
9
|
+
import expo.modules.imagepicker.getAllDataUris
|
|
8
10
|
import expo.modules.imagepicker.toMediaType
|
|
9
11
|
import expo.modules.kotlin.activityresult.AppContextActivityResultContract
|
|
10
12
|
import expo.modules.kotlin.providers.AppContextProvider
|
|
@@ -14,25 +16,37 @@ import java.io.Serializable
|
|
|
14
16
|
* An [androidx.activity.result.contract.ActivityResultContract] to prompt the user to pick single or multiple image(s) or/and video(s),
|
|
15
17
|
* receiving a `content://` [Uri] for each piece of content.
|
|
16
18
|
*
|
|
17
|
-
* @see [androidx.activity.result.contract.ActivityResultContracts.GetContent]
|
|
19
|
+
* @see [androidx.activity.result.contract.ActivityResultContracts.GetContent],
|
|
20
|
+
* @see [androidx.activity.result.contract.ActivityResultContracts.GetMultipleContents]
|
|
18
21
|
*/
|
|
19
22
|
internal class ImageLibraryContract(
|
|
20
23
|
private val appContextProvider: AppContextProvider,
|
|
21
24
|
) : AppContextActivityResultContract<ImageLibraryContractOptions, ImagePickerContractResult> {
|
|
25
|
+
val contentResolver: ContentResolver
|
|
26
|
+
get() = requireNotNull(appContextProvider.appContext.reactContext) {
|
|
27
|
+
"React Application Context is null"
|
|
28
|
+
}.contentResolver
|
|
29
|
+
|
|
22
30
|
override fun createIntent(context: Context, input: ImageLibraryContractOptions) =
|
|
23
31
|
Intent(Intent.ACTION_GET_CONTENT)
|
|
24
32
|
.addCategory(Intent.CATEGORY_OPENABLE)
|
|
25
33
|
.setType(input.options.mediaTypes.toMimeType())
|
|
34
|
+
.apply {
|
|
35
|
+
if (input.options.allowsMultipleSelection) {
|
|
36
|
+
putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true)
|
|
37
|
+
}
|
|
38
|
+
}
|
|
26
39
|
|
|
27
40
|
override fun parseResult(input: ImageLibraryContractOptions, resultCode: Int, intent: Intent?) =
|
|
28
41
|
if (resultCode == Activity.RESULT_CANCELED) {
|
|
29
42
|
ImagePickerContractResult.Cancelled()
|
|
43
|
+
} else if (input.options.allowsMultipleSelection) {
|
|
44
|
+
val uris = requireNotNull(intent).getAllDataUris()
|
|
45
|
+
ImagePickerContractResult.Success(uris.map { uri -> uri.toMediaType(contentResolver) to uri })
|
|
30
46
|
} else {
|
|
31
47
|
val uri = requireNotNull(requireNotNull(intent).data)
|
|
32
|
-
val contentResolver = requireNotNull(appContextProvider.appContext.reactContext) { "React Application Context is null. " }.contentResolver
|
|
33
48
|
val type = uri.toMediaType(contentResolver)
|
|
34
|
-
|
|
35
|
-
ImagePickerContractResult.Success(type to uri)
|
|
49
|
+
ImagePickerContractResult.Success(listOf(type to uri))
|
|
36
50
|
}
|
|
37
51
|
}
|
|
38
52
|
|
package/build/ImagePicker.d.ts
CHANGED
|
@@ -68,7 +68,7 @@ export declare function getPendingResultAsync(): Promise<(ImagePickerResult | Im
|
|
|
68
68
|
/**
|
|
69
69
|
* Display the system UI for taking a photo with the camera. Requires `Permissions.CAMERA`.
|
|
70
70
|
* On Android and iOS 10 `Permissions.CAMERA_ROLL` is also required. On mobile web, this must be
|
|
71
|
-
* called immediately in a user interaction like a button press, otherwise the browser will
|
|
71
|
+
* called immediately in a user interaction like a button press, otherwise the browser will block
|
|
72
72
|
* the request without a warning.
|
|
73
73
|
* > **Note:** Make sure that you handle `MainActivity` destruction on **Android**. See [ImagePicker.getPendingResultAsync](#imagepickergetpendingresultasync).
|
|
74
74
|
* > **Notes for Web:** The system UI can only be shown after user activation (e.g. a `Button` press).
|
package/build/ImagePicker.js
CHANGED
|
@@ -118,7 +118,7 @@ export async function getPendingResultAsync() {
|
|
|
118
118
|
/**
|
|
119
119
|
* Display the system UI for taking a photo with the camera. Requires `Permissions.CAMERA`.
|
|
120
120
|
* On Android and iOS 10 `Permissions.CAMERA_ROLL` is also required. On mobile web, this must be
|
|
121
|
-
* called immediately in a user interaction like a button press, otherwise the browser will
|
|
121
|
+
* called immediately in a user interaction like a button press, otherwise the browser will block
|
|
122
122
|
* the request without a warning.
|
|
123
123
|
* > **Note:** Make sure that you handle `MainActivity` destruction on **Android**. See [ImagePicker.getPendingResultAsync](#imagepickergetpendingresultasync).
|
|
124
124
|
* > **Notes for Web:** The system UI can only be shown after user activation (e.g. a `Button` press).
|
package/build/ImagePicker.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ImagePicker.js","sourceRoot":"","sources":["../src/ImagePicker.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n PermissionStatus,\n PermissionExpiration,\n PermissionHookOptions,\n PermissionResponse,\n createPermissionHook,\n UnavailabilityError,\n CodedError,\n} from 'expo-modules-core';\n\nimport ExponentImagePicker from './ExponentImagePicker';\nimport {\n CameraPermissionResponse,\n CameraRollPermissionResponse,\n MediaLibraryPermissionResponse,\n ImagePickerResult,\n ImagePickerErrorResult,\n MediaTypeOptions,\n ImagePickerOptions,\n VideoExportPreset,\n ExpandImagePickerResult,\n ImageInfo,\n ImagePickerMultipleResult,\n ImagePickerCancelledResult,\n OpenFileBrowserOptions,\n UIImagePickerControllerQualityType,\n UIImagePickerPresentationStyle,\n} from './ImagePicker.types';\n\nfunction validateOptions(options: ImagePickerOptions) {\n const { aspect, quality, videoMaxDuration } = options;\n\n if (aspect != null) {\n const [x, y] = aspect;\n\n if (x <= 0 || y <= 0) {\n throw new CodedError(\n 'ERR_INVALID_ARGUMENT',\n `Invalid aspect ratio values ${x}:${y}. Provide positive numbers.`\n );\n }\n }\n\n if (quality && (quality < 0 || quality > 1)) {\n throw new CodedError(\n 'ERR_INVALID_ARGUMENT',\n `Invalid 'quality' value ${quality}. Provide a value between 0 and 1.`\n );\n }\n\n if (videoMaxDuration && videoMaxDuration < 0) {\n throw new CodedError(\n 'ERR_INVALID_ARGUMENT',\n `Invalid 'videoMaxDuration' value ${videoMaxDuration}. Provide a non-negative number.`\n );\n }\n\n return options;\n}\n\n// @needsAudit\n/**\n * Checks user's permissions for accessing camera.\n * @return A promise that fulfills with an object of type [CameraPermissionResponse](#camerarollpermissionresponse).\n */\nexport async function getCameraPermissionsAsync(): Promise<CameraPermissionResponse> {\n return ExponentImagePicker.getCameraPermissionsAsync();\n}\n\n/**\n * @deprecated Use `getMediaLibraryPermissionsAsync()` instead.\n */\nexport async function getCameraRollPermissionsAsync(): Promise<MediaLibraryPermissionResponse> {\n console.warn(\n 'ImagePicker.getCameraRollPermissionsAsync() is deprecated in favour of ImagePicker.getMediaLibraryPermissionsAsync()'\n );\n return getMediaLibraryPermissionsAsync();\n}\n\n// @needsAudit\n/**\n * Checks user's permissions for accessing photos.\n * @param writeOnly Whether to request write or read and write permissions. Defaults to `false`\n * @return A promise that fulfills with an object of type [MediaLibraryPermissionResponse](#medialibrarypermissionresponse).\n */\nexport async function getMediaLibraryPermissionsAsync(\n writeOnly: boolean = false\n): Promise<MediaLibraryPermissionResponse> {\n return ExponentImagePicker.getMediaLibraryPermissionsAsync(writeOnly);\n}\n\n// @needsAudit\n/**\n * Asks the user to grant permissions for accessing camera. This does nothing on web because the\n * browser camera is not used.\n * @return A promise that fulfills with an object of type [CameraPermissionResponse](#camerarollpermissionresponse).\n */\nexport async function requestCameraPermissionsAsync(): Promise<CameraPermissionResponse> {\n return ExponentImagePicker.requestCameraPermissionsAsync();\n}\n\n/**\n * @deprecated Use `requestMediaLibraryPermissionsAsync()` instead.\n */\nexport async function requestCameraRollPermissionsAsync(): Promise<MediaLibraryPermissionResponse> {\n console.warn(\n 'ImagePicker.requestCameraRollPermissionsAsync() is deprecated in favour of ImagePicker.requestMediaLibraryPermissionsAsync()'\n );\n return requestMediaLibraryPermissionsAsync();\n}\n\n// @needsAudit\n/**\n * Asks the user to grant permissions for accessing user's photo. This method does nothing on web.\n * @param writeOnly Whether to request write or read and write permissions. Defaults to `false`\n * @return A promise that fulfills with an object of type [MediaLibraryPermissionResponse](#medialibrarypermissionresponse).\n */\nexport async function requestMediaLibraryPermissionsAsync(\n writeOnly: boolean = false\n): Promise<MediaLibraryPermissionResponse> {\n const imagePickerMethod = ExponentImagePicker.requestMediaLibraryPermissionsAsync;\n return imagePickerMethod(writeOnly);\n}\n\n// @needsAudit\n/**\n * Check or request permissions to access the media library.\n * This uses both `requestMediaLibraryPermissionsAsync` and `getMediaLibraryPermissionsAsync` to interact with the permissions.\n *\n * @example\n * ```ts\n * const [status, requestPermission] = ImagePicker.useMediaLibraryPermissions();\n * ```\n */\nexport const useMediaLibraryPermissions = createPermissionHook<\n MediaLibraryPermissionResponse,\n { writeOnly?: boolean }\n>({\n // TODO(cedric): permission requesters should have an options param or a different requester\n getMethod: (options) => getMediaLibraryPermissionsAsync(options?.writeOnly),\n requestMethod: (options) => requestMediaLibraryPermissionsAsync(options?.writeOnly),\n});\n\n// @needsAudit\n/**\n * Check or request permissions to access the camera.\n * This uses both `requestCameraPermissionsAsync` and `getCameraPermissionsAsync` to interact with the permissions.\n *\n * @example\n * ```ts\n * const [status, requestPermission] = ImagePicker.useCameraPermissions();\n * ```\n */\nexport const useCameraPermissions = createPermissionHook({\n getMethod: getCameraPermissionsAsync,\n requestMethod: requestCameraPermissionsAsync,\n});\n\n// @needsAudit\n/**\n * Android system sometimes kills the `MainActivity` after the `ImagePicker` finishes. When this\n * happens, we lost the data selected from the `ImagePicker`. However, you can retrieve the lost\n * data by calling `getPendingResultAsync`. You can test this functionality by turning on\n * `Don't keep activities` in the developer options.\n * @return\n * - **On Android:** a promise that resolves to an array of objects of exactly same type as in\n * `ImagePicker.launchImageLibraryAsync` or `ImagePicker.launchCameraAsync` if the `ImagePicker`\n * finished successfully. Otherwise, to the array of [`ImagePickerErrorResult`](#imagepickerimagepickererrorresult).\n * - **On other platforms:** an empty array.\n */\nexport async function getPendingResultAsync(): Promise<\n (ImagePickerResult | ImagePickerErrorResult)[]\n> {\n if (ExponentImagePicker.getPendingResultAsync) {\n return ExponentImagePicker.getPendingResultAsync();\n }\n return [];\n}\n\n// @needsAudit\n/**\n * Display the system UI for taking a photo with the camera. Requires `Permissions.CAMERA`.\n * On Android and iOS 10 `Permissions.CAMERA_ROLL` is also required. On mobile web, this must be\n * called immediately in a user interaction like a button press, otherwise the browser will bloc\n * the request without a warning.\n * > **Note:** Make sure that you handle `MainActivity` destruction on **Android**. See [ImagePicker.getPendingResultAsync](#imagepickergetpendingresultasync).\n * > **Notes for Web:** The system UI can only be shown after user activation (e.g. a `Button` press).\n * Therefore, calling `launchCameraAsync` in `componentDidMount`, for example, will **not** work as\n * intended. The `cancelled` event will not be returned in the browser due to platform restrictions\n * and inconsistencies across browsers.\n * @param options An `ImagePickerOptions` object.\n * @return If the user cancelled the action, the method returns `{ cancelled: true }`. Otherwise,\n * this method returns information about the selected media item. When the chosen item is an image,\n * this method returns `{ cancelled: false, type: 'image', uri, width, height, exif, base64 }`;\n * when the item is a video, this method returns `{ cancelled: false, type: 'video', uri, width, height, duration }`.\n */\nexport async function launchCameraAsync(\n options: ImagePickerOptions = {}\n): Promise<ImagePickerResult> {\n if (!ExponentImagePicker.launchCameraAsync) {\n throw new UnavailabilityError('ImagePicker', 'launchCameraAsync');\n }\n return await ExponentImagePicker.launchCameraAsync(validateOptions(options));\n}\n\n// @needsAudit\n/**\n * Display the system UI for choosing an image or a video from the phone's library.\n * Requires `Permissions.MEDIA_LIBRARY` on iOS 10 only. On mobile web, this must be called\n * immediately in a user interaction like a button press, otherwise the browser will block the\n * request without a warning.\n * **Animated GIFs support** If the selected image is an animated GIF, the result image will be an\n * animated GIF too if and only if `quality` is set to `undefined` and `allowsEditing` is set to `false`.\n * Otherwise compression and/or cropper will pick the first frame of the GIF and return it as the\n * result (on Android the result will be a PNG, on iOS — GIF).\n * > **Notes for Web:** The system UI can only be shown after user activation (e.g. a `Button` press).\n * Therefore, calling `launchImageLibraryAsync` in `componentDidMount`, for example, will **not**\n * work as intended. The `cancelled` event will not be returned in the browser due to platform\n * restrictions and inconsistencies across browsers.\n * @param options An object extended by [`ImagePickerOptions`](#imagepickeroptions).\n * @return If the user cancelled the action, the method returns `{ cancelled: true }`. Otherwise,\n * this method returns information about the selected media item. When the chosen item is an image,\n * this method returns `{ cancelled: false, type: 'image', uri, width, height, exif, base64 }`;\n * when the item is a video, this method returns `{ cancelled: false, type: 'video', uri, width, height, duration }`.\n */\nexport async function launchImageLibraryAsync<T extends ImagePickerOptions>(\n options?: T\n): Promise<ExpandImagePickerResult<T>> {\n if (!ExponentImagePicker.launchImageLibraryAsync) {\n throw new UnavailabilityError('ImagePicker', 'launchImageLibraryAsync');\n }\n if (options?.allowsEditing && options.allowsMultipleSelection) {\n console.warn(\n '[expo-image-picker] `allowsEditing` is not supported when `allowsMultipleSelection` is enabled and will be ignored.' +\n \"Disable either 'allowsEditing' or 'allowsMultipleSelection' in 'launchImageLibraryAsync' \" +\n 'to fix this warning.'\n );\n }\n return await ExponentImagePicker.launchImageLibraryAsync(options ?? {});\n}\n\nexport {\n MediaTypeOptions,\n ImagePickerOptions,\n ImagePickerResult,\n ImagePickerErrorResult,\n VideoExportPreset,\n CameraPermissionResponse,\n CameraRollPermissionResponse,\n MediaLibraryPermissionResponse,\n PermissionStatus,\n PermissionExpiration,\n PermissionHookOptions,\n PermissionResponse,\n ImageInfo,\n ImagePickerMultipleResult,\n ImagePickerCancelledResult,\n OpenFileBrowserOptions,\n ExpandImagePickerResult,\n UIImagePickerControllerQualityType,\n UIImagePickerPresentationStyle,\n};\n"]}
|
|
1
|
+
{"version":3,"file":"ImagePicker.js","sourceRoot":"","sources":["../src/ImagePicker.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n PermissionStatus,\n PermissionExpiration,\n PermissionHookOptions,\n PermissionResponse,\n createPermissionHook,\n UnavailabilityError,\n CodedError,\n} from 'expo-modules-core';\n\nimport ExponentImagePicker from './ExponentImagePicker';\nimport {\n CameraPermissionResponse,\n CameraRollPermissionResponse,\n MediaLibraryPermissionResponse,\n ImagePickerResult,\n ImagePickerErrorResult,\n MediaTypeOptions,\n ImagePickerOptions,\n VideoExportPreset,\n ExpandImagePickerResult,\n ImageInfo,\n ImagePickerMultipleResult,\n ImagePickerCancelledResult,\n OpenFileBrowserOptions,\n UIImagePickerControllerQualityType,\n UIImagePickerPresentationStyle,\n} from './ImagePicker.types';\n\nfunction validateOptions(options: ImagePickerOptions) {\n const { aspect, quality, videoMaxDuration } = options;\n\n if (aspect != null) {\n const [x, y] = aspect;\n\n if (x <= 0 || y <= 0) {\n throw new CodedError(\n 'ERR_INVALID_ARGUMENT',\n `Invalid aspect ratio values ${x}:${y}. Provide positive numbers.`\n );\n }\n }\n\n if (quality && (quality < 0 || quality > 1)) {\n throw new CodedError(\n 'ERR_INVALID_ARGUMENT',\n `Invalid 'quality' value ${quality}. Provide a value between 0 and 1.`\n );\n }\n\n if (videoMaxDuration && videoMaxDuration < 0) {\n throw new CodedError(\n 'ERR_INVALID_ARGUMENT',\n `Invalid 'videoMaxDuration' value ${videoMaxDuration}. Provide a non-negative number.`\n );\n }\n\n return options;\n}\n\n// @needsAudit\n/**\n * Checks user's permissions for accessing camera.\n * @return A promise that fulfills with an object of type [CameraPermissionResponse](#camerarollpermissionresponse).\n */\nexport async function getCameraPermissionsAsync(): Promise<CameraPermissionResponse> {\n return ExponentImagePicker.getCameraPermissionsAsync();\n}\n\n/**\n * @deprecated Use `getMediaLibraryPermissionsAsync()` instead.\n */\nexport async function getCameraRollPermissionsAsync(): Promise<MediaLibraryPermissionResponse> {\n console.warn(\n 'ImagePicker.getCameraRollPermissionsAsync() is deprecated in favour of ImagePicker.getMediaLibraryPermissionsAsync()'\n );\n return getMediaLibraryPermissionsAsync();\n}\n\n// @needsAudit\n/**\n * Checks user's permissions for accessing photos.\n * @param writeOnly Whether to request write or read and write permissions. Defaults to `false`\n * @return A promise that fulfills with an object of type [MediaLibraryPermissionResponse](#medialibrarypermissionresponse).\n */\nexport async function getMediaLibraryPermissionsAsync(\n writeOnly: boolean = false\n): Promise<MediaLibraryPermissionResponse> {\n return ExponentImagePicker.getMediaLibraryPermissionsAsync(writeOnly);\n}\n\n// @needsAudit\n/**\n * Asks the user to grant permissions for accessing camera. This does nothing on web because the\n * browser camera is not used.\n * @return A promise that fulfills with an object of type [CameraPermissionResponse](#camerarollpermissionresponse).\n */\nexport async function requestCameraPermissionsAsync(): Promise<CameraPermissionResponse> {\n return ExponentImagePicker.requestCameraPermissionsAsync();\n}\n\n/**\n * @deprecated Use `requestMediaLibraryPermissionsAsync()` instead.\n */\nexport async function requestCameraRollPermissionsAsync(): Promise<MediaLibraryPermissionResponse> {\n console.warn(\n 'ImagePicker.requestCameraRollPermissionsAsync() is deprecated in favour of ImagePicker.requestMediaLibraryPermissionsAsync()'\n );\n return requestMediaLibraryPermissionsAsync();\n}\n\n// @needsAudit\n/**\n * Asks the user to grant permissions for accessing user's photo. This method does nothing on web.\n * @param writeOnly Whether to request write or read and write permissions. Defaults to `false`\n * @return A promise that fulfills with an object of type [MediaLibraryPermissionResponse](#medialibrarypermissionresponse).\n */\nexport async function requestMediaLibraryPermissionsAsync(\n writeOnly: boolean = false\n): Promise<MediaLibraryPermissionResponse> {\n const imagePickerMethod = ExponentImagePicker.requestMediaLibraryPermissionsAsync;\n return imagePickerMethod(writeOnly);\n}\n\n// @needsAudit\n/**\n * Check or request permissions to access the media library.\n * This uses both `requestMediaLibraryPermissionsAsync` and `getMediaLibraryPermissionsAsync` to interact with the permissions.\n *\n * @example\n * ```ts\n * const [status, requestPermission] = ImagePicker.useMediaLibraryPermissions();\n * ```\n */\nexport const useMediaLibraryPermissions = createPermissionHook<\n MediaLibraryPermissionResponse,\n { writeOnly?: boolean }\n>({\n // TODO(cedric): permission requesters should have an options param or a different requester\n getMethod: (options) => getMediaLibraryPermissionsAsync(options?.writeOnly),\n requestMethod: (options) => requestMediaLibraryPermissionsAsync(options?.writeOnly),\n});\n\n// @needsAudit\n/**\n * Check or request permissions to access the camera.\n * This uses both `requestCameraPermissionsAsync` and `getCameraPermissionsAsync` to interact with the permissions.\n *\n * @example\n * ```ts\n * const [status, requestPermission] = ImagePicker.useCameraPermissions();\n * ```\n */\nexport const useCameraPermissions = createPermissionHook({\n getMethod: getCameraPermissionsAsync,\n requestMethod: requestCameraPermissionsAsync,\n});\n\n// @needsAudit\n/**\n * Android system sometimes kills the `MainActivity` after the `ImagePicker` finishes. When this\n * happens, we lost the data selected from the `ImagePicker`. However, you can retrieve the lost\n * data by calling `getPendingResultAsync`. You can test this functionality by turning on\n * `Don't keep activities` in the developer options.\n * @return\n * - **On Android:** a promise that resolves to an array of objects of exactly same type as in\n * `ImagePicker.launchImageLibraryAsync` or `ImagePicker.launchCameraAsync` if the `ImagePicker`\n * finished successfully. Otherwise, to the array of [`ImagePickerErrorResult`](#imagepickerimagepickererrorresult).\n * - **On other platforms:** an empty array.\n */\nexport async function getPendingResultAsync(): Promise<\n (ImagePickerResult | ImagePickerErrorResult)[]\n> {\n if (ExponentImagePicker.getPendingResultAsync) {\n return ExponentImagePicker.getPendingResultAsync();\n }\n return [];\n}\n\n// @needsAudit\n/**\n * Display the system UI for taking a photo with the camera. Requires `Permissions.CAMERA`.\n * On Android and iOS 10 `Permissions.CAMERA_ROLL` is also required. On mobile web, this must be\n * called immediately in a user interaction like a button press, otherwise the browser will block\n * the request without a warning.\n * > **Note:** Make sure that you handle `MainActivity` destruction on **Android**. See [ImagePicker.getPendingResultAsync](#imagepickergetpendingresultasync).\n * > **Notes for Web:** The system UI can only be shown after user activation (e.g. a `Button` press).\n * Therefore, calling `launchCameraAsync` in `componentDidMount`, for example, will **not** work as\n * intended. The `cancelled` event will not be returned in the browser due to platform restrictions\n * and inconsistencies across browsers.\n * @param options An `ImagePickerOptions` object.\n * @return If the user cancelled the action, the method returns `{ cancelled: true }`. Otherwise,\n * this method returns information about the selected media item. When the chosen item is an image,\n * this method returns `{ cancelled: false, type: 'image', uri, width, height, exif, base64 }`;\n * when the item is a video, this method returns `{ cancelled: false, type: 'video', uri, width, height, duration }`.\n */\nexport async function launchCameraAsync(\n options: ImagePickerOptions = {}\n): Promise<ImagePickerResult> {\n if (!ExponentImagePicker.launchCameraAsync) {\n throw new UnavailabilityError('ImagePicker', 'launchCameraAsync');\n }\n return await ExponentImagePicker.launchCameraAsync(validateOptions(options));\n}\n\n// @needsAudit\n/**\n * Display the system UI for choosing an image or a video from the phone's library.\n * Requires `Permissions.MEDIA_LIBRARY` on iOS 10 only. On mobile web, this must be called\n * immediately in a user interaction like a button press, otherwise the browser will block the\n * request without a warning.\n * **Animated GIFs support** If the selected image is an animated GIF, the result image will be an\n * animated GIF too if and only if `quality` is set to `undefined` and `allowsEditing` is set to `false`.\n * Otherwise compression and/or cropper will pick the first frame of the GIF and return it as the\n * result (on Android the result will be a PNG, on iOS — GIF).\n * > **Notes for Web:** The system UI can only be shown after user activation (e.g. a `Button` press).\n * Therefore, calling `launchImageLibraryAsync` in `componentDidMount`, for example, will **not**\n * work as intended. The `cancelled` event will not be returned in the browser due to platform\n * restrictions and inconsistencies across browsers.\n * @param options An object extended by [`ImagePickerOptions`](#imagepickeroptions).\n * @return If the user cancelled the action, the method returns `{ cancelled: true }`. Otherwise,\n * this method returns information about the selected media item. When the chosen item is an image,\n * this method returns `{ cancelled: false, type: 'image', uri, width, height, exif, base64 }`;\n * when the item is a video, this method returns `{ cancelled: false, type: 'video', uri, width, height, duration }`.\n */\nexport async function launchImageLibraryAsync<T extends ImagePickerOptions>(\n options?: T\n): Promise<ExpandImagePickerResult<T>> {\n if (!ExponentImagePicker.launchImageLibraryAsync) {\n throw new UnavailabilityError('ImagePicker', 'launchImageLibraryAsync');\n }\n if (options?.allowsEditing && options.allowsMultipleSelection) {\n console.warn(\n '[expo-image-picker] `allowsEditing` is not supported when `allowsMultipleSelection` is enabled and will be ignored.' +\n \"Disable either 'allowsEditing' or 'allowsMultipleSelection' in 'launchImageLibraryAsync' \" +\n 'to fix this warning.'\n );\n }\n return await ExponentImagePicker.launchImageLibraryAsync(options ?? {});\n}\n\nexport {\n MediaTypeOptions,\n ImagePickerOptions,\n ImagePickerResult,\n ImagePickerErrorResult,\n VideoExportPreset,\n CameraPermissionResponse,\n CameraRollPermissionResponse,\n MediaLibraryPermissionResponse,\n PermissionStatus,\n PermissionExpiration,\n PermissionHookOptions,\n PermissionResponse,\n ImageInfo,\n ImagePickerMultipleResult,\n ImagePickerCancelledResult,\n OpenFileBrowserOptions,\n ExpandImagePickerResult,\n UIImagePickerControllerQualityType,\n UIImagePickerPresentationStyle,\n};\n"]}
|
|
@@ -205,6 +205,17 @@ export declare type ImageInfo = {
|
|
|
205
205
|
* an image) and `width` and `height` specify the dimensions of the media.
|
|
206
206
|
*/
|
|
207
207
|
uri: string;
|
|
208
|
+
/**
|
|
209
|
+
* The unique ID that represents the picked image or video, if picked from the library. It can be used
|
|
210
|
+
* by [expo-media-library](./media-library) to manage the picked asset.
|
|
211
|
+
*
|
|
212
|
+
* > This might be `null` when the ID is unavailable or the user gave limited permission to access the media library.
|
|
213
|
+
* > On Android, the ID is unavailable when the user selects a photo by directly browsing file system.
|
|
214
|
+
*
|
|
215
|
+
* @platform ios
|
|
216
|
+
* @platform android
|
|
217
|
+
*/
|
|
218
|
+
assetId?: string | null;
|
|
208
219
|
/**
|
|
209
220
|
* Width of the image or video.
|
|
210
221
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ImagePicker.types.d.ts","sourceRoot":"","sources":["../src/ImagePicker.types.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ImagePicker.types.d.ts","sourceRoot":"","sources":["../src/ImagePicker.types.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ImagePicker.types.js","sourceRoot":"","sources":["../src/ImagePicker.types.ts"],"names":[],"mappings":"AA0BA,cAAc;AACd,MAAM,CAAN,IAAY,gBAaX;AAbD,WAAY,gBAAgB;IAC1B;;OAEG;IACH,+BAAW,CAAA;IACX;;OAEG;IACH,qCAAiB,CAAA;IACjB;;OAEG;IACH,qCAAiB,CAAA;AACnB,CAAC,EAbW,gBAAgB,KAAhB,gBAAgB,QAa3B;AAED,cAAc;AACd,MAAM,CAAN,IAAY,iBAmEX;AAnED,WAAY,iBAAiB;IAC3B;;;;OAIG;IACH,uEAAe,CAAA;IACf;;;;OAIG;IACH,qEAAc,CAAA;IACd;;;;OAIG;IACH,2EAAiB,CAAA;IACjB;;;;OAIG;IACH,6EAAkB,CAAA;IAClB;;;;OAIG;IACH,yEAAgB,CAAA;IAChB;;;;OAIG;IACH,yEAAgB,CAAA;IAChB;;;;OAIG;IACH,2EAAiB,CAAA;IACjB;;;;OAIG;IACH,6EAAkB,CAAA;IAClB;;;;OAIG;IACH,6EAAkB,CAAA;IAClB;;;;OAIG;IACH,6EAAkB,CAAA;IAClB;;;;OAIG;IACH,8EAAmB,CAAA;AACrB,CAAC,EAnEW,iBAAiB,KAAjB,iBAAiB,QAmE5B;AAED,cAAc;AACd,MAAM,CAAN,IAAY,kCAyBX;AAzBD,WAAY,kCAAkC;IAC5C;;OAEG;IACH,2FAAQ,CAAA;IACR;;OAEG;IACH,+FAAU,CAAA;IACV;;OAEG;IACH,yFAAO,CAAA;IACP;;OAEG;IACH,uGAAc,CAAA;IACd;;OAEG;IACH,+GAAkB,CAAA;IAClB;;OAEG;IACH,6GAAiB,CAAA;AACnB,CAAC,EAzBW,kCAAkC,KAAlC,kCAAkC,QAyB7C;AAED;;;;GAIG;AACH,MAAM,CAAN,IAAY,8BAoEX;AApED,WAAY,8BAA8B;IACxC;;OAEG;IACH,4DAA0B,CAAA;IAC1B;;OAEG;IACH,0DAAwB,CAAA;IACxB;;OAEG;IACH,0DAAwB,CAAA;IACxB;;OAEG;IACH,oEAAkC,CAAA;IAClC;;OAEG;IACH,qEAAmC,CAAA;IACnC;;OAEG;IACH,6EAA2C,CAAA;IAC3C;;OAEG;IACH,qDAAmB,CAAA;IACnB;;;;;OAKG;IACH,yDAAuB,CAAA;IACvB;;OAEG;IACH,2DAAyB,CAAA;IACzB;;OAEG;IACH,yDAAuB,CAAA;IACvB;;OAEG;IACH,yDAAuB,CAAA;IACvB;;OAEG;IACH,mEAAiC,CAAA;IACjC;;OAEG;IACH,mEAAiC,CAAA;IACjC;;OAEG;IACH,2EAAyC,CAAA;IACzC;;OAEG;IACH,qDAAmB,CAAA;IACnB;;OAEG;IACH,yDAAuB,CAAA;AACzB,CAAC,EApEW,8BAA8B,KAA9B,8BAA8B,QAoEzC","sourcesContent":["import { PermissionResponse } from 'expo-modules-core';\n\n// @needsAudit\n/**\n * Alias for `PermissionResponse` type exported by `expo-modules-core`.\n */\nexport type CameraPermissionResponse = PermissionResponse;\n\n// @needsAudit\n/**\n * Extends `PermissionResponse` type exported by `expo-modules-core` and contains additional iOS-specific field.\n */\nexport type MediaLibraryPermissionResponse = PermissionResponse & {\n /**\n * @platform ios\n */\n accessPrivileges?: 'all' | 'limited' | 'none';\n};\n\n// @needsAudit\n/**\n * An alias for the `MediaLibraryPermissionResponse` object.\n * @deprecated Use `ImagePicker.MediaLibraryPermissionResponse` instead.\n */\nexport type CameraRollPermissionResponse = MediaLibraryPermissionResponse;\n\n// @needsAudit\nexport enum MediaTypeOptions {\n /**\n * Images and videos.\n */\n All = 'All',\n /**\n * Only videos.\n */\n Videos = 'Videos',\n /**\n * Only images.\n */\n Images = 'Images',\n}\n\n// @needsAudit\nexport enum VideoExportPreset {\n /**\n * Resolution: __Unchanged__ •\n * Video compression: __None__ •\n * Audio compression: __None__\n */\n Passthrough = 0,\n /**\n * Resolution: __Depends on the device__ •\n * Video compression: __H.264__ •\n * Audio compression: __AAC__\n */\n LowQuality = 1,\n /**\n * Resolution: __Depends on the device__ •\n * Video compression: __H.264__ •\n * Audio compression: __AAC__\n */\n MediumQuality = 2,\n /**\n * Resolution: __Depends on the device__ •\n * Video compression: __H.264__ •\n * Audio compression: __AAC__\n */\n HighestQuality = 3,\n /**\n * Resolution: __640 × 480__ •\n * Video compression: __H.264__ •\n * Audio compression: __AAC__\n */\n H264_640x480 = 4,\n /**\n * Resolution: __960 × 540__ •\n * Video compression: __H.264__ •\n * Audio compression: __AAC__\n */\n H264_960x540 = 5,\n /**\n * Resolution: __1280 × 720__ •\n * Video compression: __H.264__ •\n * Audio compression: __AAC__\n */\n H264_1280x720 = 6,\n /**\n * Resolution: __1920 × 1080__ •\n * Video compression: __H.264__ •\n * Audio compression: __AAC__\n */\n H264_1920x1080 = 7,\n /**\n * Resolution: __3840 × 2160__ •\n * Video compression: __H.264__ •\n * Audio compression: __AAC__\n */\n H264_3840x2160 = 8,\n /**\n * Resolution: __1920 × 1080__ •\n * Video compression: __HEVC__ •\n * Audio compression: __AAC__\n */\n HEVC_1920x1080 = 9,\n /**\n * Resolution: __3840 × 2160__ •\n * Video compression: __HEVC__ •\n * Audio compression: __AAC__\n */\n HEVC_3840x2160 = 10,\n}\n\n// @needsAudit\nexport enum UIImagePickerControllerQualityType {\n /**\n * Highest available resolution.\n */\n High = 0,\n /**\n * Depends on the device.\n */\n Medium = 1,\n /**\n * Depends on the device.\n */\n Low = 2,\n /**\n * 640 × 480\n */\n VGA640x480 = 3,\n /**\n * 1280 × 720\n */\n IFrame1280x720 = 4,\n /**\n * 960 × 540\n */\n IFrame960x540 = 5,\n}\n\n/**\n * Picker presentation style. Its values are directly mapped to the [`UIModalPresentationStyle`](https://developer.apple.com/documentation/uikit/uiviewcontroller/1621355-modalpresentationstyle).\n *\n * @platform ios\n */\nexport enum UIImagePickerPresentationStyle {\n /**\n * A presentation style in which the presented picker covers the screen.\n */\n FULL_SCREEN = 'fullScreen',\n /**\n * A presentation style that partially covers the underlying content.\n */\n PAGE_SHEET = 'pageSheet',\n /**\n * A presentation style that displays the picker centered in the screen.\n */\n FORM_SHEET = 'formSheet',\n /**\n * A presentation style where the picker is displayed over the app's content.\n */\n CURRENT_CONTEXT = 'currentContext',\n /**\n * A presentation style in which the picker view covers the screen.\n */\n OVER_FULL_SCREEN = 'overFullScreen',\n /**\n * A presentation style where the picker is displayed over the app's content.\n */\n OVER_CURRENT_CONTEXT = 'overCurrentContext',\n /**\n * A presentation style where the picker is displayed in a popover view.\n */\n POPOVER = 'popover',\n /**\n * The default presentation style chosen by the system.\n * On older iOS versions, falls back to `WebBrowserPresentationStyle.FullScreen`.\n *\n * @platform ios 13+\n */\n AUTOMATIC = 'automatic',\n /**\n * @deprecated Use `UIImagePickerPresentationStyle.FULL_SCREEN` instead.\n */\n FullScreen = 'fullScreen',\n /**\n * @deprecated Use `UIImagePickerPresentationStyle.PAGE_SHEET` instead.\n */\n PageSheet = 'pageSheet',\n /**\n * @deprecated Use `UIImagePickerPresentationStyle.FORM_SHEET` instead.\n */\n FormSheet = 'formSheet',\n /**\n * @deprecated Use `UIImagePickerPresentationStyle.CURRENT_CONTEXT` instead.\n */\n CurrentContext = 'currentContext',\n /**\n * @deprecated Use `UIImagePickerPresentationStyle.OVER_FULL_SCREEN` instead.\n */\n OverFullScreen = 'overFullScreen',\n /**\n * @deprecated Use `UIImagePickerPresentationStyle.OVER_CURRENT_CONTEXT` instead.\n */\n OverCurrentContext = 'overCurrentContext',\n /**\n * @deprecated Use `UIImagePickerPresentationStyle.POPOVER` instead.\n */\n Popover = 'popover',\n /**\n * @deprecated Use `UIImagePickerPresentationStyle.AUTOMATIC` instead.\n */\n Automatic = 'automatic',\n}\n\n// @needsAudit\nexport type ImageInfo = {\n /**\n * URI to the local image or video file (usable as the source of an `Image` element, in the case of\n * an image) and `width` and `height` specify the dimensions of the media.\n */\n uri: string;\n /**\n * Width of the image or video.\n */\n width: number;\n /**\n * Height of the image or video.\n */\n height: number;\n /**\n * The type of the asset.\n */\n type?: 'image' | 'video';\n /**\n * Preferred filename to use when saving this item. This might be `null` when the name is unavailable\n * or user gave limited permission to access the media library.\n *\n * @platform ios\n */\n fileName?: string | null;\n /**\n * File size of the picked image or video, in bytes.\n *\n * @platform ios\n */\n fileSize?: number;\n /**\n * The `exif` field is included if the `exif` option is truthy, and is an object containing the\n * image's EXIF data. The names of this object's properties are EXIF tags and the values are the\n * respective EXIF values for those tags.\n */\n exif?: Record<string, any>;\n /**\n * Included if the `base64` option is truthy, and is a Base64-encoded string of the selected\n * image's JPEG data. If you prepend this with `'data:image/jpeg;base64,'` to create a data URI,\n * you can use it as the source of an `Image` element; for example:\n * ```ts\n * <Image\n * source={{ uri: 'data:image/jpeg;base64,' + launchCameraResult.base64 }}\n * style={{ width: 200, height: 200 }}\n * />\n * ```\n */\n base64?: string;\n /**\n * Length of the video in milliseconds.\n */\n duration?: number;\n /**\n * Boolean flag which shows if request was cancelled. If asset data have been returned this should\n * always be `false`.\n */\n cancelled: boolean;\n};\n\n// @needsAudit\nexport type ImagePickerErrorResult = {\n /**\n * The error code.\n */\n code: string;\n /**\n * The error message.\n */\n message: string;\n /**\n * The exception which caused the error.\n */\n exception?: string;\n};\n\n// @needsAudit\n/**\n * An object returned when the pick action has been cancelled by the user.\n */\nexport type ImagePickerCancelledResult = { cancelled: true };\n\n// @needsAudit\nexport type ImagePickerResult = ImagePickerCancelledResult | ImageInfo;\n\n// @needsAudit @docsMissing\nexport type ImagePickerMultipleResult =\n | ImagePickerCancelledResult\n | { cancelled: false; selected: ImageInfo[] };\n\n// @needsAudit\nexport type ImagePickerOptions = {\n /**\n * Whether to show a UI to edit the image after it is picked. On Android the user can crop and\n * rotate the image and on iOS simply crop it.\n *\n * > Cropping multiple images is not supported - this option is mutually exclusive with `allowsMultipleSelection`.\n * > On iOS, this option is ignored if `allowsMultipleSelection` is enabled.\n *\n * @default false\n * @platform ios\n * @platform android\n */\n allowsEditing?: boolean;\n /**\n * An array with two entries `[x, y]` specifying the aspect ratio to maintain if the user is\n * allowed to edit the image (by passing `allowsEditing: true`). This is only applicable on\n * Android, since on iOS the crop rectangle is always a square.\n */\n aspect?: [number, number];\n /**\n * Specify the quality of compression, from `0` to `1`. `0` means compress for small size,\n * `1` means compress for maximum quality.\n * > Note: If the selected image has been compressed before, the size of the output file may be\n * > bigger than the size of the original image.\n *\n * > Note: On iOS, if a `.bmp` or `.png` image is selected from the library, this option is ignored.\n *\n * @default 0.2\n * @platform ios\n * @platform android\n */\n quality?: number;\n /**\n * Choose what type of media to pick.\n * @default ImagePicker.MediaTypeOptions.Images\n */\n mediaTypes?: MediaTypeOptions;\n /**\n * Whether to also include the EXIF data for the image. On iOS the EXIF data does not include GPS\n * tags in the camera case.\n */\n exif?: boolean;\n /**\n * Whether to also include the image data in Base64 format.\n */\n base64?: boolean;\n /**\n * Specify preset which will be used to compress selected video.\n * @default ImagePicker.VideoExportPreset.Passthrough\n * @platform ios 11+\n * @deprecated See [`videoExportPreset`](https://developer.apple.com/documentation/uikit/uiimagepickercontroller/2890964-videoexportpreset?language=objc)\n * in Apple documentation.\n */\n videoExportPreset?: VideoExportPreset;\n /**\n * Specify the quality of recorded videos. Defaults to the highest quality available for the device.\n * @default ImagePicker.UIImagePickerControllerQualityType.High\n * @platform ios\n */\n videoQuality?: UIImagePickerControllerQualityType;\n /**\n * Whether or not to allow selecting multiple media files at once.\n *\n * > Cropping multiple images is not supported - this option is mutually exclusive with `allowsEditing`.\n * > If this option is enabled, then `allowsEditing` is ignored.\n *\n * @default false\n * @platform ios 14+\n * @platform web\n */\n allowsMultipleSelection?: boolean;\n /**\n * The maximum number of items that user can select. Applicable when `allowsMultipleSelection` is enabled.\n * Setting the value to `0` sets the selection limit to the maximum that the system supports.\n *\n * @platform ios 14+\n * @default 0\n */\n selectionLimit?: number;\n /**\n * Whether to display number badges when assets are selected. The badges are numbered\n * in selection order. Assets are then returned in the exact same order they were selected.\n *\n * > Assets should be returned in the selection order regardless of this option,\n * > but there is no guarantee that it is always true when this option is disabled.\n *\n * @platform ios 15+\n * @default false\n */\n orderedSelection?: boolean;\n /**\n * Maximum duration, in seconds, for video recording. Setting this to `0` disables the limit.\n * Defaults to `0` (no limit).\n * - **On iOS**, when `allowsEditing` is set to `true`, maximum duration is limited to 10 minutes.\n * This limit is applied automatically, if `0` or no value is specified.\n * - **On Android**, effect of this option depends on support of installed camera app.\n * - **On Web** this option has no effect - the limit is browser-dependant.\n */\n videoMaxDuration?: number;\n /**\n * Choose [presentation style](https://developer.apple.com/documentation/uikit/uiviewcontroller/1621355-modalpresentationstyle?language=objc)\n * to customize view during taking photo/video.\n * @default ImagePicker.UIImagePickerPresentationStyle.Automatic\n * @platform ios\n */\n presentationStyle?: UIImagePickerPresentationStyle;\n};\n\n// @needsAudit\nexport type OpenFileBrowserOptions = {\n /**\n * Choose what type of media to pick.\n * @default ImagePicker.MediaTypeOptions.Images\n */\n mediaTypes: MediaTypeOptions;\n // @docsMissing\n capture?: boolean;\n /**\n * Whether or not to allow selecting multiple media files at once.\n * @platform web\n */\n allowsMultipleSelection: boolean;\n /**\n * Whether to also include the image data in Base64 format.\n */\n base64: boolean;\n};\n\n// @needsAudit @docsMissing\nexport type ExpandImagePickerResult<T extends ImagePickerOptions | OpenFileBrowserOptions> =\n T extends {\n allowsMultipleSelection: true;\n }\n ? ImagePickerMultipleResult\n : ImagePickerResult;\n"]}
|
|
1
|
+
{"version":3,"file":"ImagePicker.types.js","sourceRoot":"","sources":["../src/ImagePicker.types.ts"],"names":[],"mappings":"AA0BA,cAAc;AACd,MAAM,CAAN,IAAY,gBAaX;AAbD,WAAY,gBAAgB;IAC1B;;OAEG;IACH,+BAAW,CAAA;IACX;;OAEG;IACH,qCAAiB,CAAA;IACjB;;OAEG;IACH,qCAAiB,CAAA;AACnB,CAAC,EAbW,gBAAgB,KAAhB,gBAAgB,QAa3B;AAED,cAAc;AACd,MAAM,CAAN,IAAY,iBAmEX;AAnED,WAAY,iBAAiB;IAC3B;;;;OAIG;IACH,uEAAe,CAAA;IACf;;;;OAIG;IACH,qEAAc,CAAA;IACd;;;;OAIG;IACH,2EAAiB,CAAA;IACjB;;;;OAIG;IACH,6EAAkB,CAAA;IAClB;;;;OAIG;IACH,yEAAgB,CAAA;IAChB;;;;OAIG;IACH,yEAAgB,CAAA;IAChB;;;;OAIG;IACH,2EAAiB,CAAA;IACjB;;;;OAIG;IACH,6EAAkB,CAAA;IAClB;;;;OAIG;IACH,6EAAkB,CAAA;IAClB;;;;OAIG;IACH,6EAAkB,CAAA;IAClB;;;;OAIG;IACH,8EAAmB,CAAA;AACrB,CAAC,EAnEW,iBAAiB,KAAjB,iBAAiB,QAmE5B;AAED,cAAc;AACd,MAAM,CAAN,IAAY,kCAyBX;AAzBD,WAAY,kCAAkC;IAC5C;;OAEG;IACH,2FAAQ,CAAA;IACR;;OAEG;IACH,+FAAU,CAAA;IACV;;OAEG;IACH,yFAAO,CAAA;IACP;;OAEG;IACH,uGAAc,CAAA;IACd;;OAEG;IACH,+GAAkB,CAAA;IAClB;;OAEG;IACH,6GAAiB,CAAA;AACnB,CAAC,EAzBW,kCAAkC,KAAlC,kCAAkC,QAyB7C;AAED;;;;GAIG;AACH,MAAM,CAAN,IAAY,8BAoEX;AApED,WAAY,8BAA8B;IACxC;;OAEG;IACH,4DAA0B,CAAA;IAC1B;;OAEG;IACH,0DAAwB,CAAA;IACxB;;OAEG;IACH,0DAAwB,CAAA;IACxB;;OAEG;IACH,oEAAkC,CAAA;IAClC;;OAEG;IACH,qEAAmC,CAAA;IACnC;;OAEG;IACH,6EAA2C,CAAA;IAC3C;;OAEG;IACH,qDAAmB,CAAA;IACnB;;;;;OAKG;IACH,yDAAuB,CAAA;IACvB;;OAEG;IACH,2DAAyB,CAAA;IACzB;;OAEG;IACH,yDAAuB,CAAA;IACvB;;OAEG;IACH,yDAAuB,CAAA;IACvB;;OAEG;IACH,mEAAiC,CAAA;IACjC;;OAEG;IACH,mEAAiC,CAAA;IACjC;;OAEG;IACH,2EAAyC,CAAA;IACzC;;OAEG;IACH,qDAAmB,CAAA;IACnB;;OAEG;IACH,yDAAuB,CAAA;AACzB,CAAC,EApEW,8BAA8B,KAA9B,8BAA8B,QAoEzC","sourcesContent":["import { PermissionResponse } from 'expo-modules-core';\n\n// @needsAudit\n/**\n * Alias for `PermissionResponse` type exported by `expo-modules-core`.\n */\nexport type CameraPermissionResponse = PermissionResponse;\n\n// @needsAudit\n/**\n * Extends `PermissionResponse` type exported by `expo-modules-core` and contains additional iOS-specific field.\n */\nexport type MediaLibraryPermissionResponse = PermissionResponse & {\n /**\n * @platform ios\n */\n accessPrivileges?: 'all' | 'limited' | 'none';\n};\n\n// @needsAudit\n/**\n * An alias for the `MediaLibraryPermissionResponse` object.\n * @deprecated Use `ImagePicker.MediaLibraryPermissionResponse` instead.\n */\nexport type CameraRollPermissionResponse = MediaLibraryPermissionResponse;\n\n// @needsAudit\nexport enum MediaTypeOptions {\n /**\n * Images and videos.\n */\n All = 'All',\n /**\n * Only videos.\n */\n Videos = 'Videos',\n /**\n * Only images.\n */\n Images = 'Images',\n}\n\n// @needsAudit\nexport enum VideoExportPreset {\n /**\n * Resolution: __Unchanged__ •\n * Video compression: __None__ •\n * Audio compression: __None__\n */\n Passthrough = 0,\n /**\n * Resolution: __Depends on the device__ •\n * Video compression: __H.264__ •\n * Audio compression: __AAC__\n */\n LowQuality = 1,\n /**\n * Resolution: __Depends on the device__ •\n * Video compression: __H.264__ •\n * Audio compression: __AAC__\n */\n MediumQuality = 2,\n /**\n * Resolution: __Depends on the device__ •\n * Video compression: __H.264__ •\n * Audio compression: __AAC__\n */\n HighestQuality = 3,\n /**\n * Resolution: __640 × 480__ •\n * Video compression: __H.264__ •\n * Audio compression: __AAC__\n */\n H264_640x480 = 4,\n /**\n * Resolution: __960 × 540__ •\n * Video compression: __H.264__ •\n * Audio compression: __AAC__\n */\n H264_960x540 = 5,\n /**\n * Resolution: __1280 × 720__ •\n * Video compression: __H.264__ •\n * Audio compression: __AAC__\n */\n H264_1280x720 = 6,\n /**\n * Resolution: __1920 × 1080__ •\n * Video compression: __H.264__ •\n * Audio compression: __AAC__\n */\n H264_1920x1080 = 7,\n /**\n * Resolution: __3840 × 2160__ •\n * Video compression: __H.264__ •\n * Audio compression: __AAC__\n */\n H264_3840x2160 = 8,\n /**\n * Resolution: __1920 × 1080__ •\n * Video compression: __HEVC__ •\n * Audio compression: __AAC__\n */\n HEVC_1920x1080 = 9,\n /**\n * Resolution: __3840 × 2160__ •\n * Video compression: __HEVC__ •\n * Audio compression: __AAC__\n */\n HEVC_3840x2160 = 10,\n}\n\n// @needsAudit\nexport enum UIImagePickerControllerQualityType {\n /**\n * Highest available resolution.\n */\n High = 0,\n /**\n * Depends on the device.\n */\n Medium = 1,\n /**\n * Depends on the device.\n */\n Low = 2,\n /**\n * 640 × 480\n */\n VGA640x480 = 3,\n /**\n * 1280 × 720\n */\n IFrame1280x720 = 4,\n /**\n * 960 × 540\n */\n IFrame960x540 = 5,\n}\n\n/**\n * Picker presentation style. Its values are directly mapped to the [`UIModalPresentationStyle`](https://developer.apple.com/documentation/uikit/uiviewcontroller/1621355-modalpresentationstyle).\n *\n * @platform ios\n */\nexport enum UIImagePickerPresentationStyle {\n /**\n * A presentation style in which the presented picker covers the screen.\n */\n FULL_SCREEN = 'fullScreen',\n /**\n * A presentation style that partially covers the underlying content.\n */\n PAGE_SHEET = 'pageSheet',\n /**\n * A presentation style that displays the picker centered in the screen.\n */\n FORM_SHEET = 'formSheet',\n /**\n * A presentation style where the picker is displayed over the app's content.\n */\n CURRENT_CONTEXT = 'currentContext',\n /**\n * A presentation style in which the picker view covers the screen.\n */\n OVER_FULL_SCREEN = 'overFullScreen',\n /**\n * A presentation style where the picker is displayed over the app's content.\n */\n OVER_CURRENT_CONTEXT = 'overCurrentContext',\n /**\n * A presentation style where the picker is displayed in a popover view.\n */\n POPOVER = 'popover',\n /**\n * The default presentation style chosen by the system.\n * On older iOS versions, falls back to `WebBrowserPresentationStyle.FullScreen`.\n *\n * @platform ios 13+\n */\n AUTOMATIC = 'automatic',\n /**\n * @deprecated Use `UIImagePickerPresentationStyle.FULL_SCREEN` instead.\n */\n FullScreen = 'fullScreen',\n /**\n * @deprecated Use `UIImagePickerPresentationStyle.PAGE_SHEET` instead.\n */\n PageSheet = 'pageSheet',\n /**\n * @deprecated Use `UIImagePickerPresentationStyle.FORM_SHEET` instead.\n */\n FormSheet = 'formSheet',\n /**\n * @deprecated Use `UIImagePickerPresentationStyle.CURRENT_CONTEXT` instead.\n */\n CurrentContext = 'currentContext',\n /**\n * @deprecated Use `UIImagePickerPresentationStyle.OVER_FULL_SCREEN` instead.\n */\n OverFullScreen = 'overFullScreen',\n /**\n * @deprecated Use `UIImagePickerPresentationStyle.OVER_CURRENT_CONTEXT` instead.\n */\n OverCurrentContext = 'overCurrentContext',\n /**\n * @deprecated Use `UIImagePickerPresentationStyle.POPOVER` instead.\n */\n Popover = 'popover',\n /**\n * @deprecated Use `UIImagePickerPresentationStyle.AUTOMATIC` instead.\n */\n Automatic = 'automatic',\n}\n\n// @needsAudit\nexport type ImageInfo = {\n /**\n * URI to the local image or video file (usable as the source of an `Image` element, in the case of\n * an image) and `width` and `height` specify the dimensions of the media.\n */\n uri: string;\n /**\n * The unique ID that represents the picked image or video, if picked from the library. It can be used\n * by [expo-media-library](./media-library) to manage the picked asset.\n *\n * > This might be `null` when the ID is unavailable or the user gave limited permission to access the media library.\n * > On Android, the ID is unavailable when the user selects a photo by directly browsing file system.\n *\n * @platform ios\n * @platform android\n */\n assetId?: string | null;\n /**\n * Width of the image or video.\n */\n width: number;\n /**\n * Height of the image or video.\n */\n height: number;\n /**\n * The type of the asset.\n */\n type?: 'image' | 'video';\n /**\n * Preferred filename to use when saving this item. This might be `null` when the name is unavailable\n * or user gave limited permission to access the media library.\n *\n * @platform ios\n */\n fileName?: string | null;\n /**\n * File size of the picked image or video, in bytes.\n *\n * @platform ios\n */\n fileSize?: number;\n /**\n * The `exif` field is included if the `exif` option is truthy, and is an object containing the\n * image's EXIF data. The names of this object's properties are EXIF tags and the values are the\n * respective EXIF values for those tags.\n */\n exif?: Record<string, any>;\n /**\n * Included if the `base64` option is truthy, and is a Base64-encoded string of the selected\n * image's JPEG data. If you prepend this with `'data:image/jpeg;base64,'` to create a data URI,\n * you can use it as the source of an `Image` element; for example:\n * ```ts\n * <Image\n * source={{ uri: 'data:image/jpeg;base64,' + launchCameraResult.base64 }}\n * style={{ width: 200, height: 200 }}\n * />\n * ```\n */\n base64?: string;\n /**\n * Length of the video in milliseconds.\n */\n duration?: number;\n /**\n * Boolean flag which shows if request was cancelled. If asset data have been returned this should\n * always be `false`.\n */\n cancelled: boolean;\n};\n\n// @needsAudit\nexport type ImagePickerErrorResult = {\n /**\n * The error code.\n */\n code: string;\n /**\n * The error message.\n */\n message: string;\n /**\n * The exception which caused the error.\n */\n exception?: string;\n};\n\n// @needsAudit\n/**\n * An object returned when the pick action has been cancelled by the user.\n */\nexport type ImagePickerCancelledResult = { cancelled: true };\n\n// @needsAudit\nexport type ImagePickerResult = ImagePickerCancelledResult | ImageInfo;\n\n// @needsAudit @docsMissing\nexport type ImagePickerMultipleResult =\n | ImagePickerCancelledResult\n | { cancelled: false; selected: ImageInfo[] };\n\n// @needsAudit\nexport type ImagePickerOptions = {\n /**\n * Whether to show a UI to edit the image after it is picked. On Android the user can crop and\n * rotate the image and on iOS simply crop it.\n *\n * > Cropping multiple images is not supported - this option is mutually exclusive with `allowsMultipleSelection`.\n * > On iOS, this option is ignored if `allowsMultipleSelection` is enabled.\n *\n * @default false\n * @platform ios\n * @platform android\n */\n allowsEditing?: boolean;\n /**\n * An array with two entries `[x, y]` specifying the aspect ratio to maintain if the user is\n * allowed to edit the image (by passing `allowsEditing: true`). This is only applicable on\n * Android, since on iOS the crop rectangle is always a square.\n */\n aspect?: [number, number];\n /**\n * Specify the quality of compression, from `0` to `1`. `0` means compress for small size,\n * `1` means compress for maximum quality.\n * > Note: If the selected image has been compressed before, the size of the output file may be\n * > bigger than the size of the original image.\n *\n * > Note: On iOS, if a `.bmp` or `.png` image is selected from the library, this option is ignored.\n *\n * @default 0.2\n * @platform ios\n * @platform android\n */\n quality?: number;\n /**\n * Choose what type of media to pick.\n * @default ImagePicker.MediaTypeOptions.Images\n */\n mediaTypes?: MediaTypeOptions;\n /**\n * Whether to also include the EXIF data for the image. On iOS the EXIF data does not include GPS\n * tags in the camera case.\n */\n exif?: boolean;\n /**\n * Whether to also include the image data in Base64 format.\n */\n base64?: boolean;\n /**\n * Specify preset which will be used to compress selected video.\n * @default ImagePicker.VideoExportPreset.Passthrough\n * @platform ios 11+\n * @deprecated See [`videoExportPreset`](https://developer.apple.com/documentation/uikit/uiimagepickercontroller/2890964-videoexportpreset?language=objc)\n * in Apple documentation.\n */\n videoExportPreset?: VideoExportPreset;\n /**\n * Specify the quality of recorded videos. Defaults to the highest quality available for the device.\n * @default ImagePicker.UIImagePickerControllerQualityType.High\n * @platform ios\n */\n videoQuality?: UIImagePickerControllerQualityType;\n /**\n * Whether or not to allow selecting multiple media files at once.\n *\n * > Cropping multiple images is not supported - this option is mutually exclusive with `allowsEditing`.\n * > If this option is enabled, then `allowsEditing` is ignored.\n *\n * @default false\n * @platform ios 14+\n * @platform web\n */\n allowsMultipleSelection?: boolean;\n /**\n * The maximum number of items that user can select. Applicable when `allowsMultipleSelection` is enabled.\n * Setting the value to `0` sets the selection limit to the maximum that the system supports.\n *\n * @platform ios 14+\n * @default 0\n */\n selectionLimit?: number;\n /**\n * Whether to display number badges when assets are selected. The badges are numbered\n * in selection order. Assets are then returned in the exact same order they were selected.\n *\n * > Assets should be returned in the selection order regardless of this option,\n * > but there is no guarantee that it is always true when this option is disabled.\n *\n * @platform ios 15+\n * @default false\n */\n orderedSelection?: boolean;\n /**\n * Maximum duration, in seconds, for video recording. Setting this to `0` disables the limit.\n * Defaults to `0` (no limit).\n * - **On iOS**, when `allowsEditing` is set to `true`, maximum duration is limited to 10 minutes.\n * This limit is applied automatically, if `0` or no value is specified.\n * - **On Android**, effect of this option depends on support of installed camera app.\n * - **On Web** this option has no effect - the limit is browser-dependant.\n */\n videoMaxDuration?: number;\n /**\n * Choose [presentation style](https://developer.apple.com/documentation/uikit/uiviewcontroller/1621355-modalpresentationstyle?language=objc)\n * to customize view during taking photo/video.\n * @default ImagePicker.UIImagePickerPresentationStyle.Automatic\n * @platform ios\n */\n presentationStyle?: UIImagePickerPresentationStyle;\n};\n\n// @needsAudit\nexport type OpenFileBrowserOptions = {\n /**\n * Choose what type of media to pick.\n * @default ImagePicker.MediaTypeOptions.Images\n */\n mediaTypes: MediaTypeOptions;\n // @docsMissing\n capture?: boolean;\n /**\n * Whether or not to allow selecting multiple media files at once.\n * @platform web\n */\n allowsMultipleSelection: boolean;\n /**\n * Whether to also include the image data in Base64 format.\n */\n base64: boolean;\n};\n\n// @needsAudit @docsMissing\nexport type ExpandImagePickerResult<T extends ImagePickerOptions | OpenFileBrowserOptions> =\n T extends {\n allowsMultipleSelection: true;\n }\n ? ImagePickerMultipleResult\n : ImagePickerResult;\n"]}
|
|
@@ -26,6 +26,12 @@ internal class MissingCameraPermissionException: Exception {
|
|
|
26
26
|
}
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
+
internal class MissingPhotoLibraryPermissionException: Exception {
|
|
30
|
+
override var reason: String {
|
|
31
|
+
"Missing photo library permission"
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
29
35
|
internal class CameraUnavailableOnSimulatorException: Exception {
|
|
30
36
|
override var reason: String {
|
|
31
37
|
"Camera not available on simulator"
|
|
@@ -63,6 +63,7 @@ internal protocol SelectedMediaInfo {
|
|
|
63
63
|
Represents a single selected image
|
|
64
64
|
*/
|
|
65
65
|
internal struct ImageInfo: SelectedMediaInfo {
|
|
66
|
+
let assetId: String?
|
|
66
67
|
let type: String = "image"
|
|
67
68
|
let uri: String
|
|
68
69
|
let width: Double
|
|
@@ -76,6 +77,7 @@ internal struct ImageInfo: SelectedMediaInfo {
|
|
|
76
77
|
var result: [String: Any] = [
|
|
77
78
|
"type": type,
|
|
78
79
|
"uri": uri,
|
|
80
|
+
"assetId": assetId,
|
|
79
81
|
"width": width,
|
|
80
82
|
"height": height,
|
|
81
83
|
"fileName": fileName,
|
|
@@ -95,6 +97,7 @@ internal struct ImageInfo: SelectedMediaInfo {
|
|
|
95
97
|
Represents a single selected video
|
|
96
98
|
*/
|
|
97
99
|
internal struct VideoInfo: SelectedMediaInfo {
|
|
100
|
+
let assetId: String?
|
|
98
101
|
let type: String = "video"
|
|
99
102
|
let uri: String
|
|
100
103
|
let width: Double
|
|
@@ -107,6 +110,7 @@ internal struct VideoInfo: SelectedMediaInfo {
|
|
|
107
110
|
[
|
|
108
111
|
"type": type,
|
|
109
112
|
"uri": uri,
|
|
113
|
+
"assetId": assetId,
|
|
110
114
|
"width": width,
|
|
111
115
|
"height": height,
|
|
112
116
|
"fileName": fileName,
|
package/ios/MediaHandler.swift
CHANGED
|
@@ -23,41 +23,38 @@ internal struct MediaHandler {
|
|
|
23
23
|
|
|
24
24
|
@available(iOS 14, *)
|
|
25
25
|
internal func handleMultipleMedia(_ selection: [PHPickerResult], completion: @escaping (ImagePickerResult) -> Void) {
|
|
26
|
-
var results
|
|
26
|
+
var results = Array<SelectedMediaInfo?>(repeating: nil, count: selection.count)
|
|
27
27
|
|
|
28
28
|
let dispatchGroup = DispatchGroup()
|
|
29
29
|
let dispatchQueue = DispatchQueue(label: "expo.imagepicker.multipleMediaHandler")
|
|
30
30
|
|
|
31
|
-
let resultHandler = { (
|
|
31
|
+
let resultHandler = { (index: Int, result: SelectedMediaResult) -> Void in
|
|
32
32
|
switch result {
|
|
33
33
|
case .failure(let exception):
|
|
34
34
|
return completion(.failure(exception))
|
|
35
35
|
case .success(let mediaInfo):
|
|
36
36
|
dispatchQueue.async {
|
|
37
|
-
results[
|
|
37
|
+
results[index] = mediaInfo
|
|
38
38
|
dispatchGroup.leave()
|
|
39
39
|
}
|
|
40
40
|
}
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
-
for
|
|
44
|
-
let itemProvider =
|
|
45
|
-
let id = item.assetIdentifier
|
|
43
|
+
for (index, selectedItem) in selection.enumerated() {
|
|
44
|
+
let itemProvider = selectedItem.itemProvider
|
|
46
45
|
|
|
47
46
|
dispatchGroup.enter()
|
|
48
47
|
if itemProvider.hasItemConformingToTypeIdentifier(UTType.image.identifier) {
|
|
49
|
-
handleImage(
|
|
48
|
+
handleImage(from: selectedItem, atIndex: index, completion: resultHandler)
|
|
50
49
|
} else if itemProvider.hasItemConformingToTypeIdentifier(UTType.movie.identifier) {
|
|
51
|
-
handleVideo(
|
|
50
|
+
handleVideo(from: selectedItem, atIndex: index, completion: resultHandler)
|
|
52
51
|
} else {
|
|
53
52
|
completion(.failure(InvalidMediaTypeException(itemProvider.registeredTypeIdentifiers.first)))
|
|
54
53
|
}
|
|
55
54
|
}
|
|
56
55
|
|
|
57
56
|
dispatchGroup.notify(queue: .main) {
|
|
58
|
-
|
|
59
|
-
let sortedResults = selection.map { results[$0.assetIdentifier!]! }
|
|
60
|
-
completion(.success(ImagePickerMultipleResponse(results: sortedResults)))
|
|
57
|
+
completion(.success(ImagePickerMultipleResponse(results: results.compactMap { $0 } )))
|
|
61
58
|
}
|
|
62
59
|
}
|
|
63
60
|
|
|
@@ -95,7 +92,8 @@ internal struct MediaHandler {
|
|
|
95
92
|
shouldReadBase64: self.options.base64)
|
|
96
93
|
|
|
97
94
|
ImageUtils.optionallyReadExifFrom(mediaInfo: mediaInfo, shouldReadExif: self.options.exif) { exif in
|
|
98
|
-
let result: ImagePickerSingleResponse = .image(ImageInfo(
|
|
95
|
+
let result: ImagePickerSingleResponse = .image(ImageInfo(assetId: asset?.localIdentifier,
|
|
96
|
+
uri: targetUrl.absoluteString,
|
|
99
97
|
width: image.size.width,
|
|
100
98
|
height: image.size.height,
|
|
101
99
|
fileName: fileName,
|
|
@@ -112,15 +110,16 @@ internal struct MediaHandler {
|
|
|
112
110
|
}
|
|
113
111
|
|
|
114
112
|
@available(iOS 14, *)
|
|
115
|
-
private func handleImage(
|
|
116
|
-
|
|
117
|
-
completion: @escaping (
|
|
113
|
+
private func handleImage(from selectedImage: PHPickerResult,
|
|
114
|
+
atIndex index: Int = -1,
|
|
115
|
+
completion: @escaping (Int, SelectedMediaResult) -> Void) {
|
|
116
|
+
let itemProvider = selectedImage.itemProvider
|
|
118
117
|
itemProvider.loadDataRepresentation(forTypeIdentifier: UTType.image.identifier) { rawData, error in
|
|
119
118
|
do {
|
|
120
119
|
guard error == nil,
|
|
121
120
|
let rawData = rawData,
|
|
122
121
|
let image = try? UIImage(data: rawData) else {
|
|
123
|
-
return completion(
|
|
122
|
+
return completion(index, .failure(FailedToReadImageException().causedBy(error)))
|
|
124
123
|
}
|
|
125
124
|
|
|
126
125
|
let (imageData, fileExtension) = try ImageUtils.readDataAndFileExtension(image: image,
|
|
@@ -140,18 +139,19 @@ internal struct MediaHandler {
|
|
|
140
139
|
tryReadingFile: false,
|
|
141
140
|
shouldReadBase64: self.options.base64)
|
|
142
141
|
|
|
143
|
-
let result = ImageInfo(
|
|
142
|
+
let result = ImageInfo(assetId: selectedImage.assetIdentifier,
|
|
143
|
+
uri: targetUrl.absoluteString,
|
|
144
144
|
width: image.size.width,
|
|
145
145
|
height: image.size.height,
|
|
146
146
|
fileName: fileName,
|
|
147
147
|
fileSize: fileSize,
|
|
148
148
|
base64: base64,
|
|
149
149
|
exif: exif)
|
|
150
|
-
completion(
|
|
150
|
+
completion(index, .success(result))
|
|
151
151
|
} catch let exception as Exception {
|
|
152
|
-
return completion(
|
|
152
|
+
return completion(index, .failure(exception))
|
|
153
153
|
} catch {
|
|
154
|
-
return completion(
|
|
154
|
+
return completion(index, .failure(UnexpectedException(error)))
|
|
155
155
|
}
|
|
156
156
|
} // loadObject
|
|
157
157
|
}
|
|
@@ -183,7 +183,8 @@ internal struct MediaHandler {
|
|
|
183
183
|
let fileName = asset?.value(forKey: "filename") as? String
|
|
184
184
|
let fileSize = getFileSize(from: targetUrl)
|
|
185
185
|
|
|
186
|
-
let result: ImagePickerSingleResponse = .video(VideoInfo(
|
|
186
|
+
let result: ImagePickerSingleResponse = .video(VideoInfo(assetId: asset?.localIdentifier,
|
|
187
|
+
uri: targetUrl.absoluteString,
|
|
187
188
|
width: dimensions.width,
|
|
188
189
|
height: dimensions.height,
|
|
189
190
|
fileName: fileName,
|
|
@@ -198,14 +199,15 @@ internal struct MediaHandler {
|
|
|
198
199
|
}
|
|
199
200
|
|
|
200
201
|
@available(iOS 14, *)
|
|
201
|
-
private func handleVideo(
|
|
202
|
-
|
|
203
|
-
completion: @escaping (
|
|
202
|
+
private func handleVideo(from selectedVideo: PHPickerResult,
|
|
203
|
+
atIndex index: Int = -1,
|
|
204
|
+
completion: @escaping (Int, SelectedMediaResult) -> Void) {
|
|
205
|
+
let itemProvider = selectedVideo.itemProvider
|
|
204
206
|
itemProvider.loadFileRepresentation(forTypeIdentifier: UTType.movie.identifier) { [self] url, error in
|
|
205
207
|
do {
|
|
206
208
|
guard error == nil,
|
|
207
209
|
let videoUrl = url as? URL else {
|
|
208
|
-
return completion(
|
|
210
|
+
return completion(index, .failure(FailedToReadVideoException().causedBy(error)))
|
|
209
211
|
}
|
|
210
212
|
|
|
211
213
|
// In case of passthrough, we want original file extension, mp4 otherwise
|
|
@@ -227,17 +229,17 @@ internal struct MediaHandler {
|
|
|
227
229
|
exportPreset: options.videoExportPreset) { result in
|
|
228
230
|
switch result {
|
|
229
231
|
case .failure(let exception):
|
|
230
|
-
return completion(
|
|
232
|
+
return completion(index, .failure(exception))
|
|
231
233
|
case .success(let targetUrl):
|
|
232
234
|
let fileName = itemProvider.suggestedName.map { $0 + transcodeFileExtension }
|
|
233
|
-
let videoResult = buildVideoResult(for: targetUrl, withName: fileName)
|
|
234
|
-
return completion(
|
|
235
|
+
let videoResult = buildVideoResult(for: targetUrl, withName: fileName, assetId: selectedVideo.assetIdentifier)
|
|
236
|
+
return completion(index, videoResult)
|
|
235
237
|
}
|
|
236
238
|
}
|
|
237
239
|
} catch let exception as Exception {
|
|
238
|
-
return completion(
|
|
240
|
+
return completion(index, .failure(exception))
|
|
239
241
|
} catch {
|
|
240
|
-
return completion(
|
|
242
|
+
return completion(index, .failure(UnexpectedException(error)))
|
|
241
243
|
}
|
|
242
244
|
}
|
|
243
245
|
}
|
|
@@ -255,15 +257,16 @@ internal struct MediaHandler {
|
|
|
255
257
|
let url = URL(fileURLWithPath: path)
|
|
256
258
|
return url
|
|
257
259
|
}
|
|
258
|
-
|
|
259
|
-
private func buildVideoResult(for videoUrl: URL, withName fileName: String
|
|
260
|
+
|
|
261
|
+
private func buildVideoResult(for videoUrl: URL, withName fileName: String?, assetId: String?) -> SelectedMediaResult {
|
|
260
262
|
guard let size = VideoUtils.readSizeFrom(url: videoUrl) else {
|
|
261
263
|
return .failure(FailedToReadVideoSizeException())
|
|
262
264
|
}
|
|
263
265
|
let duration = VideoUtils.readDurationFrom(url: videoUrl)
|
|
264
266
|
let fileSize = getFileSize(from: videoUrl)
|
|
265
267
|
|
|
266
|
-
let result = VideoInfo(
|
|
268
|
+
let result = VideoInfo(assetId: assetId,
|
|
269
|
+
uri: videoUrl.absoluteString,
|
|
267
270
|
width: size.width,
|
|
268
271
|
height: size.height,
|
|
269
272
|
fileName: fileName,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "expo-image-picker",
|
|
3
|
-
"version": "13.
|
|
3
|
+
"version": "13.3.0",
|
|
4
4
|
"description": "Provides access to the system's UI for selecting images and videos from the phone's library or taking a photo with the camera.",
|
|
5
5
|
"main": "build/ImagePicker.js",
|
|
6
6
|
"types": "build/ImagePicker.d.ts",
|
|
@@ -46,5 +46,5 @@
|
|
|
46
46
|
"peerDependencies": {
|
|
47
47
|
"expo": "*"
|
|
48
48
|
},
|
|
49
|
-
"gitHead": "
|
|
49
|
+
"gitHead": "c6678c65b68e45062d49a2deea8e822f69388278"
|
|
50
50
|
}
|
package/src/ImagePicker.ts
CHANGED
|
@@ -181,7 +181,7 @@ export async function getPendingResultAsync(): Promise<
|
|
|
181
181
|
/**
|
|
182
182
|
* Display the system UI for taking a photo with the camera. Requires `Permissions.CAMERA`.
|
|
183
183
|
* On Android and iOS 10 `Permissions.CAMERA_ROLL` is also required. On mobile web, this must be
|
|
184
|
-
* called immediately in a user interaction like a button press, otherwise the browser will
|
|
184
|
+
* called immediately in a user interaction like a button press, otherwise the browser will block
|
|
185
185
|
* the request without a warning.
|
|
186
186
|
* > **Note:** Make sure that you handle `MainActivity` destruction on **Android**. See [ImagePicker.getPendingResultAsync](#imagepickergetpendingresultasync).
|
|
187
187
|
* > **Notes for Web:** The system UI can only be shown after user activation (e.g. a `Button` press).
|
package/src/ImagePicker.types.ts
CHANGED
|
@@ -220,6 +220,17 @@ export type ImageInfo = {
|
|
|
220
220
|
* an image) and `width` and `height` specify the dimensions of the media.
|
|
221
221
|
*/
|
|
222
222
|
uri: string;
|
|
223
|
+
/**
|
|
224
|
+
* The unique ID that represents the picked image or video, if picked from the library. It can be used
|
|
225
|
+
* by [expo-media-library](./media-library) to manage the picked asset.
|
|
226
|
+
*
|
|
227
|
+
* > This might be `null` when the ID is unavailable or the user gave limited permission to access the media library.
|
|
228
|
+
* > On Android, the ID is unavailable when the user selects a photo by directly browsing file system.
|
|
229
|
+
*
|
|
230
|
+
* @platform ios
|
|
231
|
+
* @platform android
|
|
232
|
+
*/
|
|
233
|
+
assetId?: string | null;
|
|
223
234
|
/**
|
|
224
235
|
* Width of the image or video.
|
|
225
236
|
*/
|