@imgly/camera-react-native 1.76.0 → 1.77.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/android/build.gradle +1 -1
- package/android/src/main/kotlin/ly/img/camera/reactnative/module/IMGLYCameraModule.kt +12 -10
- package/android/src/main/kotlin/ly/img/camera/reactnative/module/model/CameraResult.kt +123 -25
- package/android/src/main/kotlin/ly/img/camera/reactnative/module/model/CameraSettings.kt +74 -3
- package/ios/IMGLYCameraModule.mm +15 -1
- package/ios/Model/CameraBuilder.swift +37 -5
- package/ios/Model/CameraResult.swift +156 -48
- package/ios/Model/CameraSettings.swift +17 -0
- package/package.json +1 -1
- package/src/NativeIMGLYCamera.ts +139 -26
package/android/build.gradle
CHANGED
|
@@ -11,14 +11,14 @@ import com.facebook.react.bridge.ReadableMap
|
|
|
11
11
|
import com.facebook.react.bridge.WritableArray
|
|
12
12
|
import com.facebook.react.bridge.WritableMap
|
|
13
13
|
import ly.img.camera.CameraActivity
|
|
14
|
-
import ly.img.camera.core.
|
|
15
|
-
import ly.img.camera.core.
|
|
14
|
+
import ly.img.camera.core.CaptureMedia
|
|
15
|
+
import ly.img.camera.core.CaptureMedia.Companion.INTENT_KEY_CAMERA_INPUT
|
|
16
16
|
import ly.img.camera.core.EngineConfiguration
|
|
17
17
|
import ly.img.camera.reactnative.module.model.CameraResult
|
|
18
18
|
import ly.img.camera.reactnative.module.model.CameraSettings
|
|
19
19
|
|
|
20
|
-
/** A closure to specify a [
|
|
21
|
-
typealias CameraInputClosure = (metadata: Map<String, Any?>?) ->
|
|
20
|
+
/** A closure to specify a [CaptureMedia.Input] the camera session based on given *metadata*. */
|
|
21
|
+
typealias CameraInputClosure = (metadata: Map<String, Any?>?) -> CaptureMedia.Input
|
|
22
22
|
|
|
23
23
|
/** A closure to modify the [CameraResult] before being send to the JS layer. */
|
|
24
24
|
typealias CameraResultClosure = (result: CameraResult?) -> CameraResult?
|
|
@@ -29,7 +29,7 @@ class IMGLYCameraModule(
|
|
|
29
29
|
) : IMGLYCameraModuleSpec(reactContext),
|
|
30
30
|
ActivityEventListener {
|
|
31
31
|
companion object {
|
|
32
|
-
/** A closure to specify a [
|
|
32
|
+
/** A closure to specify a [CaptureMedia.Input] based on given *metadata*. */
|
|
33
33
|
var configurationClosure: CameraInputClosure? = null
|
|
34
34
|
|
|
35
35
|
/** A closure to modify the [CameraResult] before being send to the JS layer. */
|
|
@@ -128,9 +128,11 @@ class IMGLYCameraModule(
|
|
|
128
128
|
this.completion = completion
|
|
129
129
|
|
|
130
130
|
val engineConfiguration =
|
|
131
|
-
EngineConfiguration(license = settings.license ?: "", userId = settings.userId)
|
|
132
|
-
val
|
|
133
|
-
|
|
131
|
+
EngineConfiguration(license = settings.license ?: "", userId = settings.userId, host = "react-native")
|
|
132
|
+
val cameraConfiguration =
|
|
133
|
+
settings.configuration?.toNative() ?: ly.img.camera.core.CameraConfiguration()
|
|
134
|
+
val input: CaptureMedia.Input =
|
|
135
|
+
configurationClosure?.invoke(metadata) ?: CaptureMedia.Input(engineConfiguration, cameraConfiguration)
|
|
134
136
|
val intent = Intent(activity, CameraActivity::class.java).apply {
|
|
135
137
|
putExtra(INTENT_KEY_CAMERA_INPUT, input)
|
|
136
138
|
}
|
|
@@ -149,9 +151,9 @@ class IMGLYCameraModule(
|
|
|
149
151
|
) {
|
|
150
152
|
if (requestCode == this.requestCode) {
|
|
151
153
|
if (resultCode == Activity.RESULT_OK) {
|
|
152
|
-
val result = intent?.getParcelableExtra<ly.img.camera.core.CameraResult>(
|
|
154
|
+
val result = intent?.getParcelableExtra<ly.img.camera.core.CameraResult>(CaptureMedia.INTENT_KEY_CAMERA_RESULT)
|
|
153
155
|
when (result) {
|
|
154
|
-
is ly.img.camera.core.CameraResult.
|
|
156
|
+
is ly.img.camera.core.CameraResult.Captures -> {
|
|
155
157
|
var modifiedResult: CameraResult? = CameraResult(result)
|
|
156
158
|
val closure = resultClosure
|
|
157
159
|
if (closure != null) {
|
|
@@ -1,57 +1,155 @@
|
|
|
1
1
|
package ly.img.camera.reactnative.module.model
|
|
2
2
|
|
|
3
|
+
import android.net.Uri
|
|
3
4
|
import android.os.Parcel
|
|
4
5
|
import android.os.Parcelable
|
|
5
6
|
import ly.img.camera.reactnative.module.model.CameraResult.CREATOR.readMap
|
|
6
7
|
import ly.img.camera.reactnative.module.model.CameraResult.CREATOR.writeMap
|
|
8
|
+
import kotlin.time.Duration
|
|
9
|
+
import kotlin.time.Duration.Companion.milliseconds
|
|
10
|
+
import kotlin.time.DurationUnit
|
|
11
|
+
import ly.img.camera.core.CameraResult as CoreCameraResult
|
|
12
|
+
import ly.img.camera.core.Capture as CoreCapture
|
|
7
13
|
|
|
8
14
|
/**
|
|
9
|
-
*
|
|
15
|
+
* A captured still photo.
|
|
10
16
|
*
|
|
11
|
-
* @property
|
|
17
|
+
* @property uri The location of the photo file in temporary storage.
|
|
18
|
+
* @property duration The duration stamped on the photo.
|
|
12
19
|
*/
|
|
13
|
-
data class
|
|
14
|
-
val
|
|
20
|
+
data class Photo(
|
|
21
|
+
val uri: Uri,
|
|
22
|
+
val duration: Duration,
|
|
15
23
|
) : Parcelable {
|
|
16
|
-
/**
|
|
17
|
-
* Creates a new instance from a given [Parcel].
|
|
18
|
-
* @param parcel The [Parcel].
|
|
19
|
-
*/
|
|
20
24
|
constructor(parcel: Parcel) : this(
|
|
21
|
-
parcel.
|
|
25
|
+
uri = parcel.readParcelable(Uri::class.java.classLoader)!!,
|
|
26
|
+
duration = parcel.readLong().milliseconds,
|
|
22
27
|
)
|
|
23
|
-
constructor(
|
|
24
|
-
|
|
28
|
+
constructor(photo: CoreCapture.Photo) : this(
|
|
29
|
+
uri = photo.uri,
|
|
30
|
+
duration = photo.clipDuration,
|
|
25
31
|
)
|
|
26
32
|
|
|
27
33
|
override fun writeToParcel(
|
|
28
34
|
parcel: Parcel,
|
|
29
35
|
flags: Int,
|
|
30
36
|
) {
|
|
31
|
-
parcel.
|
|
37
|
+
parcel.writeParcelable(uri, flags)
|
|
38
|
+
parcel.writeLong(duration.inWholeMilliseconds)
|
|
32
39
|
}
|
|
33
40
|
|
|
34
41
|
override fun describeContents(): Int = 0
|
|
35
42
|
|
|
36
|
-
companion object CREATOR : Parcelable.Creator<
|
|
37
|
-
|
|
43
|
+
companion object CREATOR : Parcelable.Creator<Photo> {
|
|
44
|
+
private const val PHOTO_FRAME_WIDTH = 1080f
|
|
45
|
+
private const val PHOTO_FRAME_HEIGHT = 1920f
|
|
38
46
|
|
|
39
|
-
override fun
|
|
47
|
+
override fun createFromParcel(parcel: Parcel): Photo = Photo(parcel)
|
|
48
|
+
|
|
49
|
+
override fun newArray(size: Int): Array<Photo?> = arrayOfNulls(size)
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
fun toMap(): Map<String, Any?> {
|
|
53
|
+
// Android has no dual-camera mode — emit a single-element `images` list with the rect
|
|
54
|
+
// covering the full 1080×1920 preview frame so the wire format matches iOS's
|
|
55
|
+
// `Photo { images: [PhotoImage], duration }` contract.
|
|
56
|
+
val image = mapOf<String, Any?>(
|
|
57
|
+
"uri" to uri.toString(),
|
|
58
|
+
"rect" to mapOf<String, Any?>(
|
|
59
|
+
"x" to 0f,
|
|
60
|
+
"y" to 0f,
|
|
61
|
+
"width" to PHOTO_FRAME_WIDTH,
|
|
62
|
+
"height" to PHOTO_FRAME_HEIGHT,
|
|
63
|
+
),
|
|
64
|
+
)
|
|
65
|
+
return mapOf(
|
|
66
|
+
"images" to listOf(image),
|
|
67
|
+
"duration" to duration.toDouble(DurationUnit.MILLISECONDS),
|
|
68
|
+
)
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* A single capture from the camera. Either a still [photo] or a video [video] recording.
|
|
74
|
+
*/
|
|
75
|
+
data class Capture(
|
|
76
|
+
val photo: Photo?,
|
|
77
|
+
val video: Recording?,
|
|
78
|
+
) : Parcelable {
|
|
79
|
+
constructor(parcel: Parcel) : this(
|
|
80
|
+
photo = parcel.readParcelable(Photo::class.java.classLoader),
|
|
81
|
+
video = parcel.readParcelable(Recording::class.java.classLoader),
|
|
82
|
+
)
|
|
83
|
+
constructor(capture: CoreCapture) : this(
|
|
84
|
+
photo = (capture as? CoreCapture.Photo)?.let { Photo(it) },
|
|
85
|
+
video = (capture as? CoreCapture.Video)?.recording?.let { Recording(it) },
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
override fun writeToParcel(
|
|
89
|
+
parcel: Parcel,
|
|
90
|
+
flags: Int,
|
|
91
|
+
) {
|
|
92
|
+
parcel.writeParcelable(photo, flags)
|
|
93
|
+
parcel.writeParcelable(video, flags)
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
override fun describeContents(): Int = 0
|
|
97
|
+
|
|
98
|
+
companion object CREATOR : Parcelable.Creator<Capture> {
|
|
99
|
+
override fun createFromParcel(parcel: Parcel): Capture = Capture(parcel)
|
|
100
|
+
|
|
101
|
+
override fun newArray(size: Int): Array<Capture?> = arrayOfNulls(size)
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
fun toMap(): Map<String, Any?> = buildMap<String, Any?> {
|
|
105
|
+
photo?.let { put("photo", it.toMap()) }
|
|
106
|
+
video?.let { put("video", it.toMap()) }
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* The result type for a photo, video, or mixed camera capture session.
|
|
112
|
+
*
|
|
113
|
+
* @property captures The captures of the camera session.
|
|
114
|
+
*/
|
|
115
|
+
data class CameraCapture(
|
|
116
|
+
val captures: List<Capture>?,
|
|
117
|
+
) : Parcelable {
|
|
118
|
+
constructor(parcel: Parcel) : this(
|
|
119
|
+
captures = parcel.createTypedArrayList(Capture),
|
|
120
|
+
)
|
|
121
|
+
constructor(captures: CoreCameraResult.Captures) : this(
|
|
122
|
+
captures = captures.captures.map { Capture(it) },
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
override fun writeToParcel(
|
|
126
|
+
parcel: Parcel,
|
|
127
|
+
flags: Int,
|
|
128
|
+
) {
|
|
129
|
+
parcel.writeTypedList(captures)
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
override fun describeContents(): Int = 0
|
|
133
|
+
|
|
134
|
+
companion object CREATOR : Parcelable.Creator<CameraCapture> {
|
|
135
|
+
override fun createFromParcel(parcel: Parcel): CameraCapture = CameraCapture(parcel)
|
|
136
|
+
|
|
137
|
+
override fun newArray(size: Int): Array<CameraCapture?> = arrayOfNulls(size)
|
|
40
138
|
}
|
|
41
139
|
|
|
42
140
|
fun toMap(): Map<String, Any?> = mapOf(
|
|
43
|
-
"
|
|
141
|
+
"captures" to captures?.map { it.toMap() },
|
|
44
142
|
)
|
|
45
143
|
}
|
|
46
144
|
|
|
47
145
|
/**
|
|
48
146
|
* A class representing the result of a camera session.
|
|
49
147
|
*
|
|
50
|
-
* @property
|
|
148
|
+
* @property capture The result for a photo, video, or mixed capture session.
|
|
51
149
|
* @property metadata The associated metadata.
|
|
52
150
|
*/
|
|
53
151
|
data class CameraResult(
|
|
54
|
-
val
|
|
152
|
+
val capture: CameraCapture?,
|
|
55
153
|
val metadata: Map<String, Any> = emptyMap(),
|
|
56
154
|
) : Parcelable {
|
|
57
155
|
/**
|
|
@@ -59,19 +157,19 @@ data class CameraResult(
|
|
|
59
157
|
* @param parcel The [Parcel].
|
|
60
158
|
*/
|
|
61
159
|
constructor(parcel: Parcel) : this(
|
|
62
|
-
|
|
63
|
-
readMap(parcel),
|
|
160
|
+
capture = parcel.readParcelable(CameraCapture::class.java.classLoader),
|
|
161
|
+
metadata = readMap(parcel),
|
|
64
162
|
)
|
|
65
|
-
constructor(
|
|
66
|
-
|
|
67
|
-
emptyMap(),
|
|
163
|
+
constructor(captures: CoreCameraResult.Captures) : this(
|
|
164
|
+
capture = CameraCapture(captures),
|
|
165
|
+
metadata = emptyMap(),
|
|
68
166
|
)
|
|
69
167
|
|
|
70
168
|
override fun writeToParcel(
|
|
71
169
|
parcel: Parcel,
|
|
72
170
|
flags: Int,
|
|
73
171
|
) {
|
|
74
|
-
|
|
172
|
+
parcel.writeParcelable(capture, flags)
|
|
75
173
|
writeMap(parcel, metadata, flags)
|
|
76
174
|
}
|
|
77
175
|
|
|
@@ -110,7 +208,7 @@ data class CameraResult(
|
|
|
110
208
|
}
|
|
111
209
|
|
|
112
210
|
fun toMap(): Map<String, Any?> = mapOf(
|
|
113
|
-
"
|
|
211
|
+
"capture" to capture?.toMap(),
|
|
114
212
|
"metadata" to metadata,
|
|
115
213
|
)
|
|
116
214
|
}
|
|
@@ -2,24 +2,31 @@ package ly.img.camera.reactnative.module.model
|
|
|
2
2
|
|
|
3
3
|
import android.os.Parcel
|
|
4
4
|
import android.os.Parcelable
|
|
5
|
+
import ly.img.camera.core.CaptureCount
|
|
6
|
+
import ly.img.camera.core.CaptureType
|
|
7
|
+
import kotlin.time.Duration.Companion.seconds
|
|
8
|
+
import ly.img.camera.core.CameraConfiguration as NativeCameraConfiguration
|
|
5
9
|
|
|
6
10
|
/**
|
|
7
11
|
* A class containing all necessary information to configure the camera.
|
|
8
12
|
*
|
|
9
13
|
* @property license The license key. Pass `null` to run the SDK in evaluation mode with a watermark.
|
|
10
14
|
* @property userId The id of the current user.
|
|
15
|
+
* @property configuration Optional [CameraConfiguration] controlling how the camera captures media.
|
|
11
16
|
*/
|
|
12
17
|
data class CameraSettings(
|
|
13
18
|
val license: String? = null,
|
|
14
19
|
val userId: String?,
|
|
20
|
+
val configuration: CameraConfiguration? = null,
|
|
15
21
|
) : Parcelable {
|
|
16
22
|
/**
|
|
17
23
|
* Creates a new instance from a given [Parcel].
|
|
18
24
|
* @param parcel The [Parcel].
|
|
19
25
|
*/
|
|
20
26
|
constructor(parcel: Parcel) : this(
|
|
21
|
-
parcel.readString(),
|
|
22
|
-
parcel.readString(),
|
|
27
|
+
license = parcel.readString(),
|
|
28
|
+
userId = parcel.readString(),
|
|
29
|
+
configuration = parcel.readParcelable(CameraConfiguration::class.java.classLoader),
|
|
23
30
|
)
|
|
24
31
|
|
|
25
32
|
override fun writeToParcel(
|
|
@@ -28,6 +35,7 @@ data class CameraSettings(
|
|
|
28
35
|
) {
|
|
29
36
|
parcel.writeString(license)
|
|
30
37
|
parcel.writeString(userId)
|
|
38
|
+
parcel.writeParcelable(configuration, flags)
|
|
31
39
|
}
|
|
32
40
|
|
|
33
41
|
override fun describeContents(): Int = 0
|
|
@@ -40,7 +48,70 @@ data class CameraSettings(
|
|
|
40
48
|
fun createFromMap(map: Map<String, Any?>): CameraSettings {
|
|
41
49
|
val license = map["license"] as? String
|
|
42
50
|
val userId = map["userId"] as? String
|
|
43
|
-
|
|
51
|
+
val configuration = (map["configuration"] as? Map<*, *>)?.let {
|
|
52
|
+
CameraConfiguration.createFromMap(it)
|
|
53
|
+
}
|
|
54
|
+
return CameraSettings(license, userId, configuration)
|
|
44
55
|
}
|
|
45
56
|
}
|
|
46
57
|
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Capture configuration forwarded from the TS layer. String fields stay loose at the bridge
|
|
61
|
+
* boundary and are mapped to the native enums when building [NativeCameraConfiguration].
|
|
62
|
+
*
|
|
63
|
+
* @property captureType One of `"photo"`, `"video"`, `"mixed"` or `null` for the native default.
|
|
64
|
+
* @property captureCount One of `"single"`, `"multi"` or `null` for the native default.
|
|
65
|
+
* @property photoClipDuration Duration in seconds stamped on each photo capture.
|
|
66
|
+
*/
|
|
67
|
+
data class CameraConfiguration(
|
|
68
|
+
val captureType: String? = null,
|
|
69
|
+
val captureCount: String? = null,
|
|
70
|
+
val photoClipDuration: Double? = null,
|
|
71
|
+
) : Parcelable {
|
|
72
|
+
constructor(parcel: Parcel) : this(
|
|
73
|
+
captureType = parcel.readString(),
|
|
74
|
+
captureCount = parcel.readString(),
|
|
75
|
+
photoClipDuration = parcel.readValue(Double::class.java.classLoader) as? Double,
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
override fun writeToParcel(
|
|
79
|
+
parcel: Parcel,
|
|
80
|
+
flags: Int,
|
|
81
|
+
) {
|
|
82
|
+
parcel.writeString(captureType)
|
|
83
|
+
parcel.writeString(captureCount)
|
|
84
|
+
parcel.writeValue(photoClipDuration)
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
override fun describeContents(): Int = 0
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Maps the wrapper configuration to a native [NativeCameraConfiguration]. Unset fields fall
|
|
91
|
+
* back to native defaults.
|
|
92
|
+
*/
|
|
93
|
+
fun toNative(): NativeCameraConfiguration {
|
|
94
|
+
val defaults = NativeCameraConfiguration()
|
|
95
|
+
return NativeCameraConfiguration(
|
|
96
|
+
captureType = captureType?.let { type ->
|
|
97
|
+
CaptureType.entries.firstOrNull { it.name.equals(type, ignoreCase = true) }
|
|
98
|
+
} ?: defaults.captureType,
|
|
99
|
+
captureCount = captureCount?.let { count ->
|
|
100
|
+
CaptureCount.entries.firstOrNull { it.name.equals(count, ignoreCase = true) }
|
|
101
|
+
} ?: defaults.captureCount,
|
|
102
|
+
photoClipDuration = photoClipDuration?.seconds ?: defaults.photoClipDuration,
|
|
103
|
+
)
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
companion object CREATOR : Parcelable.Creator<CameraConfiguration> {
|
|
107
|
+
override fun createFromParcel(parcel: Parcel): CameraConfiguration = CameraConfiguration(parcel)
|
|
108
|
+
|
|
109
|
+
override fun newArray(size: Int): Array<CameraConfiguration?> = arrayOfNulls(size)
|
|
110
|
+
|
|
111
|
+
fun createFromMap(map: Map<*, *>) = CameraConfiguration(
|
|
112
|
+
captureType = map["captureType"] as? String,
|
|
113
|
+
captureCount = map["captureCount"] as? String,
|
|
114
|
+
photoClipDuration = (map["photoClipDuration"] as? Number)?.toDouble(),
|
|
115
|
+
)
|
|
116
|
+
}
|
|
117
|
+
}
|
package/ios/IMGLYCameraModule.mm
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
RCT_EXPORT_MODULE(IMGLYCamera)
|
|
7
7
|
|
|
8
8
|
#ifdef RCT_NEW_ARCH_ENABLED
|
|
9
|
-
- (void)openCamera:(JS::NativeIMGLYCamera::
|
|
9
|
+
- (void)openCamera:(JS::NativeIMGLYCamera::SpecCameraSettings&)settings
|
|
10
10
|
video:(NSString*)video
|
|
11
11
|
metadata:(NSDictionary*)metadata
|
|
12
12
|
resolve:(RCTPromiseResolveBlock)resolve
|
|
@@ -18,6 +18,20 @@ RCT_EXPORT_MODULE(IMGLYCamera)
|
|
|
18
18
|
if (settings.userId() != nil) {
|
|
19
19
|
convertedSettings[@"userId"] = settings.userId();
|
|
20
20
|
}
|
|
21
|
+
auto configuration = settings.configuration();
|
|
22
|
+
if (configuration.has_value()) {
|
|
23
|
+
NSMutableDictionary* convertedConfiguration = [NSMutableDictionary dictionary];
|
|
24
|
+
if (configuration->captureType() != nil) {
|
|
25
|
+
convertedConfiguration[@"captureType"] = configuration->captureType();
|
|
26
|
+
}
|
|
27
|
+
if (configuration->captureCount() != nil) {
|
|
28
|
+
convertedConfiguration[@"captureCount"] = configuration->captureCount();
|
|
29
|
+
}
|
|
30
|
+
if (configuration->photoClipDuration().has_value()) {
|
|
31
|
+
convertedConfiguration[@"photoClipDuration"] = @(*configuration->photoClipDuration());
|
|
32
|
+
}
|
|
33
|
+
convertedSettings[@"configuration"] = convertedConfiguration;
|
|
34
|
+
}
|
|
21
35
|
[self open:convertedSettings video:video metadata:metadata resolve:resolve reject:reject];
|
|
22
36
|
}
|
|
23
37
|
|
|
@@ -50,7 +50,36 @@ extension CameraBuilder {
|
|
|
50
50
|
/// - Parameter settings: The `CameraSettings`.
|
|
51
51
|
/// - Returns: The derived `EngineSettings`.
|
|
52
52
|
private static func engineSettings(for settings: CameraSettings) -> EngineSettings {
|
|
53
|
-
|
|
53
|
+
// Identify this engine as React-Native-hosted so v4 licenses scoped to
|
|
54
|
+
// `host: react-native` validate. Hardcoded (not customer-configurable).
|
|
55
|
+
EngineSettings(license: settings.license, userID: settings.userId, host: "react-native")
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/// Builds a native `IMGLYCamera.CameraConfiguration` from the bridged config dict.
|
|
59
|
+
/// Missing or unknown fields fall back to the native defaults.
|
|
60
|
+
private static func nativeConfiguration(
|
|
61
|
+
from configuration: CameraConfiguration?,
|
|
62
|
+
) -> IMGLYCamera.CameraConfiguration {
|
|
63
|
+
IMGLYCamera.CameraConfiguration(
|
|
64
|
+
captureType: nativeCaptureType(configuration?.captureType),
|
|
65
|
+
captureCount: nativeCaptureCount(configuration?.captureCount),
|
|
66
|
+
photoClipDuration: configuration?.photoClipDuration ?? 5,
|
|
67
|
+
)
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
private static func nativeCaptureType(_ raw: String?) -> IMGLYCamera.CaptureType {
|
|
71
|
+
switch raw {
|
|
72
|
+
case "photo": .photo
|
|
73
|
+
case "mixed": .mixed
|
|
74
|
+
default: .video
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
private static func nativeCaptureCount(_ raw: String?) -> IMGLYCamera.CaptureCount {
|
|
79
|
+
switch raw {
|
|
80
|
+
case "single": .single
|
|
81
|
+
default: .multi
|
|
82
|
+
}
|
|
54
83
|
}
|
|
55
84
|
|
|
56
85
|
/// A modal camera implementation.
|
|
@@ -58,21 +87,23 @@ extension CameraBuilder {
|
|
|
58
87
|
private let settings: CameraSettings
|
|
59
88
|
private let result: CameraBuilderResult
|
|
60
89
|
private let url: URL?
|
|
90
|
+
private let config: IMGLYCamera.CameraConfiguration
|
|
61
91
|
private let onDismiss: (Result<IMGLYCamera.CameraResult, CameraError>) -> Void
|
|
62
92
|
|
|
63
93
|
public init(settings: CameraSettings, result: @escaping CameraBuilderResult, url: URL? = nil) {
|
|
64
94
|
self.settings = settings
|
|
65
95
|
self.result = result
|
|
66
96
|
self.url = url
|
|
97
|
+
config = CameraBuilder.nativeConfiguration(from: settings.configuration)
|
|
67
98
|
|
|
68
99
|
onDismiss = { cameraResult in
|
|
69
100
|
switch cameraResult {
|
|
70
101
|
case let .success(.reaction(video: recording, reaction: reaction)):
|
|
71
102
|
let reaction = CameraReaction(video: recording, recordings: reaction)
|
|
72
103
|
result(.success(CameraResult(reaction: reaction)))
|
|
73
|
-
case let .success(.
|
|
74
|
-
let
|
|
75
|
-
result(.success(CameraResult(
|
|
104
|
+
case let .success(.capture(captures)):
|
|
105
|
+
let capture = CameraCapture(captures: captures)
|
|
106
|
+
result(.success(CameraResult(capture: capture)))
|
|
76
107
|
case let .failure(error):
|
|
77
108
|
result(.failure(error))
|
|
78
109
|
}
|
|
@@ -83,11 +114,12 @@ extension CameraBuilder {
|
|
|
83
114
|
if let url {
|
|
84
115
|
Camera(
|
|
85
116
|
engineSettings(for: settings),
|
|
117
|
+
config: config,
|
|
86
118
|
mode: .reaction(.horizontal, video: url, positionsSwapped: false),
|
|
87
119
|
onDismiss: onDismiss,
|
|
88
120
|
)
|
|
89
121
|
} else {
|
|
90
|
-
Camera(engineSettings(for: settings), onDismiss: onDismiss)
|
|
122
|
+
Camera(engineSettings(for: settings), config: config, onDismiss: onDismiss)
|
|
91
123
|
}
|
|
92
124
|
}
|
|
93
125
|
}
|
|
@@ -1,33 +1,5 @@
|
|
|
1
1
|
import IMGLYCamera
|
|
2
2
|
|
|
3
|
-
/// The result type for a camera recording session in standard or dual camera mode.
|
|
4
|
-
@objc @objcMembers public class CameraRecording: NSObject {
|
|
5
|
-
/// The recorded videos.
|
|
6
|
-
public let recordings: [Recording]
|
|
7
|
-
|
|
8
|
-
/// Creates a new `CameraResult` from the `IMGLYCamera` result types.
|
|
9
|
-
/// - Parameters:
|
|
10
|
-
/// - recordings: The recorded `IMGLYCamera.Recording` videos.
|
|
11
|
-
public convenience init(recordings: [IMGLYCamera.Recording]) {
|
|
12
|
-
self.init(
|
|
13
|
-
recordings: recordings.compactMap { Recording(recording: $0) },
|
|
14
|
-
)
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
/// Creates a new `CameraResult`.
|
|
18
|
-
/// - Parameters:
|
|
19
|
-
/// - recordings: The recorded videos.
|
|
20
|
-
public init(recordings: [Recording]) {
|
|
21
|
-
self.recordings = recordings
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
func toDictionary() -> [String: Any] {
|
|
25
|
-
[
|
|
26
|
-
"recordings": recordings.compactMap { $0.toDictionary() },
|
|
27
|
-
]
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
|
|
31
3
|
/// The result type for a camera reaction session.
|
|
32
4
|
@objc @objcMembers public class CameraReaction: NSObject {
|
|
33
5
|
/// The video that was reacted to.
|
|
@@ -64,50 +36,186 @@ import IMGLYCamera
|
|
|
64
36
|
}
|
|
65
37
|
}
|
|
66
38
|
|
|
39
|
+
/// The result type for a camera capture session producing photos, videos, or both.
|
|
40
|
+
@objc @objcMembers public class CameraCapture: NSObject {
|
|
41
|
+
/// The individual captures from the session.
|
|
42
|
+
public let captures: [Capture]
|
|
43
|
+
|
|
44
|
+
/// Creates a new `CameraCapture` from the `IMGLYCamera` result types.
|
|
45
|
+
/// - Parameter captures: The `IMGLYCamera.Capture` items.
|
|
46
|
+
public convenience init(captures: [IMGLYCamera.Capture]) {
|
|
47
|
+
self.init(captures: captures.map { Capture(capture: $0) })
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/// Creates a new `CameraCapture` instance.
|
|
51
|
+
/// - Parameter captures: The captures from the session.
|
|
52
|
+
public init(captures: [Capture]) {
|
|
53
|
+
self.captures = captures
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
func toDictionary() -> [String: Any] {
|
|
57
|
+
[
|
|
58
|
+
"captures": captures.map { $0.toDictionary() },
|
|
59
|
+
]
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/// A single capture from the camera. Either a still photo or a video recording.
|
|
64
|
+
@objc @objcMembers public class Capture: NSObject {
|
|
65
|
+
/// The captured still photo, when this is a photo capture.
|
|
66
|
+
public let photo: Photo?
|
|
67
|
+
|
|
68
|
+
/// The video recording, when this is a video capture.
|
|
69
|
+
public let video: Recording?
|
|
70
|
+
|
|
71
|
+
/// Creates a new photo `Capture`.
|
|
72
|
+
public convenience init(photo: Photo) {
|
|
73
|
+
self.init(photo: photo, video: nil)
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/// Creates a new video `Capture`.
|
|
77
|
+
public convenience init(video: Recording) {
|
|
78
|
+
self.init(photo: nil, video: video)
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/// Creates a new `Capture` from the `IMGLYCamera.Capture` enum.
|
|
82
|
+
public convenience init(capture: IMGLYCamera.Capture) {
|
|
83
|
+
switch capture {
|
|
84
|
+
case let .photo(photo):
|
|
85
|
+
self.init(photo: Photo(photo: photo))
|
|
86
|
+
case let .video(recording):
|
|
87
|
+
self.init(video: Recording(recording: recording))
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
private init(photo: Photo?, video: Recording?) {
|
|
92
|
+
self.photo = photo
|
|
93
|
+
self.video = video
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
func toDictionary() -> [String: Any] {
|
|
97
|
+
var dictionary: [String: Any] = [:]
|
|
98
|
+
if let photo {
|
|
99
|
+
dictionary["photo"] = photo.toDictionary()
|
|
100
|
+
}
|
|
101
|
+
if let video {
|
|
102
|
+
dictionary["video"] = video.toDictionary()
|
|
103
|
+
}
|
|
104
|
+
return dictionary
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/// A captured still photo. Contains one image in standard mode or two stacked images in dual camera mode.
|
|
109
|
+
@objc @objcMembers public class Photo: NSObject {
|
|
110
|
+
/// The individual image(s) of the photo capture.
|
|
111
|
+
public let images: [PhotoImage]
|
|
112
|
+
|
|
113
|
+
/// The duration in seconds stamped on the photo.
|
|
114
|
+
public let duration: Double
|
|
115
|
+
|
|
116
|
+
/// Creates a new `Photo`.
|
|
117
|
+
/// - Parameters:
|
|
118
|
+
/// - images: The individual image(s) of the photo capture.
|
|
119
|
+
/// - duration: The duration in seconds stamped on the photo.
|
|
120
|
+
public init(images: [PhotoImage], duration: Double) {
|
|
121
|
+
self.images = images
|
|
122
|
+
self.duration = duration
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/// Creates a new `Photo` from an `IMGLYCamera.Photo`.
|
|
126
|
+
public convenience init(photo: IMGLYCamera.Photo) {
|
|
127
|
+
self.init(
|
|
128
|
+
images: photo.images.map { PhotoImage(image: $0) },
|
|
129
|
+
duration: photo.duration.seconds,
|
|
130
|
+
)
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
func toDictionary() -> [String: Any] {
|
|
134
|
+
[
|
|
135
|
+
"images": images.map { $0.toDictionary() },
|
|
136
|
+
"duration": duration,
|
|
137
|
+
]
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/// A single image inside a photo capture.
|
|
142
|
+
@objc @objcMembers public class PhotoImage: NSObject {
|
|
143
|
+
/// The `URL` to the source of the image.
|
|
144
|
+
public let url: URL
|
|
145
|
+
|
|
146
|
+
/// The position and size of the image inside the dual-camera layout.
|
|
147
|
+
public let rect: CGRect
|
|
148
|
+
|
|
149
|
+
/// Creates a new `PhotoImage`.
|
|
150
|
+
public init(url: URL, rect: CGRect) {
|
|
151
|
+
self.url = url
|
|
152
|
+
self.rect = rect
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/// Creates a new `PhotoImage` from an `IMGLYCamera.Photo.Image`.
|
|
156
|
+
public convenience init(image: IMGLYCamera.Photo.Image) {
|
|
157
|
+
self.init(url: image.url, rect: image.rect)
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
func toDictionary() -> [String: Any] {
|
|
161
|
+
[
|
|
162
|
+
"uri": url.absoluteString,
|
|
163
|
+
"rect": [
|
|
164
|
+
"x": rect.origin.x,
|
|
165
|
+
"y": rect.origin.y,
|
|
166
|
+
"width": Double(rect.width),
|
|
167
|
+
"height": Double(rect.height),
|
|
168
|
+
],
|
|
169
|
+
]
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
67
173
|
/// The result of a camera session.
|
|
68
174
|
@objc @objcMembers public class CameraResult: NSObject {
|
|
69
|
-
/// The
|
|
70
|
-
public let recording: CameraRecording?
|
|
71
|
-
|
|
72
|
-
/// The recorded videos.
|
|
175
|
+
/// The reaction session result.
|
|
73
176
|
public let reaction: CameraReaction?
|
|
74
177
|
|
|
178
|
+
/// The capture result for a photo, video, or mixed session.
|
|
179
|
+
public let capture: CameraCapture?
|
|
180
|
+
|
|
75
181
|
/// The associated metadata.
|
|
76
182
|
public let metadata: [String: Any]
|
|
77
183
|
|
|
78
184
|
/// Creates a new `CameraResult`.
|
|
79
185
|
/// - Parameters:
|
|
80
|
-
/// -
|
|
81
|
-
/// - recordings: The recorded videos.
|
|
186
|
+
/// - reaction: The reaction session result.
|
|
82
187
|
/// - metadata: The associated metadata.
|
|
83
|
-
public convenience init(
|
|
84
|
-
self.init(
|
|
188
|
+
public convenience init(reaction: CameraReaction, metadata: [String: Any] = [:]) {
|
|
189
|
+
self.init(reaction: reaction, capture: nil, metadata: metadata)
|
|
85
190
|
}
|
|
86
191
|
|
|
87
|
-
/// Creates a new `CameraResult
|
|
192
|
+
/// Creates a new `CameraResult`.
|
|
88
193
|
/// - Parameters:
|
|
89
|
-
/// -
|
|
90
|
-
/// - recordings: The recorded `IMGLYCamera.Recording` videos.
|
|
194
|
+
/// - capture: The capture session result.
|
|
91
195
|
/// - metadata: The associated metadata.
|
|
92
|
-
public convenience init(
|
|
93
|
-
self.init(
|
|
196
|
+
public convenience init(capture: CameraCapture, metadata: [String: Any] = [:]) {
|
|
197
|
+
self.init(reaction: nil, capture: capture, metadata: metadata)
|
|
94
198
|
}
|
|
95
199
|
|
|
96
|
-
private init(
|
|
97
|
-
|
|
200
|
+
private init(
|
|
201
|
+
reaction: CameraReaction?,
|
|
202
|
+
capture: CameraCapture?,
|
|
203
|
+
metadata: [String: Any] = [:],
|
|
204
|
+
) {
|
|
98
205
|
self.reaction = reaction
|
|
206
|
+
self.capture = capture
|
|
99
207
|
self.metadata = metadata
|
|
100
208
|
}
|
|
101
209
|
|
|
102
210
|
/// Converts the instance to a dictionary.
|
|
103
211
|
public func toDictionary() -> [String: Any] {
|
|
104
212
|
var dictionary: [String: Any] = ["metadata": metadata]
|
|
105
|
-
if let recording {
|
|
106
|
-
dictionary["recording"] = recording.toDictionary()
|
|
107
|
-
}
|
|
108
213
|
if let reaction {
|
|
109
214
|
dictionary["reaction"] = reaction.toDictionary()
|
|
110
215
|
}
|
|
216
|
+
if let capture {
|
|
217
|
+
dictionary["capture"] = capture.toDictionary()
|
|
218
|
+
}
|
|
111
219
|
return dictionary
|
|
112
220
|
}
|
|
113
221
|
}
|
|
@@ -117,13 +225,13 @@ import IMGLYCamera
|
|
|
117
225
|
/// The individual video sections.
|
|
118
226
|
public let videos: [Video]
|
|
119
227
|
|
|
120
|
-
/// The duration in
|
|
228
|
+
/// The duration in seconds.
|
|
121
229
|
public let duration: Double
|
|
122
230
|
|
|
123
231
|
/// Creates a new `Recording` instance.
|
|
124
232
|
/// - Parameters:
|
|
125
233
|
/// - videos: The individual video sections.
|
|
126
|
-
/// - duration: The duration in
|
|
234
|
+
/// - duration: The duration in seconds.
|
|
127
235
|
public init(videos: [Video], duration: Double) {
|
|
128
236
|
self.videos = videos
|
|
129
237
|
self.duration = duration
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import Foundation
|
|
2
|
+
|
|
1
3
|
/// A struct containing all necessary settings to setup the camera.
|
|
2
4
|
@objc @objcMembers public class CameraSettings: NSObject, Codable {
|
|
3
5
|
/// The license key. Pass `nil` to run the SDK in evaluation mode with a watermark.
|
|
@@ -6,6 +8,9 @@
|
|
|
6
8
|
/// The id of the current user.
|
|
7
9
|
public let userId: String?
|
|
8
10
|
|
|
11
|
+
/// Optional camera configuration. When `nil`, native defaults apply.
|
|
12
|
+
public let configuration: CameraConfiguration?
|
|
13
|
+
|
|
9
14
|
/// Creates a new instance from a given dictionary.
|
|
10
15
|
///
|
|
11
16
|
/// - Parameters:
|
|
@@ -22,3 +27,15 @@
|
|
|
22
27
|
}
|
|
23
28
|
}
|
|
24
29
|
}
|
|
30
|
+
|
|
31
|
+
/// Camera configuration options forwarded from the TypeScript layer.
|
|
32
|
+
@objc @objcMembers public class CameraConfiguration: NSObject, Codable {
|
|
33
|
+
/// The kind of media the camera captures (`"photo"`, `"video"`, `"mixed"`).
|
|
34
|
+
public let captureType: String?
|
|
35
|
+
|
|
36
|
+
/// How many captures the session produces (`"single"`, `"multi"`).
|
|
37
|
+
public let captureCount: String?
|
|
38
|
+
|
|
39
|
+
/// The duration in seconds stamped on each captured photo.
|
|
40
|
+
public let photoClipDuration: Double?
|
|
41
|
+
}
|
package/package.json
CHANGED
package/src/NativeIMGLYCamera.ts
CHANGED
|
@@ -8,7 +8,7 @@ export interface Recording {
|
|
|
8
8
|
/** The individual videos of the recording. */
|
|
9
9
|
videos: Video[];
|
|
10
10
|
|
|
11
|
-
/** The overall duration in
|
|
11
|
+
/** The overall duration in seconds. */
|
|
12
12
|
duration: number;
|
|
13
13
|
}
|
|
14
14
|
|
|
@@ -46,10 +46,81 @@ export interface Rect {
|
|
|
46
46
|
height: number;
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
-
/**
|
|
50
|
-
interface
|
|
51
|
-
/** The
|
|
52
|
-
|
|
49
|
+
/** A captured still photo. Contains one image in standard mode or two stacked images in dual camera mode. */
|
|
50
|
+
export interface Photo {
|
|
51
|
+
/** The individual image(s) of the photo capture. */
|
|
52
|
+
images: PhotoImage[];
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* The duration stamped on the photo, in seconds.
|
|
56
|
+
* Note: the Flutter bridge passes this value in milliseconds instead.
|
|
57
|
+
*/
|
|
58
|
+
duration: number;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/** A single image inside a photo capture. */
|
|
62
|
+
export interface PhotoImage {
|
|
63
|
+
/**
|
|
64
|
+
* A url to the photo file that is stored
|
|
65
|
+
* in a temporary location.
|
|
66
|
+
*/
|
|
67
|
+
uri: string;
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* A rect that contains the position of
|
|
71
|
+
* the image inside the dual-camera layout
|
|
72
|
+
* (iOS only).
|
|
73
|
+
*/
|
|
74
|
+
rect: Rect;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* A single capture from the camera. Either a still
|
|
79
|
+
* photo or a video recording.
|
|
80
|
+
*/
|
|
81
|
+
export interface Capture {
|
|
82
|
+
/** The captured still photo, when this is a photo capture. */
|
|
83
|
+
photo?: Photo;
|
|
84
|
+
|
|
85
|
+
/** The video recording, when this is a video capture. */
|
|
86
|
+
video?: Recording;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/** The kind of media the camera captures. */
|
|
90
|
+
export type CaptureType = 'photo' | 'video' | 'mixed';
|
|
91
|
+
|
|
92
|
+
/** How many captures the camera session produces. */
|
|
93
|
+
export type CaptureCount = 'single' | 'multi';
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Configuration options that control how the camera captures media.
|
|
97
|
+
* All fields are optional; missing values fall back to native defaults
|
|
98
|
+
* (`video`, `multi`, `5` seconds).
|
|
99
|
+
*/
|
|
100
|
+
export interface CameraConfiguration {
|
|
101
|
+
/** The kind of media the camera captures. */
|
|
102
|
+
captureType?: CaptureType;
|
|
103
|
+
|
|
104
|
+
/** How many captures the camera session produces. */
|
|
105
|
+
captureCount?: CaptureCount;
|
|
106
|
+
|
|
107
|
+
/** The duration in seconds stamped on each captured photo. */
|
|
108
|
+
photoClipDuration?: number;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Spec-level shape for the configuration field.
|
|
113
|
+
*
|
|
114
|
+
* The native turbo-module codegen does not support string literal unions
|
|
115
|
+
* inside nested struct fields, so the Spec sees this looser variant with
|
|
116
|
+
* plain strings while customers still author against the strict
|
|
117
|
+
* `CameraConfiguration` above. The literal types narrow it correctly at
|
|
118
|
+
* the call site through subtype assignability.
|
|
119
|
+
*/
|
|
120
|
+
interface SpecCameraConfiguration {
|
|
121
|
+
captureType?: string;
|
|
122
|
+
captureCount?: string;
|
|
123
|
+
photoClipDuration?: number;
|
|
53
124
|
}
|
|
54
125
|
|
|
55
126
|
/** The result for a reaction camera recording session. */
|
|
@@ -61,14 +132,20 @@ interface CameraReaction {
|
|
|
61
132
|
recordings: Recording[];
|
|
62
133
|
}
|
|
63
134
|
|
|
135
|
+
/** The result for a photo, video, or mixed camera capture session. */
|
|
136
|
+
interface CameraCapture {
|
|
137
|
+
/** The individual captures from the session. */
|
|
138
|
+
captures: Capture[];
|
|
139
|
+
}
|
|
140
|
+
|
|
64
141
|
/** The result of a camera session. */
|
|
65
142
|
interface CameraResult {
|
|
66
|
-
/** The
|
|
67
|
-
recording?: CameraRecording;
|
|
68
|
-
|
|
69
|
-
/** The recorded videos. */
|
|
143
|
+
/** The reaction result for a reaction camera session (iOS only). */
|
|
70
144
|
reaction?: CameraReaction;
|
|
71
145
|
|
|
146
|
+
/** The capture result for a photo, video, or mixed camera session. */
|
|
147
|
+
capture?: CameraCapture;
|
|
148
|
+
|
|
72
149
|
/** The associated metadata. */
|
|
73
150
|
metadata: { [key: string]: unknown };
|
|
74
151
|
}
|
|
@@ -84,6 +161,22 @@ export interface CameraSettings {
|
|
|
84
161
|
* active users (MAU).
|
|
85
162
|
*/
|
|
86
163
|
userId?: string;
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Optional camera configuration. When omitted,
|
|
167
|
+
* native defaults apply.
|
|
168
|
+
*/
|
|
169
|
+
configuration?: CameraConfiguration;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Spec-level shape for `CameraSettings`. See `SpecCameraConfiguration`
|
|
174
|
+
* for the reason this exists alongside the public `CameraSettings`.
|
|
175
|
+
*/
|
|
176
|
+
interface SpecCameraSettings {
|
|
177
|
+
license?: string;
|
|
178
|
+
userId?: string;
|
|
179
|
+
configuration?: SpecCameraConfiguration;
|
|
87
180
|
}
|
|
88
181
|
|
|
89
182
|
/** TurboModule Spec. */
|
|
@@ -95,7 +188,7 @@ interface Spec extends TurboModule {
|
|
|
95
188
|
* @param metadata The metadata to pass to the native module.
|
|
96
189
|
*/
|
|
97
190
|
openCamera(
|
|
98
|
-
settings:
|
|
191
|
+
settings: SpecCameraSettings,
|
|
99
192
|
video?: string,
|
|
100
193
|
metadata?: { [key: string]: unknown }
|
|
101
194
|
): Promise<CameraResult | null>;
|
|
@@ -106,15 +199,6 @@ const NativeModule = TurboModuleRegistry.get<Spec>(
|
|
|
106
199
|
'IMGLYCamera'
|
|
107
200
|
) as Spec | null;
|
|
108
201
|
|
|
109
|
-
/** The result for a default camera recording session. */
|
|
110
|
-
export interface CameraRecordingResult {
|
|
111
|
-
/** The recorded videos. */
|
|
112
|
-
recordings: Recording[];
|
|
113
|
-
|
|
114
|
-
/** The associated metadata. */
|
|
115
|
-
metadata: { [key: string]: unknown };
|
|
116
|
-
}
|
|
117
|
-
|
|
118
202
|
/** The result for a reaction camera recording session. */
|
|
119
203
|
export interface CameraReactionResult {
|
|
120
204
|
/** The video that was reacted to (iOS only). */
|
|
@@ -127,8 +211,37 @@ export interface CameraReactionResult {
|
|
|
127
211
|
metadata: { [key: string]: unknown };
|
|
128
212
|
}
|
|
129
213
|
|
|
214
|
+
/** The result for a photo, video, or mixed camera capture session. */
|
|
215
|
+
export interface CameraCaptureResult {
|
|
216
|
+
/** The individual captures from the session. */
|
|
217
|
+
captures: Capture[];
|
|
218
|
+
|
|
219
|
+
/** The associated metadata. */
|
|
220
|
+
metadata: { [key: string]: unknown };
|
|
221
|
+
}
|
|
222
|
+
|
|
130
223
|
/** The IMG.LY Camera. */
|
|
131
224
|
class IMGLYCamera {
|
|
225
|
+
/**
|
|
226
|
+
* Opens the camera in photo or mixed capture mode.
|
|
227
|
+
*
|
|
228
|
+
* Returns a `CameraCaptureResult` with photos, videos, or both, depending
|
|
229
|
+
* on the configured `captureType`.
|
|
230
|
+
*
|
|
231
|
+
* @param settings - Configuration settings for the camera. Must include
|
|
232
|
+
* a `configuration` with `captureType: 'photo'` or `'mixed'`.
|
|
233
|
+
* @param metadata - Optional metadata to pass to the native module.
|
|
234
|
+
* @returns A promise that resolves to the capture result, or null if cancelled.
|
|
235
|
+
*/
|
|
236
|
+
static async openCamera(
|
|
237
|
+
settings: CameraSettings & {
|
|
238
|
+
configuration: CameraConfiguration & {
|
|
239
|
+
captureType: 'photo' | 'mixed';
|
|
240
|
+
};
|
|
241
|
+
},
|
|
242
|
+
metadata?: { [key: string]: unknown }
|
|
243
|
+
): Promise<CameraCaptureResult | null>;
|
|
244
|
+
|
|
132
245
|
/**
|
|
133
246
|
* Opens the camera for reaction mode (iOS only).
|
|
134
247
|
* @param settings - Configuration settings for the camera.
|
|
@@ -143,28 +256,28 @@ class IMGLYCamera {
|
|
|
143
256
|
): Promise<CameraReactionResult | null>;
|
|
144
257
|
|
|
145
258
|
/**
|
|
146
|
-
* Opens the standard camera.
|
|
259
|
+
* Opens the standard video camera.
|
|
147
260
|
* @param settings - Configuration settings for the camera.
|
|
148
261
|
* @param metadata - Optional metadata to pass to the native module.
|
|
149
|
-
* @returns A promise that resolves to the
|
|
262
|
+
* @returns A promise that resolves to the capture result, or null if cancelled.
|
|
150
263
|
*/
|
|
151
264
|
static async openCamera(
|
|
152
265
|
settings: CameraSettings,
|
|
153
266
|
metadata?: { [key: string]: unknown }
|
|
154
|
-
): Promise<
|
|
267
|
+
): Promise<CameraCaptureResult | null>;
|
|
155
268
|
|
|
156
269
|
/**
|
|
157
270
|
* Opens the camera with the specified settings and optional video or metadata.
|
|
158
271
|
* @param settings - Configuration settings for the camera.
|
|
159
272
|
* @param video - Optional video input to trigger reactions (iOS only) or metadata object.
|
|
160
273
|
* @param metadata - Optional metadata to pass to the native module.
|
|
161
|
-
* @returns A promise that resolves to
|
|
274
|
+
* @returns A promise that resolves to a recording, reaction, or capture result, or null if unsuccessful.
|
|
162
275
|
*/
|
|
163
276
|
static async openCamera(
|
|
164
277
|
settings: CameraSettings,
|
|
165
278
|
video?: string | { [key: string]: unknown },
|
|
166
279
|
metadata: { [key: string]: unknown } = {}
|
|
167
|
-
): Promise<
|
|
280
|
+
): Promise<CameraReactionResult | CameraCaptureResult | null> {
|
|
168
281
|
if (!NativeModule) return null;
|
|
169
282
|
const videoInput = typeof video === 'string' ? video : undefined;
|
|
170
283
|
const metadataInput =
|
|
@@ -178,9 +291,9 @@ class IMGLYCamera {
|
|
|
178
291
|
const { video, recordings } = result.reaction;
|
|
179
292
|
return { video, recordings, metadata: result.metadata };
|
|
180
293
|
}
|
|
181
|
-
if (result?.
|
|
294
|
+
if (result?.capture) {
|
|
182
295
|
return {
|
|
183
|
-
|
|
296
|
+
captures: result.capture.captures,
|
|
184
297
|
metadata: result.metadata
|
|
185
298
|
};
|
|
186
299
|
}
|