@imgly/editor-react-native 1.48.0 → 1.49.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.
@@ -6,16 +6,38 @@ buildscript {
6
6
  google()
7
7
  gradlePluginPortal()
8
8
  }
9
- dependencies {
10
- classpath("com.android.tools.build:gradle:7.3.1")
11
- classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.7.22")
12
- }
13
9
  }
14
10
 
15
11
  def isNewArchitectureEnabled() {
16
12
  return rootProject.hasProperty("newArchEnabled") && rootProject.getProperty("newArchEnabled") == "true"
17
13
  }
18
14
 
15
+ def getKotlinVersion() {
16
+ return project.plugins.findPlugin("kotlin-android")?.class?.package?.implementationVersion
17
+ }
18
+
19
+ def isKotlin2OrHigher() {
20
+ def kotlinVersion = getKotlinVersion()
21
+ if (kotlinVersion) {
22
+ def mainVersion = kotlinVersion.split('-')[0]
23
+ def versionParts = mainVersion.tokenize('.').collect { it.toInteger() }
24
+ return versionParts[0] >= 2
25
+ }
26
+ return false
27
+ }
28
+
29
+ def getComposeVersion() {
30
+ if (isKotlin2OrHigher()) {
31
+ def mainVersion = getKotlinVersion().split('-')[0]
32
+ return mainVersion
33
+ }
34
+ return gradle.ext.has("kotlinCompilerExtensionVersion") ? gradle.ext.kotlinCompilerExtensionVersion : "1.5.10"
35
+ }
36
+
37
+ if (isKotlin2OrHigher()) {
38
+ project.plugins.apply('org.jetbrains.kotlin.plugin.compose')
39
+ }
40
+
19
41
  apply plugin: 'com.android.library'
20
42
  apply plugin: 'com.facebook.react'
21
43
  apply plugin: 'org.jetbrains.kotlin.android'
@@ -44,8 +66,10 @@ android {
44
66
  compose true
45
67
  }
46
68
 
47
- composeOptions {
48
- kotlinCompilerExtensionVersion = "1.5.10"
69
+ if (!isKotlin2OrHigher()) {
70
+ composeOptions {
71
+ kotlinCompilerExtensionVersion = getComposeVersion()
72
+ }
49
73
  }
50
74
  }
51
75
 
@@ -55,7 +79,7 @@ repositories {
55
79
  }
56
80
 
