@capacitor/camera 8.1.0-test.250320251731 → 8.1.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/CapacitorCamera.podspec +3 -2
- package/Package.swift +4 -2
- package/README.md +419 -67
- package/android/build.gradle +4 -4
- package/android/src/main/AndroidManifest.xml +6 -0
- package/android/src/main/java/com/capacitorjs/plugins/camera/CameraPlugin.kt +3 -2
- package/android/src/main/java/com/capacitorjs/plugins/camera/IonCameraFlow.kt +111 -70
- package/android/src/main/java/com/capacitorjs/plugins/camera/IonCameraSettings.kt +1 -2
- package/android/src/main/java/com/capacitorjs/plugins/camera/IonEditableMode.kt +16 -0
- package/android/src/main/java/com/capacitorjs/plugins/camera/IonGallerySettings.kt +1 -2
- package/dist/docs.json +18 -50
- package/dist/esm/definitions.d.ts +22 -37
- package/dist/esm/definitions.js.map +1 -1
- package/dist/esm/web.d.ts +13 -2
- package/dist/esm/web.js +280 -39
- package/dist/esm/web.js.map +1 -1
- package/dist/plugin.cjs.js +279 -38
- package/dist/plugin.cjs.js.map +1 -1
- package/dist/plugin.js +279 -38
- package/dist/plugin.js.map +1 -1
- package/ios/Sources/CameraPlugin/CameraPlugin.swift +193 -9
- package/package.json +10 -5
- package/android/libs/IONCameraLib-debug.aar +0 -0
- package/android/src/main/java/com/capacitorjs/plugins/camera/IonVideoSettings.kt +0 -7
package/android/build.gradle
CHANGED
|
@@ -30,8 +30,8 @@ apply plugin: 'com.android.library'
|
|
|
30
30
|
apply plugin: 'kotlin-android'
|
|
31
31
|
if (System.getenv("CAP_PLUGIN_PUBLISH") == "true") {
|
|
32
32
|
apply plugin: 'io.github.gradle-nexus.publish-plugin'
|
|
33
|
-
apply from: file('
|
|
34
|
-
apply from: file('
|
|
33
|
+
apply from: file('../scripts/android/publish-root.gradle')
|
|
34
|
+
apply from: file('../scripts/android/publish-module.gradle')
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
android {
|
|
@@ -74,6 +74,8 @@ repositories {
|
|
|
74
74
|
|
|
75
75
|
dependencies {
|
|
76
76
|
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
|
77
|
+
|
|
78
|
+
implementation 'io.ionic.libs:ioncamera-android:1.0.0'
|
|
77
79
|
|
|
78
80
|
if (System.getenv("CAP_PLUGIN_PUBLISH") == "true") {
|
|
79
81
|
implementation "com.capacitorjs:core:$capacitorVersion"
|
|
@@ -89,6 +91,4 @@ dependencies {
|
|
|
89
91
|
androidTestImplementation "androidx.test.ext:junit:$androidxJunitVersion"
|
|
90
92
|
androidTestImplementation "androidx.test.espresso:espresso-core:$androidxEspressoCoreVersion"
|
|
91
93
|
implementation 'com.google.code.gson:gson:2.10.1'
|
|
92
|
-
//implementation project(':gradle-project-test')
|
|
93
|
-
implementation files('libs/IONCameraLib-debug.aar')
|
|
94
94
|
}
|
|
@@ -3,5 +3,11 @@
|
|
|
3
3
|
<intent>
|
|
4
4
|
<action android:name="android.media.action.IMAGE_CAPTURE" />
|
|
5
5
|
</intent>
|
|
6
|
+
<intent>
|
|
7
|
+
<action android:name="android.intent.action.GET_CONTENT" />
|
|
8
|
+
</intent>
|
|
9
|
+
<intent>
|
|
10
|
+
<action android:name="android.intent.action.PICK" />
|
|
11
|
+
</intent>
|
|
6
12
|
</queries>
|
|
7
13
|
</manifest>
|
|
@@ -90,7 +90,7 @@ class CameraPlugin : Plugin() {
|
|
|
90
90
|
ionFlow.load()
|
|
91
91
|
}
|
|
92
92
|
|
|
93
|
-
|
|
93
|
+
@Deprecated("Use either takePhoto for CameraSource.Camera or chooseFromGallery for CameraSource.Photos")
|
|
94
94
|
@PluginMethod
|
|
95
95
|
fun getPhoto(call: PluginCall) {
|
|
96
96
|
legacyFlow.getPhoto(call)
|
|
@@ -126,6 +126,7 @@ class CameraPlugin : Plugin() {
|
|
|
126
126
|
ionFlow.editURIPhoto(call)
|
|
127
127
|
}
|
|
128
128
|
|
|
129
|
+
@Deprecated("Use chooseFromGallery instead")
|
|
129
130
|
@PluginMethod
|
|
130
131
|
fun pickImages(call: PluginCall) {
|
|
131
132
|
legacyFlow.pickImages(call)
|
|
@@ -160,7 +161,7 @@ class CameraPlugin : Plugin() {
|
|
|
160
161
|
*/
|
|
161
162
|
@PermissionCallback
|
|
162
163
|
private fun ionCameraPermissionsCallback(call: PluginCall) {
|
|
163
|
-
ionFlow.
|
|
164
|
+
ionFlow.handlePermissionsCallback(call)
|
|
164
165
|
}
|
|
165
166
|
|
|
166
167
|
override fun requestPermissionForAliases(
|
|
@@ -33,6 +33,7 @@ import io.ionic.libs.ioncameralib.manager.IONCAMRGalleryManager
|
|
|
33
33
|
import io.ionic.libs.ioncameralib.manager.IONCAMRVideoManager
|
|
34
34
|
import io.ionic.libs.ioncameralib.model.IONCAMRCameraParameters
|
|
35
35
|
import io.ionic.libs.ioncameralib.model.IONCAMREditParameters
|
|
36
|
+
import io.ionic.libs.ioncameralib.model.IONCAMRVideoParameters
|
|
36
37
|
import io.ionic.libs.ioncameralib.model.IONCAMRError
|
|
37
38
|
import io.ionic.libs.ioncameralib.model.IONCAMRMediaResult
|
|
38
39
|
import io.ionic.libs.ioncameralib.model.IONCAMRMediaType
|
|
@@ -62,11 +63,11 @@ class IonCameraFlow(
|
|
|
62
63
|
private lateinit var editLauncher: ActivityResultLauncher<Intent>
|
|
63
64
|
private var currentCall: PluginCall? = null
|
|
64
65
|
private var cameraSettings: IonCameraSettings? = null
|
|
65
|
-
private var videoSettings: IonVideoSettings? = null
|
|
66
66
|
private var gallerySettings: IonGallerySettings? = null
|
|
67
67
|
private var editParameters = IONCAMREditParameters(
|
|
68
68
|
editURI = "", fromUri = false, saveToGallery = false, includeMetadata = false
|
|
69
69
|
)
|
|
70
|
+
private var videoParameters: IONCAMRVideoParameters? = null
|
|
70
71
|
private var lastEditUri: String? = null
|
|
71
72
|
|
|
72
73
|
companion object {
|
|
@@ -118,7 +119,7 @@ class IonCameraFlow(
|
|
|
118
119
|
}
|
|
119
120
|
|
|
120
121
|
fun recordVideo(call: PluginCall) {
|
|
121
|
-
|
|
122
|
+
videoParameters = getVideoSettings(call)
|
|
122
123
|
currentCall = call
|
|
123
124
|
openRecordVideo(call)
|
|
124
125
|
}
|
|
@@ -186,8 +187,8 @@ class IonCameraFlow(
|
|
|
186
187
|
|
|
187
188
|
}
|
|
188
189
|
|
|
189
|
-
fun getVideoSettings(call: PluginCall):
|
|
190
|
-
return
|
|
190
|
+
fun getVideoSettings(call: PluginCall): IONCAMRVideoParameters {
|
|
191
|
+
return IONCAMRVideoParameters(
|
|
191
192
|
saveToGallery = call.getBoolean("saveToGallery") ?: false,
|
|
192
193
|
includeMetadata = call.getBoolean("includeMetadata") ?: false,
|
|
193
194
|
isPersistent = call.getBoolean("isPersistent") ?: true
|
|
@@ -200,8 +201,7 @@ class IonCameraFlow(
|
|
|
200
201
|
allowMultipleSelection = call.getBoolean("allowMultipleSelection") ?: false,
|
|
201
202
|
limit = call.getInt("limit") ?: 0,
|
|
202
203
|
includeMetadata = call.getBoolean("includeMetadata") ?: false,
|
|
203
|
-
|
|
204
|
-
editInApp = call.getBoolean("editInApp") ?: true,
|
|
204
|
+
editable = IonEditableMode.fromString(call.getString("editable")),
|
|
205
205
|
quality = call.getInt("quality") ?: DEFAULT_QUALITY,
|
|
206
206
|
width = call.getInt("targetWidth") ?: 0,
|
|
207
207
|
height = call.getInt("targetHeight") ?: 0,
|
|
@@ -214,8 +214,7 @@ class IonCameraFlow(
|
|
|
214
214
|
var allowMultipleSelection: Boolean = false,
|
|
215
215
|
var limit: Int = 0,
|
|
216
216
|
var includeMetadata: Boolean = false,
|
|
217
|
-
var
|
|
218
|
-
var editInApp: Boolean = true,
|
|
217
|
+
var editable: IonEditableMode = IonEditableMode.NO,
|
|
219
218
|
var quality: Int = 90,
|
|
220
219
|
var width: Int = 0,
|
|
221
220
|
var height: Int = 0,
|
|
@@ -234,8 +233,7 @@ class IonCameraFlow(
|
|
|
234
233
|
settings.correctOrientation = call.getBoolean("correctOrientation") ?: IonCameraSettings.DEFAULT_CORRECT_ORIENTATION
|
|
235
234
|
settings.encodingType = call.getInt("encodingType") ?: IonCameraSettings.DEFAULT_ENCODING_TYPE
|
|
236
235
|
settings.saveToGallery = call.getBoolean("saveToGallery") ?: IonCameraSettings.DEFAULT_SAVE_IMAGE_TO_GALLERY
|
|
237
|
-
settings.
|
|
238
|
-
settings.editInApp = call.getBoolean("editInApp") ?: true
|
|
236
|
+
settings.editable = IonEditableMode.fromString(call.getString("editable"))
|
|
239
237
|
settings.includeMetadata = call.getBoolean("includeMetadata") ?: false
|
|
240
238
|
settings.shouldResize = settings.targetWidth > 0 || settings.targetHeight > 0
|
|
241
239
|
return settings
|
|
@@ -267,13 +265,13 @@ class IonCameraFlow(
|
|
|
267
265
|
currentCall = call
|
|
268
266
|
manager.takePhoto(activity, settings.encodingType, cameraLauncher)
|
|
269
267
|
} catch (ex: Exception) {
|
|
270
|
-
sendError(IONCAMRError.
|
|
268
|
+
sendError(IONCAMRError.TAKE_PHOTO_ERROR)
|
|
271
269
|
}
|
|
272
270
|
}
|
|
273
271
|
}
|
|
274
272
|
|
|
275
273
|
fun openRecordVideo(call: PluginCall) {
|
|
276
|
-
val settings =
|
|
274
|
+
val settings = videoParameters ?: run {
|
|
277
275
|
sendError(IONCAMRError.INVALID_ARGUMENT_ERROR)
|
|
278
276
|
return
|
|
279
277
|
}
|
|
@@ -293,7 +291,7 @@ class IonCameraFlow(
|
|
|
293
291
|
sendError(it)
|
|
294
292
|
}
|
|
295
293
|
} catch (ex: Exception) {
|
|
296
|
-
sendError(IONCAMRError.
|
|
294
|
+
sendError(IONCAMRError.CAPTURE_VIDEO_ERROR)
|
|
297
295
|
}
|
|
298
296
|
}
|
|
299
297
|
}
|
|
@@ -319,6 +317,8 @@ class IonCameraFlow(
|
|
|
319
317
|
}
|
|
320
318
|
|
|
321
319
|
private fun openGallery(call: PluginCall) {
|
|
320
|
+
if (!checkGalleryPermissions(call)) return
|
|
321
|
+
|
|
322
322
|
val manager = galleryManager ?: run {
|
|
323
323
|
sendError(IONCAMRError.CONTEXT_ERROR)
|
|
324
324
|
return
|
|
@@ -350,8 +350,12 @@ class IonCameraFlow(
|
|
|
350
350
|
saveToGallery = false,
|
|
351
351
|
includeMetadata = false
|
|
352
352
|
)
|
|
353
|
+
|
|
353
354
|
val imageBase64 = call.getString("inputImage")
|
|
354
|
-
if (imageBase64
|
|
355
|
+
if (imageBase64.isNullOrEmpty()) {
|
|
356
|
+
sendError(IONCAMRError.INVALID_ARGUMENT_ERROR)
|
|
357
|
+
return
|
|
358
|
+
}
|
|
355
359
|
manager.editImage(activity, imageBase64, editLauncher)
|
|
356
360
|
}
|
|
357
361
|
|
|
@@ -385,10 +389,11 @@ class IonCameraFlow(
|
|
|
385
389
|
sendError(IONCAMRError.INVALID_ARGUMENT_ERROR)
|
|
386
390
|
return
|
|
387
391
|
}
|
|
388
|
-
|
|
389
|
-
|
|
392
|
+
when (settings.editable) {
|
|
393
|
+
IonEditableMode.IN_APP -> {
|
|
390
394
|
editPhoto()
|
|
391
|
-
}
|
|
395
|
+
}
|
|
396
|
+
IonEditableMode.EXTERNAL -> {
|
|
392
397
|
val editor = editManager ?: run {
|
|
393
398
|
sendError(IONCAMRError.CONTEXT_ERROR)
|
|
394
399
|
return
|
|
@@ -415,8 +420,9 @@ class IonCameraFlow(
|
|
|
415
420
|
editPhoto()
|
|
416
421
|
}
|
|
417
422
|
}
|
|
418
|
-
|
|
419
|
-
|
|
423
|
+
IonEditableMode.NO -> {
|
|
424
|
+
processResult(result.data)
|
|
425
|
+
}
|
|
420
426
|
}
|
|
421
427
|
}
|
|
422
428
|
Activity.RESULT_CANCELED -> {
|
|
@@ -465,36 +471,40 @@ class IonCameraFlow(
|
|
|
465
471
|
return
|
|
466
472
|
}
|
|
467
473
|
|
|
468
|
-
if (settings.
|
|
474
|
+
if (settings.editable != IonEditableMode.NO && uris.size == 1 && settings.mediaType == IONCAMRMediaType.PICTURE) {
|
|
469
475
|
val originalUri = uris.first()
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
activity,
|
|
473
|
-
originalUri,
|
|
474
|
-
galleryCropLauncher
|
|
475
|
-
)
|
|
476
|
-
} else {
|
|
477
|
-
val tempUri = if (originalUri.scheme == "content") {
|
|
478
|
-
IonCameraUtils.getGalleryTempImage(activity, originalUri)
|
|
479
|
-
} else {
|
|
480
|
-
originalUri
|
|
481
|
-
}
|
|
482
|
-
|
|
483
|
-
if (tempUri == null) {
|
|
484
|
-
sendError(IONCAMRError.EDIT_IMAGE_ERROR)
|
|
485
|
-
return
|
|
486
|
-
}
|
|
487
|
-
|
|
488
|
-
val editIntent = createEditIntent(tempUri)
|
|
489
|
-
if (editIntent != null) {
|
|
490
|
-
galleryCropLauncher.launch(editIntent)
|
|
491
|
-
} else {
|
|
476
|
+
when (settings.editable) {
|
|
477
|
+
IonEditableMode.IN_APP -> {
|
|
492
478
|
editor.openCropActivity(
|
|
493
479
|
activity,
|
|
494
480
|
originalUri,
|
|
495
481
|
galleryCropLauncher
|
|
496
482
|
)
|
|
497
483
|
}
|
|
484
|
+
IonEditableMode.EXTERNAL -> {
|
|
485
|
+
val tempUri = if (originalUri.scheme == "content") {
|
|
486
|
+
IonCameraUtils.getGalleryTempImage(activity, originalUri)
|
|
487
|
+
} else {
|
|
488
|
+
originalUri
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
if (tempUri == null) {
|
|
492
|
+
sendError(IONCAMRError.EDIT_IMAGE_ERROR)
|
|
493
|
+
return
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
val editIntent = createEditIntent(tempUri)
|
|
497
|
+
if (editIntent != null) {
|
|
498
|
+
galleryCropLauncher.launch(editIntent)
|
|
499
|
+
} else {
|
|
500
|
+
editor.openCropActivity(
|
|
501
|
+
activity,
|
|
502
|
+
originalUri,
|
|
503
|
+
galleryCropLauncher
|
|
504
|
+
)
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
else -> {}
|
|
498
508
|
}
|
|
499
509
|
} else {
|
|
500
510
|
processResultFromGallery(result)
|
|
@@ -531,14 +541,14 @@ class IonCameraFlow(
|
|
|
531
541
|
lastEditUri = null
|
|
532
542
|
}
|
|
533
543
|
Activity.RESULT_CANCELED -> {
|
|
534
|
-
if (
|
|
544
|
+
if (settings.editable == IonEditableMode.EXTERNAL && !lastEditUri.isNullOrEmpty()) {
|
|
535
545
|
val intent = Intent().apply {
|
|
536
546
|
putExtra(IONCAMRImageEditorActivity.IMAGE_OUTPUT_URI_EXTRAS, lastEditUri)
|
|
537
547
|
}
|
|
538
548
|
processResultEditFromGallery(intent)
|
|
539
549
|
} else {
|
|
540
550
|
lastEditUri = null
|
|
541
|
-
sendError(IONCAMRError.
|
|
551
|
+
sendError(IONCAMRError.EDIT_CANCELLED_ERROR)
|
|
542
552
|
}
|
|
543
553
|
}
|
|
544
554
|
else -> sendError(IONCAMRError.EDIT_IMAGE_ERROR)
|
|
@@ -571,7 +581,7 @@ class IonCameraFlow(
|
|
|
571
581
|
private fun handleEditResult(result: ActivityResult) {
|
|
572
582
|
when (result.resultCode) {
|
|
573
583
|
Activity.RESULT_OK -> processResultFromEdit(result)
|
|
574
|
-
Activity.RESULT_CANCELED -> sendError(IONCAMRError.
|
|
584
|
+
Activity.RESULT_CANCELED -> sendError(IONCAMRError.EDIT_CANCELLED_ERROR)
|
|
575
585
|
else -> sendError(IONCAMRError.EDIT_IMAGE_ERROR)
|
|
576
586
|
}
|
|
577
587
|
}
|
|
@@ -689,14 +699,14 @@ class IonCameraFlow(
|
|
|
689
699
|
lastEditUri = null
|
|
690
700
|
}
|
|
691
701
|
Activity.RESULT_CANCELED -> {
|
|
692
|
-
if (
|
|
702
|
+
if (settings.editable == IonEditableMode.EXTERNAL && !lastEditUri.isNullOrEmpty()) {
|
|
693
703
|
val intent = Intent().apply {
|
|
694
704
|
putExtra(IONCAMRImageEditorActivity.IMAGE_OUTPUT_URI_EXTRAS, lastEditUri)
|
|
695
705
|
}
|
|
696
706
|
processResult(intent)
|
|
697
707
|
} else {
|
|
698
708
|
lastEditUri = null
|
|
699
|
-
sendError(IONCAMRError.
|
|
709
|
+
sendError(IONCAMRError.EDIT_CANCELLED_ERROR)
|
|
700
710
|
}
|
|
701
711
|
}
|
|
702
712
|
else -> sendError(IONCAMRError.EDIT_IMAGE_ERROR)
|
|
@@ -727,18 +737,17 @@ class IonCameraFlow(
|
|
|
727
737
|
ret.put("webPath", FileUtils.getPortablePath(context, bridge.localUrl, uri))
|
|
728
738
|
ret.put("saved", mediaResult.saved)
|
|
729
739
|
|
|
730
|
-
val metadata = JSObject()
|
|
731
740
|
mediaResult.metadata?.let {
|
|
741
|
+
val metadata = JSObject()
|
|
732
742
|
metadata.put("duration", it.duration)
|
|
733
743
|
metadata.put("size", it.size)
|
|
734
744
|
metadata.put("format", it.format)
|
|
735
745
|
metadata.put("resolution", it.resolution)
|
|
736
746
|
metadata.put("creationDate", it.creationDate)
|
|
737
747
|
metadata.put("exif", exif.toJson())
|
|
748
|
+
ret.put("metadata", metadata)
|
|
738
749
|
}
|
|
739
750
|
|
|
740
|
-
ret.put("metadata", metadata)
|
|
741
|
-
|
|
742
751
|
currentCall?.resolve(ret)
|
|
743
752
|
currentCall = null
|
|
744
753
|
lastEditUri = null
|
|
@@ -755,17 +764,16 @@ class IonCameraFlow(
|
|
|
755
764
|
ret.put("webPath", FileUtils.getPortablePath(context, bridge.localUrl, uri))
|
|
756
765
|
ret.put("saved", mediaResult.saved)
|
|
757
766
|
|
|
758
|
-
val metadata = JSObject()
|
|
759
767
|
mediaResult.metadata?.let {
|
|
768
|
+
val metadata = JSObject()
|
|
760
769
|
metadata.put("duration", it.duration)
|
|
761
770
|
metadata.put("size", it.size)
|
|
762
771
|
metadata.put("format", it.format)
|
|
763
772
|
metadata.put("resolution", it.resolution)
|
|
764
773
|
metadata.put("creationDate", it.creationDate)
|
|
774
|
+
ret.put("metadata", metadata)
|
|
765
775
|
}
|
|
766
776
|
|
|
767
|
-
ret.put("metadata", metadata)
|
|
768
|
-
|
|
769
777
|
currentCall?.resolve(ret)
|
|
770
778
|
currentCall = null
|
|
771
779
|
}
|
|
@@ -786,27 +794,27 @@ class IonCameraFlow(
|
|
|
786
794
|
FileUtils.getPortablePath(context, bridge.localUrl, uri)
|
|
787
795
|
)
|
|
788
796
|
|
|
789
|
-
val metadata = JSObject()
|
|
790
797
|
mediaResult.metadata?.let {
|
|
798
|
+
val metadata = JSObject()
|
|
791
799
|
metadata.put("duration", it.duration)
|
|
792
800
|
metadata.put("size", it.size)
|
|
793
801
|
metadata.put("format", it.format)
|
|
794
802
|
metadata.put("resolution", it.resolution)
|
|
795
803
|
metadata.put("creationDate", it.creationDate)
|
|
796
|
-
}
|
|
797
804
|
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
805
|
+
if (mediaResult.type == IONCAMRMediaType.PICTURE.type) {
|
|
806
|
+
val bitmap = BitmapFactory.decodeFile(mediaResult.uri)
|
|
807
|
+
if (bitmap == null) {
|
|
808
|
+
sendError(IONCAMRError.PROCESS_IMAGE_ERROR)
|
|
809
|
+
return
|
|
810
|
+
}
|
|
811
|
+
|
|
812
|
+
val exif = ImageUtils.getExifData(context, bitmap, uri)
|
|
813
|
+
metadata.put("exif", exif.toJson())
|
|
803
814
|
}
|
|
804
815
|
|
|
805
|
-
|
|
806
|
-
metadata.put("exif", exif.toJson())
|
|
816
|
+
ret.put("metadata", metadata)
|
|
807
817
|
}
|
|
808
|
-
|
|
809
|
-
ret.put("metadata", metadata)
|
|
810
818
|
photos.put(ret)
|
|
811
819
|
}
|
|
812
820
|
|
|
@@ -857,7 +865,7 @@ class IonCameraFlow(
|
|
|
857
865
|
sendError(IONCAMRError.CAPTURE_VIDEO_ERROR)
|
|
858
866
|
return
|
|
859
867
|
}
|
|
860
|
-
val settings =
|
|
868
|
+
val settings = videoParameters ?: run {
|
|
861
869
|
sendError(IONCAMRError.INVALID_ARGUMENT_ERROR)
|
|
862
870
|
return
|
|
863
871
|
}
|
|
@@ -931,10 +939,10 @@ class IonCameraFlow(
|
|
|
931
939
|
targetHeight = targetHeight,
|
|
932
940
|
encodingType = encodingType,
|
|
933
941
|
mediaType = MEDIA_TYPE_PHOTO,
|
|
934
|
-
allowEdit =
|
|
942
|
+
allowEdit = editable != IonEditableMode.NO,
|
|
935
943
|
correctOrientation = correctOrientation,
|
|
936
944
|
saveToPhotoAlbum = saveToGallery,
|
|
937
|
-
includeMetadata = includeMetadata
|
|
945
|
+
includeMetadata = includeMetadata,
|
|
938
946
|
)
|
|
939
947
|
}
|
|
940
948
|
|
|
@@ -982,13 +990,46 @@ class IonCameraFlow(
|
|
|
982
990
|
return true
|
|
983
991
|
}
|
|
984
992
|
|
|
985
|
-
fun
|
|
986
|
-
|
|
993
|
+
private fun checkGalleryPermissions(call: PluginCall): Boolean {
|
|
994
|
+
// Android 10+ does not require storage permissions to use the system gallery picker
|
|
995
|
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
|
996
|
+
return true
|
|
997
|
+
}
|
|
998
|
+
val needGalleryPerms = permissionHelper.isPermissionDeclared(SAVE_GALLERY)
|
|
999
|
+
val hasGalleryPerms = !needGalleryPerms || permissionHelper.getPermissionState(SAVE_GALLERY) == PermissionState.GRANTED
|
|
1000
|
+
if (!hasGalleryPerms) {
|
|
1001
|
+
permissionHelper.requestPermissionForAlias(SAVE_GALLERY, call, "ionCameraPermissionsCallback")
|
|
1002
|
+
return false
|
|
1003
|
+
}
|
|
1004
|
+
return true
|
|
1005
|
+
}
|
|
1006
|
+
|
|
1007
|
+
fun handlePermissionsCallback(call: PluginCall) {
|
|
1008
|
+
// chooseFromGallery does not require CAMERA permission
|
|
1009
|
+
if (call.methodName != "chooseFromGallery" &&
|
|
1010
|
+
permissionHelper.getPermissionState(CAMERA) != PermissionState.GRANTED) {
|
|
987
1011
|
sendError(IONCAMRError.CAMERA_PERMISSION_DENIED_ERROR)
|
|
988
1012
|
return
|
|
989
1013
|
}
|
|
990
1014
|
|
|
991
|
-
|
|
1015
|
+
// On Android <= 9, SAVE_GALLERY (READ/WRITE_EXTERNAL_STORAGE) is required:
|
|
1016
|
+
// - for takePhoto/recordVideo when saveToGallery is true
|
|
1017
|
+
// - always for chooseFromGallery (READ_EXTERNAL_STORAGE is needed to access the gallery)
|
|
1018
|
+
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
|
|
1019
|
+
val needsGalleryPerm = when (call.methodName) {
|
|
1020
|
+
"takePhoto" -> cameraSettings?.saveToGallery ?: false
|
|
1021
|
+
"recordVideo" -> videoParameters?.saveToGallery ?: false
|
|
1022
|
+
"chooseFromGallery" -> true
|
|
1023
|
+
else -> false
|
|
1024
|
+
}
|
|
1025
|
+
val galleryPermDeclared = permissionHelper.isPermissionDeclared(SAVE_GALLERY)
|
|
1026
|
+
if (needsGalleryPerm && galleryPermDeclared && permissionHelper.getPermissionState(SAVE_GALLERY) != PermissionState.GRANTED) {
|
|
1027
|
+
sendError(IONCAMRError.GALLERY_PERMISSION_DENIED_ERROR)
|
|
1028
|
+
return
|
|
1029
|
+
}
|
|
1030
|
+
}
|
|
1031
|
+
|
|
1032
|
+
when (call.methodName) {
|
|
992
1033
|
"takePhoto" -> openCamera(call)
|
|
993
1034
|
"recordVideo" -> openRecordVideo(call)
|
|
994
1035
|
"chooseFromGallery" -> openGallery(call)
|
|
@@ -7,8 +7,7 @@ class IonCameraSettings {
|
|
|
7
7
|
var correctOrientation: Boolean = DEFAULT_CORRECT_ORIENTATION
|
|
8
8
|
var encodingType: Int = 0 //JPEG
|
|
9
9
|
var saveToGallery: Boolean = DEFAULT_SAVE_IMAGE_TO_GALLERY
|
|
10
|
-
var
|
|
11
|
-
var editInApp: Boolean = true
|
|
10
|
+
var editable: IonEditableMode = IonEditableMode.NO
|
|
12
11
|
var includeMetadata: Boolean = false
|
|
13
12
|
var shouldResize: Boolean = false
|
|
14
13
|
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
package com.capacitorjs.plugins.camera
|
|
2
|
+
|
|
3
|
+
enum class IonEditableMode(val value: String) {
|
|
4
|
+
NO("no"),
|
|
5
|
+
IN_APP("in-app"),
|
|
6
|
+
EXTERNAL("external");
|
|
7
|
+
|
|
8
|
+
companion object {
|
|
9
|
+
fun fromString(value: String?): IonEditableMode {
|
|
10
|
+
if (value == null) return NO
|
|
11
|
+
return values().find {
|
|
12
|
+
it.value.equals(value, ignoreCase = true)
|
|
13
|
+
} ?: NO
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -7,8 +7,7 @@ class IonGallerySettings {
|
|
|
7
7
|
var allowMultipleSelection: Boolean = false
|
|
8
8
|
var limit: Int = 0
|
|
9
9
|
var includeMetadata: Boolean = false
|
|
10
|
-
var
|
|
11
|
-
var editInApp: Boolean = true
|
|
10
|
+
var editable: IonEditableMode = IonEditableMode.NO
|
|
12
11
|
var quality: Int = DEFAULT_QUALITY
|
|
13
12
|
var width: Int = 0
|
|
14
13
|
var height: Int = 0
|
package/dist/docs.json
CHANGED
|
@@ -324,7 +324,7 @@
|
|
|
324
324
|
"name": "since"
|
|
325
325
|
}
|
|
326
326
|
],
|
|
327
|
-
"docs": "Returns the thumbnail of the media, base64 encoded.\nOn Web, for `MediaType.Photo`, the full image is returned here, also base64 encoded.",
|
|
327
|
+
"docs": "Returns the thumbnail of the media, base64 encoded.\nOn Web, for `MediaType.Photo`, the full image is returned here, also base64 encoded.\nOn Web, for `MediaType.Video`, a full-resolution JPEG frame captured from the video is returned, base64 encoded at 80% quality.",
|
|
328
328
|
"complexTypes": [],
|
|
329
329
|
"type": "string | undefined"
|
|
330
330
|
},
|
|
@@ -383,7 +383,7 @@
|
|
|
383
383
|
"name": "since"
|
|
384
384
|
}
|
|
385
385
|
],
|
|
386
|
-
"docs": "File size of the media, in bytes
|
|
386
|
+
"docs": "File size of the media, in bytes.",
|
|
387
387
|
"complexTypes": [],
|
|
388
388
|
"type": "number | undefined"
|
|
389
389
|
},
|
|
@@ -395,7 +395,7 @@
|
|
|
395
395
|
"name": "since"
|
|
396
396
|
}
|
|
397
397
|
],
|
|
398
|
-
"docs": "Only applicable for `MediaType.Video` - the duration of the media, in seconds
|
|
398
|
+
"docs": "Only applicable for `MediaType.Video` - the duration of the media, in seconds.",
|
|
399
399
|
"complexTypes": [],
|
|
400
400
|
"type": "number | undefined"
|
|
401
401
|
},
|
|
@@ -407,7 +407,7 @@
|
|
|
407
407
|
"name": "since"
|
|
408
408
|
}
|
|
409
409
|
],
|
|
410
|
-
"docs": "The format of the image, ex: jpeg, png, mp4.\n\nWeb supports jpeg, png and gif, but the exact availability may vary depending on the browser.\ngif is only supported for `chooseFromGallery
|
|
410
|
+
"docs": "The format of the image, ex: jpeg, png, mp4.\n\nAndroid and iOS may return 'jpg' instead of 'jpeg'. The format is the same, just with a different name.\nPlease compare against both 'jpeg' and 'jpg' when checking if the format of the returned media is JPEG.\nWeb supports jpeg, png and gif, but the exact availability may vary depending on the browser.\ngif is only supported for `chooseFromGallery` on Web.",
|
|
411
411
|
"complexTypes": [],
|
|
412
412
|
"type": "string"
|
|
413
413
|
},
|
|
@@ -421,7 +421,7 @@
|
|
|
421
421
|
],
|
|
422
422
|
"docs": "The resolution of the media, in `<width>x<height>` format. Example: '1920x1080'.",
|
|
423
423
|
"complexTypes": [],
|
|
424
|
-
"type": "string"
|
|
424
|
+
"type": "string | undefined"
|
|
425
425
|
},
|
|
426
426
|
{
|
|
427
427
|
"name": "creationDate",
|
|
@@ -431,7 +431,7 @@
|
|
|
431
431
|
"name": "since"
|
|
432
432
|
}
|
|
433
433
|
],
|
|
434
|
-
"docs": "The date and time the media was created, in ISO 8601 format.\nIf creation date is not available (e.g. Android 7 and below), the last modified date is returned.\
|
|
434
|
+
"docs": "The date and time the media was created, in ISO 8601 format.\nIf creation date is not available (e.g. Android 7 and below), the last modified date is returned.\nFor Web, the last modified date is always returned.",
|
|
435
435
|
"complexTypes": [],
|
|
436
436
|
"type": "string | undefined"
|
|
437
437
|
},
|
|
@@ -443,7 +443,7 @@
|
|
|
443
443
|
"name": "since"
|
|
444
444
|
}
|
|
445
445
|
],
|
|
446
|
-
"docs": "Exif data, if any, retreived from the media item.\nNot available on Web.",
|
|
446
|
+
"docs": "Exif data, if any, retreived from the media item.\nOnly available for `MediaType.Photo`.\nNot available on Web.",
|
|
447
447
|
"complexTypes": [],
|
|
448
448
|
"type": "string | undefined"
|
|
449
449
|
}
|
|
@@ -565,10 +565,10 @@
|
|
|
565
565
|
"type": "CameraDirection"
|
|
566
566
|
},
|
|
567
567
|
{
|
|
568
|
-
"name": "
|
|
568
|
+
"name": "editable",
|
|
569
569
|
"tags": [
|
|
570
570
|
{
|
|
571
|
-
"text": "
|
|
571
|
+
"text": "'no'",
|
|
572
572
|
"name": "default"
|
|
573
573
|
},
|
|
574
574
|
{
|
|
@@ -576,25 +576,9 @@
|
|
|
576
576
|
"name": "since"
|
|
577
577
|
}
|
|
578
578
|
],
|
|
579
|
-
"docs": "
|
|
579
|
+
"docs": "Determines if and how the user can edit the photo.\n- 'in-app': Use an in-app editor for photo edition.\n- 'external': Open a separate (platform-specific) native app to handle photo edition, falling back to the in-app editor if none is available. Note: iOS does not support external editing and will use 'in-app' instead.\n- 'no': No editing allowed.\nNot available on Web.",
|
|
580
580
|
"complexTypes": [],
|
|
581
|
-
"type": "
|
|
582
|
-
},
|
|
583
|
-
{
|
|
584
|
-
"name": "editInApp",
|
|
585
|
-
"tags": [
|
|
586
|
-
{
|
|
587
|
-
"text": "true",
|
|
588
|
-
"name": "default"
|
|
589
|
-
},
|
|
590
|
-
{
|
|
591
|
-
"text": "8.1.0",
|
|
592
|
-
"name": "since"
|
|
593
|
-
}
|
|
594
|
-
],
|
|
595
|
-
"docs": "If `true`, will use an in-app editor for photo edition.\nIf `false`, will open a separate (platform-specific) native app to handle photo edition, falling back to the in-app editor if none is available.\nOnly applicable with `allowEdit` set to true.\nNote: This option is only supported on Android and iOS.",
|
|
596
|
-
"complexTypes": [],
|
|
597
|
-
"type": "boolean | undefined"
|
|
581
|
+
"type": "'in-app' | 'external' | 'no' | undefined"
|
|
598
582
|
},
|
|
599
583
|
{
|
|
600
584
|
"name": "presentationStyle",
|
|
@@ -636,7 +620,7 @@
|
|
|
636
620
|
"name": "since"
|
|
637
621
|
}
|
|
638
622
|
],
|
|
639
|
-
"docs": "Whether or not MediaResult should include its metadata.\nIf an error occurs when obtaining the metadata, it will return empty
|
|
623
|
+
"docs": "Whether or not MediaResult should include its metadata.\nIf an error occurs when obtaining the metadata, it will return empty.",
|
|
640
624
|
"complexTypes": [],
|
|
641
625
|
"type": "boolean | undefined"
|
|
642
626
|
}
|
|
@@ -812,31 +796,15 @@
|
|
|
812
796
|
"name": "since"
|
|
813
797
|
}
|
|
814
798
|
],
|
|
815
|
-
"docs": "Whether or not MediaResult should include its metadata.\nIf an error occurs when obtaining the metadata, it will return empty
|
|
816
|
-
"complexTypes": [],
|
|
817
|
-
"type": "boolean | undefined"
|
|
818
|
-
},
|
|
819
|
-
{
|
|
820
|
-
"name": "allowEdit",
|
|
821
|
-
"tags": [
|
|
822
|
-
{
|
|
823
|
-
"text": "false",
|
|
824
|
-
"name": "default"
|
|
825
|
-
},
|
|
826
|
-
{
|
|
827
|
-
"text": "8.1.0",
|
|
828
|
-
"name": "since"
|
|
829
|
-
}
|
|
830
|
-
],
|
|
831
|
-
"docs": "Whether to allow the user to crop or make small edits.\nOnly applicable for `MediaTypeSelection.Photo` and `allowMultipleSelection` set to `false`.\nNote: This option is only supported on Android and iOS.",
|
|
799
|
+
"docs": "Whether or not MediaResult should include its metadata.\nIf an error occurs when obtaining the metadata, it will return empty.",
|
|
832
800
|
"complexTypes": [],
|
|
833
801
|
"type": "boolean | undefined"
|
|
834
802
|
},
|
|
835
803
|
{
|
|
836
|
-
"name": "
|
|
804
|
+
"name": "editable",
|
|
837
805
|
"tags": [
|
|
838
806
|
{
|
|
839
|
-
"text": "
|
|
807
|
+
"text": "'no'",
|
|
840
808
|
"name": "default"
|
|
841
809
|
},
|
|
842
810
|
{
|
|
@@ -844,9 +812,9 @@
|
|
|
844
812
|
"name": "since"
|
|
845
813
|
}
|
|
846
814
|
],
|
|
847
|
-
"docs": "
|
|
815
|
+
"docs": "Determines if and how the user can edit the photo.\n- 'in-app': Use an in-app editor for photo edition.\n- 'external': Open a separate (platform-specific) native app to handle photo edition, falling back to the in-app editor if none is available. Note: iOS does not support external editing and will use 'in-app' instead.\n- 'no': No editing allowed.\nOnly applicable for `MediaTypeSelection.Photo` and `allowMultipleSelection` set to `false`.\nNot available on Web.",
|
|
848
816
|
"complexTypes": [],
|
|
849
|
-
"type": "
|
|
817
|
+
"type": "'in-app' | 'external' | 'no' | undefined"
|
|
850
818
|
},
|
|
851
819
|
{
|
|
852
820
|
"name": "presentationStyle",
|
|
@@ -1023,7 +991,7 @@
|
|
|
1023
991
|
"name": "since"
|
|
1024
992
|
}
|
|
1025
993
|
],
|
|
1026
|
-
"docs": "Whether or not MediaResult should include its metadata.\nIf an error occurs when obtaining the metadata, it will return empty
|
|
994
|
+
"docs": "Whether or not MediaResult should include its metadata.\nIf an error occurs when obtaining the metadata, it will return empty.",
|
|
1027
995
|
"complexTypes": [],
|
|
1028
996
|
"type": "boolean | undefined"
|
|
1029
997
|
}
|