57
81
  dependencies {
58
- implementation findProject(":editor") ?: "ly.img:editor:1.48.0"
82
+ implementation findProject(":editor") ?: "ly.img:editor:1.49.0"
59
83
  implementation platform("androidx.compose:compose-bom:2023.05.01")
60
84
  implementation "androidx.activity:activity-compose:1.6.1"
61
85
  implementation "androidx.activity:activity:1.7.0"
@@ -1,6 +1,8 @@
1
1
  package ly.img.editor.reactnative.module.builder
2
2
 
3
+ import android.graphics.Bitmap
3
4
  import android.net.Uri
5
+ import android.util.Log
4
6
  import androidx.compose.runtime.Composable
5
7
  import kotlinx.coroutines.Dispatchers
6
8
  import kotlinx.coroutines.Job
@@ -30,10 +32,12 @@ import ly.img.engine.DemoAssetSource
30
32
  import ly.img.engine.DesignBlock
31
33
  import ly.img.engine.DesignBlockType
32
34
  import ly.img.engine.Engine
35
+ import ly.img.engine.FillType
33
36
  import ly.img.engine.MimeType
34
37
  import ly.img.engine.addDefaultAssetSources
35
38
  import ly.img.engine.addDemoAssetSources
36
39
  import java.io.File
40
+ import java.io.FileOutputStream
37
41
  import java.util.UUID
38
42
  import kotlin.coroutines.cancellation.CancellationException
39
43
 
@@ -370,10 +374,15 @@ object EditorBuilderDefaults {
370
374
  val tempFile = EditorDefaults.writeToTempFile(blob, mimeType)
371
375
  val scene = engine.scene.get()
372
376
  val sceneString = scene?.let {
373
- engine.scene.saveToString(it)
377
+ checkForContentUris(engine)
378
+ engine.scene.saveToString(
379
+ scene = it,
380
+ allowedResourceSchemes = listOf("blob", "bundle", "file", "http", "https", "content"),
381
+ )
374
382
  }
375
383
  val sceneUri = sceneString?.let { saveScene(it) }
376
384
  val firstPage = engine.scene.getPages().first()
385
+ engine.block.setVisible(firstPage, true)
377
386
  val thumbnail = saveThumbnail(firstPage, engine, thumbnailHeight)
378
387
  eventHandler.send(HideLoading)
379
388
  return EditorResult(
@@ -406,7 +415,11 @@ object EditorBuilderDefaults {
406
415
  val thumbnail = saveThumbnail(page, engine, thumbnailHeight)
407
416
  val scene = engine.scene.get()
408
417
  val sceneString = scene?.let {
409
- engine.scene.saveToString(it)
418
+ checkForContentUris(engine)
419
+ engine.scene.saveToString(
420
+ scene = it,
421
+ allowedResourceSchemes = listOf("blob", "bundle", "file", "http", "https", "content"),
422
+ )
410
423
  }
411
424
 
412
425
  val buffer = engine.block.exportVideo(
@@ -447,7 +460,55 @@ object EditorBuilderDefaults {
447
460
  val frames = engine.block.generateVideoThumbnailSequence(id, height, timeBegin = 0.0, timeEnd = 0.1, numberOfFrames = 1).toList()
448
461
  val firstFrame = frames.first()
449
462
  val buffer = firstFrame.imageData
450
- val tempFile = EditorDefaults.writeToTempFile(buffer, MimeType.PNG)
451
- return Uri.fromFile(tempFile)
463
+ val bitmap = Bitmap.createBitmap(firstFrame.width, firstFrame.height, Bitmap.Config.ARGB_8888)
464
+ buffer.rewind()
465
+ bitmap.copyPixelsFromBuffer(buffer)
466
+ return withContext(Dispatchers.IO) {
467
+ val file = File.createTempFile(UUID.randomUUID().toString(), ".png")
468
+ FileOutputStream(file).use { out ->
469
+ bitmap.compress(Bitmap.CompressFormat.PNG, 100, out)
470
+ }
471
+ Uri.fromFile(file)
472
+ }
473
+ }
474
+
475
+ private fun checkForContentUris(engine: Engine) = runCatching {
476
+ fun isContentUri(uri: String) = uri.startsWith("content://")
477
+
478
+ val graphicBlocks = engine.block.findByType(DesignBlockType.Graphic)
479
+ for (block in graphicBlocks) {
480
+ val fill = if (engine.block.supportsFill(block)) {
481
+ engine.block.getFill(block).takeIf { engine.block.isValid(it) }
482
+ } else {
483
+ null
484
+ }
485
+ fill ?: continue
486
+ val fillType = FillType.get(engine.block.getType(fill))
487
+ val contentUriFound = when (fillType) {
488
+ FillType.Image -> {
489
+ isContentUri(engine.block.getString(fill, "fill/image/imageFileURI")) ||
490
+ isContentUri(engine.block.getString(fill, "fill/image/previewFileURI"))
491
+ }
492
+ FillType.Video -> {
493
+ isContentUri(engine.block.getString(fill, "fill/video/fileURI"))
494
+ }
495
+ else -> continue
496
+ }
497
+ if (contentUriFound) {
498
+ Log.w(
499
+ "IMG.LY",
500
+ """
501
+ This scene contains block(s) that reference `content://` Uri(s)
502
+ (e.g. when media is picked from gallery or camera). These may not be
503
+ resolvable when loading the scene again, especially outside the
504
+ original app context. If you need to support reloading such scenes,
505
+ consider using a custom implementation with
506
+ `EngineConfiguration.onUpload` and `engine.editor.setUriResolver`
507
+ to handle these Uri(s) appropriately.
508
+ """.trimIndent(),
509
+ )
510
+ break
511
+ }
512
+ }
452
513
  }
453
514
  }
@@ -21,6 +21,7 @@ public extension OnExport {
21
21
 
22
22
  var thumbnail: URL?
23
23
  if let firstPage = try engine.scene.getPages().first {
24
+ try engine.block.setVisible(firstPage, visible: true)
24
25
  thumbnail = try await helper.saveThumbnail(firstPage, engine, thumbnailHeight)
25
26
  }
26
27
  return EditorResult(
@@ -37,13 +37,9 @@ RCT_EXPORT_MODULE(IMGLYEditor)
37
37
  return std::make_shared<facebook::react::NativeIMGLYEditorSpecJSI>(params);
38
38
  }
39
39
  #else
40
- RCT_EXPORT_METHOD(openEditor
41
- : (nonnull NSDictionary*)settings source
42
- : (nullable NSDictionary*)source preset
43
- : (NSString*)preset metadata
44
- : (NSDictionary*)metadata resolve
45
- : (RCTPromiseResolveBlock)resolve reject
46
- : (RCTPromiseRejectBlock)reject) {
40
+ RCT_EXPORT_METHOD(openEditor : (nonnull NSDictionary*)settings source : (nullable NSDictionary*)
41
+ source preset : (NSString*)preset metadata : (NSDictionary*)
42
+ metadata resolve : (RCTPromiseResolveBlock)resolve reject : (RCTPromiseRejectBlock)reject) {
47
43
  NSMutableDictionary* mergedSettings = [settings mutableCopy];
48
44
  mergedSettings[@"source"] = source;
49
45
  [self open:mergedSettings preset:preset metadata:metadata resolve:resolve reject:reject];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@imgly/editor-react-native",
3
- "version": "1.48.0",
3
+ "version": "1.49.0",
4
4
  "description": "CreativeEditor SDK for React Native - enable photo, video and design editing for your users on iOS and Android.",
5
5
  "react-native": "index.js",
6
6
  "source": "index.js",
@@ -24,7 +24,16 @@ export enum EditorPreset {
24
24
  * information.
25
25
  */
26
26
  export interface EditorResult {
27
- /** The scene. */
27
+ /** The scene.
28
+ * ⚠️ On Android, this scene might contain blocks that reference
29
+ * `content://` Uri(s) (e.g. when media is picked from gallery or camera).
30
+ * These may not be resolvable when loading the scene again, especially
31
+ * outside the original app context.
32
+ *
33
+ * If you need to support reloading such scenes, consider using a custom
34
+ * implementation with `EngineConfiguration.onUpload` and
35
+ * `engine.editor.setUriResolver` to handle these Uri(s) appropriately.
36
+ */
28
37
  scene?: string;
29
38
 
30
39
  /** The path of the exported image/video/pdf. */