@imgly/editor-react-native 1.72.3 → 1.73.1

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.
Files changed (126) hide show
  1. package/IMGLYEditorModule.podspec +23 -0
  2. package/android/build.gradle +9 -6
  3. package/android/src/main/AndroidManifest.xml +1 -1
  4. package/android/src/main/assets/scene/apparel.scene +1 -0
  5. package/android/src/main/assets/scene/design.scene +1 -0
  6. package/android/src/main/assets/scene/postcard.scene +1 -0
  7. package/android/src/main/assets/scene/video.scene +1 -0
  8. package/android/src/main/kotlin/ly/img/editor/configuration/apparel/ApparelConfigurationBuilder.kt +113 -0
  9. package/android/src/main/kotlin/ly/img/editor/configuration/apparel/EditorActivity.kt +37 -0
  10. package/android/src/main/kotlin/ly/img/editor/configuration/apparel/callback/OnCreate.kt +190 -0
  11. package/android/src/main/kotlin/ly/img/editor/configuration/apparel/callback/OnExport.kt +82 -0
  12. package/android/src/main/kotlin/ly/img/editor/configuration/apparel/callback/OnLoaded.kt +88 -0
  13. package/android/src/main/kotlin/ly/img/editor/configuration/apparel/component/CanvasMenu.kt +45 -0
  14. package/android/src/main/kotlin/ly/img/editor/configuration/apparel/component/Dock.kt +37 -0
  15. package/android/src/main/kotlin/ly/img/editor/configuration/apparel/component/InspectorBar.kt +52 -0
  16. package/android/src/main/kotlin/ly/img/editor/configuration/apparel/component/NavigationBar.kt +45 -0
  17. package/android/src/main/kotlin/ly/img/editor/configuration/apparel/component/Overlay.kt +15 -0
  18. package/android/src/main/kotlin/ly/img/editor/configuration/design/DesignConfigurationBuilder.kt +106 -0
  19. package/android/src/main/kotlin/ly/img/editor/configuration/design/EditorActivity.kt +37 -0
  20. package/android/src/main/kotlin/ly/img/editor/configuration/design/callback/OnCreate.kt +162 -0
  21. package/android/src/main/kotlin/ly/img/editor/configuration/design/callback/OnExport.kt +82 -0
  22. package/android/src/main/kotlin/ly/img/editor/configuration/design/callback/OnLoaded.kt +10 -0
  23. package/android/src/main/kotlin/ly/img/editor/configuration/design/component/CanvasMenu.kt +45 -0
  24. package/android/src/main/kotlin/ly/img/editor/configuration/design/component/Dock.kt +35 -0
  25. package/android/src/main/kotlin/ly/img/editor/configuration/design/component/InspectorBar.kt +52 -0
  26. package/android/src/main/kotlin/ly/img/editor/configuration/design/component/NavigationBar.kt +45 -0
  27. package/android/src/main/kotlin/ly/img/editor/configuration/design/component/Overlay.kt +15 -0
  28. package/android/src/main/kotlin/ly/img/editor/configuration/photo/EditorActivity.kt +37 -0
  29. package/android/src/main/kotlin/ly/img/editor/configuration/photo/PhotoConfigurationBuilder.kt +106 -0
  30. package/android/src/main/kotlin/ly/img/editor/configuration/photo/callback/OnCreate.kt +143 -0
  31. package/android/src/main/kotlin/ly/img/editor/configuration/photo/callback/OnExport.kt +82 -0
  32. package/android/src/main/kotlin/ly/img/editor/configuration/photo/callback/OnLoaded.kt +49 -0
  33. package/android/src/main/kotlin/ly/img/editor/configuration/photo/component/CanvasMenu.kt +45 -0
  34. package/android/src/main/kotlin/ly/img/editor/configuration/photo/component/Dock.kt +43 -0
  35. package/android/src/main/kotlin/ly/img/editor/configuration/photo/component/InspectorBar.kt +52 -0
  36. package/android/src/main/kotlin/ly/img/editor/configuration/photo/component/NavigationBar.kt +45 -0
  37. package/android/src/main/kotlin/ly/img/editor/configuration/photo/component/Overlay.kt +15 -0
  38. package/android/src/main/kotlin/ly/img/editor/configuration/postcard/EditorActivity.kt +37 -0
  39. package/android/src/main/kotlin/ly/img/editor/configuration/postcard/PostcardConfigurationBuilder.kt +106 -0
  40. package/android/src/main/kotlin/ly/img/editor/configuration/postcard/callback/OnCreate.kt +149 -0
  41. package/android/src/main/kotlin/ly/img/editor/configuration/postcard/callback/OnExport.kt +82 -0
  42. package/android/src/main/kotlin/ly/img/editor/configuration/postcard/callback/OnLoaded.kt +58 -0
  43. package/android/src/main/kotlin/ly/img/editor/configuration/postcard/component/CanvasMenu.kt +45 -0
  44. package/android/src/main/kotlin/ly/img/editor/configuration/postcard/component/Dock.kt +243 -0
  45. package/android/src/main/kotlin/ly/img/editor/configuration/postcard/component/InspectorBar.kt +52 -0
  46. package/android/src/main/kotlin/ly/img/editor/configuration/postcard/component/NavigationBar.kt +76 -0
  47. package/android/src/main/kotlin/ly/img/editor/configuration/postcard/component/Overlay.kt +15 -0
  48. package/android/src/main/kotlin/ly/img/editor/configuration/postcard/ext/Engine.kt +107 -0
  49. package/android/src/main/kotlin/ly/img/editor/configuration/video/EditorActivity.kt +37 -0
  50. package/android/src/main/kotlin/ly/img/editor/configuration/video/VideoConfigurationBuilder.kt +135 -0
  51. package/android/src/main/kotlin/ly/img/editor/configuration/video/callback/OnCreate.kt +191 -0
  52. package/android/src/main/kotlin/ly/img/editor/configuration/video/callback/OnExport.kt +98 -0
  53. package/android/src/main/kotlin/ly/img/editor/configuration/video/callback/OnLoaded.kt +20 -0
  54. package/android/src/main/kotlin/ly/img/editor/configuration/video/component/BottomPanel.kt +13 -0
  55. package/android/src/main/kotlin/ly/img/editor/configuration/video/component/CanvasMenu.kt +45 -0
  56. package/android/src/main/kotlin/ly/img/editor/configuration/video/component/Dock.kt +71 -0
  57. package/android/src/main/kotlin/ly/img/editor/configuration/video/component/InspectorBar.kt +68 -0
  58. package/android/src/main/kotlin/ly/img/editor/configuration/video/component/NavigationBar.kt +57 -0
  59. package/android/src/main/kotlin/ly/img/editor/configuration/video/component/Overlay.kt +421 -0
  60. package/android/src/main/kotlin/ly/img/editor/configuration/video/iconPack/CheckCircleOutline.kt +79 -0
  61. package/android/src/main/kotlin/ly/img/editor/configuration/video/iconPack/ErrorOutline.kt +92 -0
  62. package/android/src/main/kotlin/ly/img/editor/configuration/video/iconPack/IconPack.kt +14 -0
  63. package/android/src/main/kotlin/ly/img/editor/configuration/video/model/ExportStatus.kt +39 -0
  64. package/android/src/main/kotlin/ly/img/editor/reactnative/module/activity/EditorActivity.kt +2 -0
  65. package/android/src/main/kotlin/ly/img/editor/reactnative/module/builder/EditorBuilder.kt +240 -282
  66. package/ios/Extensions/OnCreate+.swift +38 -62
  67. package/ios/IMGLYEditorModule.swift +10 -1
  68. package/ios/Model/EditorBuilder.swift +132 -225
  69. package/ios/Model/ModalEditorConfiguration.swift +40 -0
  70. package/ios/Model/Source.swift +8 -0
  71. package/ios/StarterKits/Apparel/ApparelEditorConfiguration.swift +46 -0
  72. package/ios/StarterKits/Apparel/ApparelEditorStarterKit.swift +30 -0
  73. package/ios/StarterKits/Apparel/callbacks/OnChanged+Apparel.swift +116 -0
  74. package/ios/StarterKits/Apparel/callbacks/OnCreate+Apparel.swift +197 -0
  75. package/ios/StarterKits/Apparel/callbacks/OnExport+Apparel.swift +29 -0
  76. package/ios/StarterKits/Apparel/components/CanvasMenu+Apparel.swift +22 -0
  77. package/ios/StarterKits/Apparel/components/Dock+Apparel.swift +19 -0
  78. package/ios/StarterKits/Apparel/components/InspectorBar+Apparel.swift +35 -0
  79. package/ios/StarterKits/Apparel/components/NavigationBar+Apparel.swift +26 -0
  80. package/ios/StarterKits/Design/DesignEditorConfiguration.swift +43 -0
  81. package/ios/StarterKits/Design/DesignEditorStarterKit.swift +30 -0
  82. package/ios/StarterKits/Design/callbacks/OnCreate+Design.swift +131 -0
  83. package/ios/StarterKits/Design/callbacks/OnExport+Design.swift +30 -0
  84. package/ios/StarterKits/Design/components/CanvasMenu+Design.swift +22 -0
  85. package/ios/StarterKits/Design/components/Dock+Design.swift +23 -0
  86. package/ios/StarterKits/Design/components/InspectorBar+Design.swift +35 -0
  87. package/ios/StarterKits/Design/components/NavigationBar+Design.swift +24 -0
  88. package/ios/StarterKits/Photo/PhotoEditorConfiguration.swift +48 -0
  89. package/ios/StarterKits/Photo/PhotoEditorStarterKit.swift +30 -0
  90. package/ios/StarterKits/Photo/callbacks/OnChanged+Photo.swift +25 -0
  91. package/ios/StarterKits/Photo/callbacks/OnCreate+Photo.swift +138 -0
  92. package/ios/StarterKits/Photo/callbacks/OnExport+Photo.swift +29 -0
  93. package/ios/StarterKits/Photo/callbacks/OnLoaded+Photo.swift +18 -0
  94. package/ios/StarterKits/Photo/components/CanvasMenu+Photo.swift +22 -0
  95. package/ios/StarterKits/Photo/components/Dock+Photo.swift +23 -0
  96. package/ios/StarterKits/Photo/components/InspectorBar+Photo.swift +39 -0
  97. package/ios/StarterKits/Photo/components/NavigationBar+Photo.swift +24 -0
  98. package/ios/StarterKits/Photo/examples/ExampleForceCrop.swift +30 -0
  99. package/ios/StarterKits/Postcard/PostcardEditorConfiguration.swift +45 -0
  100. package/ios/StarterKits/Postcard/PostcardEditorStarterKit.swift +30 -0
  101. package/ios/StarterKits/Postcard/callbacks/OnChanged+Postcard.swift +92 -0
  102. package/ios/StarterKits/Postcard/callbacks/OnCreate+Postcard.swift +127 -0
  103. package/ios/StarterKits/Postcard/callbacks/OnExport+Postcard.swift +29 -0
  104. package/ios/StarterKits/Postcard/components/CanvasMenu+Postcard.swift +22 -0
  105. package/ios/StarterKits/Postcard/components/Dock+Postcard.swift +34 -0
  106. package/ios/StarterKits/Postcard/components/DockButtons+Postcard.swift +129 -0
  107. package/ios/StarterKits/Postcard/components/InspectorBar+Postcard.swift +35 -0
  108. package/ios/StarterKits/Postcard/components/NavigationBar+Postcard.swift +38 -0
  109. package/ios/StarterKits/Video/VideoEditorConfiguration.swift +54 -0
  110. package/ios/StarterKits/Video/VideoEditorStarterKit.swift +30 -0
  111. package/ios/StarterKits/Video/callbacks/OnCreate+Video.swift +137 -0
  112. package/ios/StarterKits/Video/callbacks/OnExport+Video.swift +46 -0
  113. package/ios/StarterKits/Video/components/BottomPanel+Video.swift +16 -0
  114. package/ios/StarterKits/Video/components/CanvasMenu+Video.swift +22 -0
  115. package/ios/StarterKits/Video/components/Dock+Video.swift +30 -0
  116. package/ios/StarterKits/Video/components/InspectorBar+Video.swift +43 -0
  117. package/ios/StarterKits/Video/components/NavigationBar+Video.swift +32 -0
  118. package/ios/StarterKits/Video/examples/ExampleVideoDurationConstraints.swift +23 -0
  119. package/ios/StarterKits/apparel-ui-b-empty.scene +1 -0
  120. package/ios/StarterKits/design-ui-empty.scene +1 -0
  121. package/ios/StarterKits/photo-ui-empty.png +0 -0
  122. package/ios/StarterKits/postcard-empty.scene +1 -0
  123. package/ios/StarterKits/video-empty.scene +1 -0
  124. package/package.json +1 -1
  125. package/src/NativeIMGLYEditor.ts +1 -1
  126. package/ios/View/ModalEditor.swift +0 -43
@@ -4,30 +4,31 @@ import android.graphics.Bitmap
4
4
  import android.net.Uri
5
5
  import android.util.Log
6
6
  import androidx.compose.runtime.Composable
7
+ import androidx.core.graphics.createBitmap
8
+ import androidx.core.net.toUri
9
+ import kotlinx.coroutines.CancellationException
7
10
  import kotlinx.coroutines.Dispatchers
8
- import kotlinx.coroutines.Job
9
- import kotlinx.coroutines.coroutineScope
10
11
  import kotlinx.coroutines.flow.toList
11
- import kotlinx.coroutines.launch
12
12
  import kotlinx.coroutines.withContext
13
- import ly.img.editor.ApparelEditor
14
- import ly.img.editor.DesignEditor
15
- import ly.img.editor.DismissVideoExportEvent
16
- import ly.img.editor.EditorDefaults
17
- import ly.img.editor.EngineConfiguration
18
- import ly.img.editor.HideLoading
19
- import ly.img.editor.PhotoEditor
20
- import ly.img.editor.PostcardEditor
21
- import ly.img.editor.ShowLoading
22
- import ly.img.editor.ShowVideoExportProgressEvent
23
- import ly.img.editor.VideoEditor
24
- import ly.img.editor.core.event.EditorEventHandler
25
- import ly.img.editor.core.library.data.AssetSourceType
26
- import ly.img.editor.core.library.data.SystemGalleryAssetSource
27
- import ly.img.editor.core.library.data.SystemGalleryConfiguration
28
- import ly.img.editor.core.library.data.SystemGalleryPermission
29
- import ly.img.editor.core.library.data.TextAssetSource
30
- import ly.img.editor.core.library.data.TypefaceProvider
13
+ import ly.img.editor.Editor
14
+ import ly.img.editor.configuration.apparel.ApparelConfigurationBuilder
15
+ import ly.img.editor.configuration.apparel.callback.onCreate
16
+ import ly.img.editor.configuration.apparel.callback.onExport
17
+ import ly.img.editor.configuration.design.DesignConfigurationBuilder
18
+ import ly.img.editor.configuration.design.callback.onCreate
19
+ import ly.img.editor.configuration.design.callback.onExport
20
+ import ly.img.editor.configuration.photo.PhotoConfigurationBuilder
21
+ import ly.img.editor.configuration.photo.callback.onCreate
22
+ import ly.img.editor.configuration.photo.callback.onExport
23
+ import ly.img.editor.configuration.postcard.PostcardConfigurationBuilder
24
+ import ly.img.editor.configuration.postcard.callback.onCreate
25
+ import ly.img.editor.configuration.postcard.callback.onExport
26
+ import ly.img.editor.configuration.video.VideoConfigurationBuilder
27
+ import ly.img.editor.configuration.video.callback.onCreate
28
+ import ly.img.editor.configuration.video.callback.onExport
29
+ import ly.img.editor.core.EditorScope
30
+ import ly.img.editor.core.configuration.EditorConfiguration
31
+ import ly.img.editor.core.configuration.remember
31
32
  import ly.img.editor.reactnative.module.model.EditorPreset
32
33
  import ly.img.editor.reactnative.module.model.EditorResult
33
34
  import ly.img.editor.reactnative.module.model.EditorSettings
@@ -36,13 +37,10 @@ import ly.img.engine.DesignBlock
36
37
  import ly.img.engine.DesignBlockType
37
38
  import ly.img.engine.Engine
38
39
  import ly.img.engine.FillType
39
- import ly.img.engine.MimeType
40
- import ly.img.engine.addDefaultAssetSources
41
- import ly.img.engine.addDemoAssetSources
42
40
  import java.io.File
43
41
  import java.io.FileOutputStream
42
+ import java.nio.ByteBuffer
44
43
  import java.util.UUID
45
- import kotlin.coroutines.cancellation.CancellationException
46
44
 
47
45
  /** A closure used to return a [Result] with type [EditorResult] from the editor. */
48
46
  typealias EditorBuilderResult = (Result<EditorResult?>) -> Unit
@@ -109,33 +107,41 @@ class EditorBuilder {
109
107
  result: EditorBuilderResult,
110
108
  onClose: (Throwable?) -> Unit,
111
109
  ) {
112
- val engineConfiguration = EngineConfiguration.remember(
110
+ Editor(
113
111
  license = settings.license,
114
- baseUri = Uri.parse(settings.baseUri),
112
+ baseUri = settings.baseUri.toUri(),
115
113
  userId = settings.userId,
116
- onCreate = {
117
- EditorBuilderDefaults.onCreate(
118
- engine = editorContext.engine,
119
- eventHandler = editorContext.eventHandler,
120
- settings = settings,
121
- defaultScene = EditorBuilderDefaults.defaultPhotoUri,
122
- sourceType = EditorSourceType.IMAGE,
123
- )
124
- },
125
- onExport = {
126
- try {
127
- val export = EditorBuilderDefaults.onExport(
128
- engine = editorContext.engine,
129
- eventHandler = editorContext.eventHandler,
130
- mimeType = MimeType.PNG,
131
- )
132
- result(Result.success(export))
133
- } catch (e: Exception) {
134
- result(Result.failure(e))
114
+ configuration = {
115
+ EditorConfiguration.remember(::PhotoConfigurationBuilder) {
116
+ onCreate = {
117
+ onCreate(
118
+ createScene = {
119
+ EditorBuilderDefaults.onCreateScene(
120
+ scope = this@Editor,
121
+ settings = settings,
122
+ defaultUri = EditorBuilderDefaults.defaultPhotoUri,
123
+ sourceType = EditorSourceType.IMAGE,
124
+ )
125
+ },
126
+ )
127
+ }
128
+ onExport = {
129
+ onExport(
130
+ postExport = {
131
+ val result = EditorBuilderDefaults.getExportResult(
132
+ scope = this@Editor,
133
+ byteBuffer = it,
134
+ )
135
+ result(Result.success(result))
136
+ },
137
+ error = {
138
+ result(Result.failure(it))
139
+ },
140
+ )
141
+ }
135
142
  }
136
143
  },
137
- )
138
- PhotoEditor(engineConfiguration = engineConfiguration) {
144
+ ) {
139
145
  onClose(it)
140
146
  }
141
147
  }
@@ -146,32 +152,40 @@ class EditorBuilder {
146
152
  result: EditorBuilderResult,
147
153
  onClose: (Throwable?) -> Unit,
148
154
  ) {
149
- val engineConfiguration = EngineConfiguration.remember(
155
+ Editor(
150
156
  license = settings.license,
151
- baseUri = Uri.parse(settings.baseUri),
157
+ baseUri = settings.baseUri.toUri(),
152
158
  userId = settings.userId,
153
- onCreate = {
154
- EditorBuilderDefaults.onCreate(
155
- engine = editorContext.engine,
156
- eventHandler = editorContext.eventHandler,
157
- settings = settings,
158
- defaultScene = EngineConfiguration.defaultApparelSceneUri,
159
- )
160
- },
161
- onExport = {
162
- try {
163
- val export = EditorBuilderDefaults.onExport(
164
- engine = editorContext.engine,
165
- eventHandler = editorContext.eventHandler,
166
- mimeType = MimeType.PDF,
167
- )
168
- result(Result.success(export))
169
- } catch (e: Exception) {
170
- result(Result.failure(e))
159
+ configuration = {
160
+ EditorConfiguration.remember(::ApparelConfigurationBuilder) {
161
+ onCreate = {
162
+ onCreate(
163
+ createScene = {
164
+ EditorBuilderDefaults.onCreateScene(
165
+ scope = this@Editor,
166
+ settings = settings,
167
+ defaultUri = "file:///android_asset/scene/apparel.scene".toUri(),
168
+ )
169
+ },
170
+ )
171
+ }
172
+ onExport = {
173
+ onExport(
174
+ postExport = {
175
+ val result = EditorBuilderDefaults.getExportResult(
176
+ scope = this@Editor,
177
+ byteBuffer = it,
178
+ )
179
+ result(Result.success(result))
180
+ },
181
+ error = {
182
+ result(Result.failure(it))
183
+ },
184
+ )
185
+ }
171
186
  }
172
187
  },
173
- )
174
- ApparelEditor(engineConfiguration = engineConfiguration) {
188
+ ) {
175
189
  onClose(it)
176
190
  }
177
191
  }
@@ -182,33 +196,40 @@ class EditorBuilder {
182
196
  result: EditorBuilderResult,
183
197
  onClose: (Throwable?) -> Unit,
184
198
  ) {
185
- val engineConfiguration = EngineConfiguration.remember(
199
+ Editor(
186
200
  license = settings.license,
187
- baseUri = Uri.parse(settings.baseUri),
201
+ baseUri = settings.baseUri.toUri(),
188
202
  userId = settings.userId,
189
- onCreate = {
190
- EditorBuilderDefaults.onCreate(
191
- engine = editorContext.engine,
192
- eventHandler = editorContext.eventHandler,
193
- settings = settings,
194
- defaultScene = EngineConfiguration.defaultDesignSceneUri,
195
- )
196
- },
197
- onExport = {
198
- try {
199
- val export = EditorBuilderDefaults.onExport(
200
- engine = editorContext.engine,
201
- eventHandler = editorContext.eventHandler,
202
- mimeType = MimeType.PDF,
203
- )
204
- result(Result.success(export))
205
- } catch (e: Exception) {
206
- result(Result.failure(e))
203
+ configuration = {
204
+ EditorConfiguration.remember(::DesignConfigurationBuilder) {
205
+ onCreate = {
206
+ onCreate(
207
+ createScene = {
208
+ EditorBuilderDefaults.onCreateScene(
209
+ scope = this@Editor,
210
+ settings = settings,
211
+ defaultUri = "file:///android_asset/scene/design.scene".toUri(),
212
+ )
213
+ },
214
+ )
215
+ }
216
+ onExport = {
217
+ onExport(
218
+ postExport = {
219
+ val result = EditorBuilderDefaults.getExportResult(
220
+ scope = this@Editor,
221
+ byteBuffer = it,
222
+ )
223
+ result(Result.success(result))
224
+ },
225
+ error = {
226
+ result(Result.failure(it))
227
+ },
228
+ )
229
+ }
207
230
  }
208
231
  },
209
- )
210
-
211
- DesignEditor(engineConfiguration = engineConfiguration) {
232
+ ) {
212
233
  onClose(it)
213
234
  }
214
235
  }
@@ -219,33 +240,40 @@ class EditorBuilder {
219
240
  result: EditorBuilderResult,
220
241
  onClose: (Throwable?) -> Unit,
221
242
  ) {
222
- val engineConfiguration = EngineConfiguration.remember(
243
+ Editor(
223
244
  license = settings.license,
224
- baseUri = Uri.parse(settings.baseUri),
245
+ baseUri = settings.baseUri.toUri(),
225
246
  userId = settings.userId,
226
- onCreate = {
227
- EditorBuilderDefaults.onCreate(
228
- engine = editorContext.engine,
229
- eventHandler = editorContext.eventHandler,
230
- settings = settings,
231
- defaultScene = EngineConfiguration.defaultPostcardSceneUri,
232
- )
233
- },
234
- onExport = {
235
- try {
236
- val export = EditorBuilderDefaults.onExport(
237
- engine = editorContext.engine,
238
- eventHandler = editorContext.eventHandler,
239
- mimeType = MimeType.PDF,
240
- )
241
- result(Result.success(export))
242
- } catch (e: Exception) {
243
- result(Result.failure(e))
247
+ configuration = {
248
+ EditorConfiguration.remember(::PostcardConfigurationBuilder) {
249
+ onCreate = {
250
+ onCreate(
251
+ createScene = {
252
+ EditorBuilderDefaults.onCreateScene(
253
+ scope = this@Editor,
254
+ settings = settings,
255
+ defaultUri = "file:///android_asset/scene/postcard.scene".toUri(),
256
+ )
257
+ },
258
+ )
259
+ }
260
+ onExport = {
261
+ onExport(
262
+ postExport = {
263
+ val result = EditorBuilderDefaults.getExportResult(
264
+ scope = this@Editor,
265
+ byteBuffer = it,
266
+ )
267
+ result(Result.success(result))
268
+ },
269
+ error = {
270
+ result(Result.failure(it))
271
+ },
272
+ )
273
+ }
244
274
  }
245
275
  },
246
- )
247
-
248
- PostcardEditor(engineConfiguration = engineConfiguration) {
276
+ ) {
249
277
  onClose(it)
250
278
  }
251
279
  }
@@ -256,36 +284,44 @@ class EditorBuilder {
256
284
  result: EditorBuilderResult,
257
285
  onClose: (Throwable?) -> Unit,
258
286
  ) {
259
- val engineConfiguration = EngineConfiguration.remember(
287
+ Editor(
260
288
  license = settings.license,
261
- baseUri = Uri.parse(settings.baseUri),
289
+ baseUri = settings.baseUri.toUri(),
262
290
  userId = settings.userId,
263
- onCreate = {
264
- EditorBuilderDefaults.onCreate(
265
- engine = editorContext.engine,
266
- eventHandler = editorContext.eventHandler,
267
- settings = settings,
268
- defaultScene = EngineConfiguration.defaultVideoSceneUri,
269
- )
270
- },
271
- onExport = {
272
- try {
273
- val export = EditorBuilderDefaults.onExportVideo(
274
- engine = editorContext.engine,
275
- eventHandler = editorContext.eventHandler,
276
- mimeType = MimeType.MP4,
277
- )
278
- result(Result.success(export))
279
- } catch (e: Exception) {
280
- if (e !is CancellationException) {
281
- result(Result.failure(e))
282
- } else {
283
- editorContext.eventHandler.send(DismissVideoExportEvent)
291
+ configuration = {
292
+ EditorConfiguration.remember(::VideoConfigurationBuilder) {
293
+ onCreate = {
294
+ onCreate(
295
+ createScene = {
296
+ EditorBuilderDefaults.onCreateScene(
297
+ scope = this@Editor,
298
+ settings = settings,
299
+ defaultUri = "file:///android_asset/scene/video.scene".toUri(),
300
+ )
301
+ },
302
+ )
303
+ }
304
+ onExport = {
305
+ onExport(
306
+ postExport = {
307
+ val result = EditorBuilderDefaults.getExportResult(
308
+ scope = this@Editor,
309
+ byteBuffer = it,
310
+ )
311
+ exportStatus = null
312
+ result(Result.success(result))
313
+ },
314
+ error = {
315
+ exportStatus = null
316
+ if (it !is CancellationException) {
317
+ result(Result.failure(it))
318
+ }
319
+ },
320
+ )
284
321
  }
285
322
  }
286
323
  },
287
- )
288
- VideoEditor(engineConfiguration = engineConfiguration) {
324
+ ) {
289
325
  onClose(it)
290
326
  }
291
327
  }
@@ -295,181 +331,97 @@ class EditorBuilder {
295
331
  /** Default implementations to ease the editor configuration process. */
296
332
  object EditorBuilderDefaults {
297
333
  /** The default image uri for the photo editor. */
298
- val defaultPhotoUri: Uri = Uri.parse("file:///android_asset/photo-ui-empty.png")
334
+ val defaultPhotoUri: Uri = "file:///android_asset/photo-ui-empty.png".toUri()
299
335
 
300
336
  /**
301
- * Default plugin implementation for the *onCreate* callback.
302
- * @param engine The [Engine] that should be used.
303
- * @param eventHandler The [EditorEventHandler] that should be used.
304
- * @param settings The [EditorSettings] containing the relevant editor information.
305
- * @param defaultScene The [Uri] of the defaultScene if no [EditorSettings.source] is specified.
306
- * @param sourceType The [EditorSourceType] defining of which type the source is.
337
+ * Default plugin implementation for the scene creation part of the *onCreate* callback.
338
+ *
339
+ * @param scope the [EditorScope] of the editor.
340
+ * @param settings the [EditorSettings] containing the relevant editor information.
341
+ * @param defaultUri the default source [Uri] if no [EditorSettings.source] is specified.
342
+ * @param sourceType the [EditorSourceType] defining of which type the source is.
307
343
  */
308
- suspend fun onCreate(
309
- engine: Engine,
310
- eventHandler: EditorEventHandler,
344
+ suspend fun onCreateScene(
345
+ scope: EditorScope,
311
346
  settings: EditorSettings,
312
- defaultScene: Uri,
347
+ defaultUri: Uri,
313
348
  sourceType: EditorSourceType = EditorSourceType.SCENE,
314
- ) = coroutineScope {
349
+ ) = scope.run {
350
+ editorContext.engine.scene.get()?.let { return@run it }
351
+
315
352
  fun isValidUri(uri: Uri): Boolean = try {
316
353
  uri.scheme != null && uri.path != null
317
- } catch (e: Exception) {
354
+ } catch (_: Exception) {
318
355
  false
319
356
  }
320
357
 
321
- val uri = if (settings.source != null) {
322
- val sourceUri = Uri.parse(settings.source?.source)
358
+ val source = settings.source
359
+ val uri = if (source != null) {
360
+ val sourceUri = source.source.toUri()
323
361
  val isValid = isValidUri(sourceUri)
324
362
  if (!isValid) {
325
363
  throw IllegalArgumentException("The specified source is not a valid Uri.")
326
364
  }
327
365
  sourceUri
328
366
  } else {
329
- defaultScene
367
+ defaultUri
330
368
  }
331
369
 
332
370
  when (settings.source?.type ?: sourceType) {
333
371
  EditorSourceType.IMAGE -> {
334
- engine.scene.createFromImage(uri)
372
+ editorContext.engine.scene.createFromImage(uri)
335
373
  }
336
374
  EditorSourceType.VIDEO -> {
337
- engine.scene.createFromVideo(uri)
375
+ editorContext.engine.scene.createFromVideo(uri)
338
376
  }
339
-
340
377
  else -> {
341
- engine.scene.load(uri)
378
+ editorContext.engine.scene.load(uri)
342
379
  }
343
380
  }
344
-
345
- launch {
346
- val baseUri = Uri.parse(settings.baseUri)
347
- engine.addDefaultAssetSources(baseUri = baseUri)
348
- SystemGalleryPermission.setMode(SystemGalleryConfiguration.Disabled)
349
- val context = engine.applicationContext
350
- listOf(
351
- AssetSourceType.GalleryAllVisuals,
352
- AssetSourceType.GalleryImage,
353
- AssetSourceType.GalleryVideo,
354
- ).forEach { type ->
355
- engine.asset.addSource(SystemGalleryAssetSource(context, type))
356
- }
357
- engine.addDemoAssetSources(
358
- sceneMode = engine.scene.getMode(),
359
- withUploadAssetSources = true,
360
- baseUri = baseUri,
361
- )
362
- val defaultTypeface = TypefaceProvider().provideTypeface(engine, "Roboto")
363
- requireNotNull(defaultTypeface)
364
- engine.asset.addSource(TextAssetSource(engine, defaultTypeface))
365
- }
366
- coroutineContext[Job]?.invokeOnCompletion {
367
- eventHandler.send(HideLoading)
368
- }
381
+ requireNotNull(editorContext.engine.scene.get())
369
382
  }
370
383
 
371
384
  /**
372
- * Default plugin implementation for the *onExport* callback.
373
- * @param engine The [Engine] that should be used.
374
- * @param eventHandler The [EditorEventHandler] that should be used.
375
- * @param mimeType The [MimeType] of the exported artifact.
376
- * @param thumbnailHeight The height of the generated thumbnail.
385
+ * Default plugin implementation that returns [EditorResult] based on the exported [byteBuffer]
386
+ *
387
+ * @param scope the [EditorScope] of the editor.
388
+ * @param byteBuffer the buffer that contains the exported data.
389
+ * @param thumbnailHeight the height of the generated thumbnail.
390
+ * @return a new [EditorResult] that contains a uri to temporary file with [byteBuffer] content,
391
+ * thumbnail and an exported scene string.
377
392
  */
378
- suspend fun onExport(
379
- engine: Engine,
380
- eventHandler: EditorEventHandler,
381
- mimeType: MimeType,
393
+ suspend fun getExportResult(
394
+ scope: EditorScope,
395
+ byteBuffer: ByteBuffer,
382
396
  thumbnailHeight: Int = 100,
383
- ): EditorResult {
384
- EditorBuilderDefaults.run {
385
- eventHandler.send(ShowLoading)
386
- val blob = engine.block.export(
387
- block = requireNotNull(engine.scene.get()),
388
- mimeType = mimeType,
389
- onPreExport = {
390
- scene.getPages().forEach { page ->
391
- block.setScopeEnabled(page, key = "layer/visibility", enabled = true)
392
- block.setVisible(page, visible = true)
393
- }
394
- },
395
- )
396
- val tempFile = EditorDefaults.writeToTempFile(blob, mimeType)
397
- val scene = engine.scene.get()
398
- val sceneString = scene?.let {
399
- checkForContentUris(engine)
400
- engine.scene.saveToString(
401
- scene = it,
402
- allowedResourceSchemes = listOf("blob", "bundle", "file", "http", "https", "content"),
403
- )
404
- }
405
- val sceneUri = sceneString?.let { saveScene(it) }
406
- val firstPage = engine.scene.getPages().first()
407
- engine.block.setVisible(firstPage, true)
408
- val thumbnail = saveThumbnail(firstPage, engine, thumbnailHeight)
409
- eventHandler.send(HideLoading)
410
- return EditorResult(
411
- scene = sceneUri.toString(),
412
- artifact = Uri.fromFile(tempFile).toString(),
413
- thumbnail = thumbnail.toString(),
397
+ ) = scope.run {
398
+ val scene = editorContext.engine.scene.get()
399
+ val sceneString = scene?.let {
400
+ checkForContentUris(editorContext.engine)
401
+ editorContext.engine.scene.saveToString(
402
+ scene = it,
403
+ allowedResourceSchemes = listOf("blob", "bundle", "file", "http", "https", "content"),
414
404
  )
415
405
  }
406
+ val sceneUri = sceneString?.let { saveScene(it) }
407
+ val firstPage = editorContext.engine.scene.getPages().first()
408
+ editorContext.engine.block.setVisible(firstPage, visible = true)
409
+ val thumbnail = saveThumbnail(firstPage, editorContext.engine, thumbnailHeight)
410
+ EditorResult(
411
+ scene = sceneUri.toString(),
412
+ artifact = Uri.fromFile(byteBuffer.writeToFile()).toString(),
413
+ thumbnail = thumbnail.toString(),
414
+ )
416
415
  }
417
416
 
418
- /**
419
- * Default plugin implementation for the *onExport* callback for the video editor.
420
- * @param engine The [Engine] that should be used.
421
- * @param eventHandler The [EditorEventHandler] that should be used.
422
- * @param mimeType The [MimeType] of the exported artifact.
423
- * @param thumbnailHeight The height of the generated thumbnail.
424
- */
425
- suspend fun onExportVideo(
426
- engine: Engine,
427
- eventHandler: EditorEventHandler,
428
- mimeType: MimeType,
429
- thumbnailHeight: Int = 100,
430
- ): EditorResult {
431
- EditorBuilderDefaults.run {
432
- eventHandler.send(ShowVideoExportProgressEvent(0f))
433
-
434
- // First create the thumbnail and save the scene
435
- // in order to finish before the video export sheet is done.
436
- val page = engine.scene.getCurrentPage() ?: engine.scene.getPages().first()
437
- val thumbnail = saveThumbnail(page, engine, thumbnailHeight)
438
- val scene = engine.scene.get()
439
- val sceneString = scene?.let {
440
- checkForContentUris(engine)
441
- engine.scene.saveToString(
442
- scene = it,
443
- allowedResourceSchemes = listOf("blob", "bundle", "file", "http", "https", "content"),
444
- )
445
- }
446
-
447
- val buffer = engine.block.exportVideo(
448
- block = page,
449
- timeOffset = 0.0,
450
- duration = engine.block.getDuration(page),
451
- mimeType = mimeType,
452
- progressCallback = { progress ->
453
- eventHandler.send(
454
- ShowVideoExportProgressEvent(progress.encodedFrames.toFloat() / progress.totalFrames),
455
- )
456
- },
457
- )
458
-
459
- val tempFile = EditorDefaults.writeToTempFile(buffer, mimeType)
460
- eventHandler.send(DismissVideoExportEvent)
461
-
462
- return EditorResult(
463
- scene = sceneString,
464
- artifact = Uri.fromFile(tempFile).toString(),
465
- thumbnail = thumbnail.toString(),
466
- )
417
+ private suspend fun ByteBuffer.writeToFile(): File = withContext(Dispatchers.IO) {
418
+ File.createTempFile(UUID.randomUUID().toString(), ".tmp").apply {
419
+ outputStream().channel.write(this@writeToFile)
467
420
  }
468
421
  }
469
422
 
470
423
  private suspend fun saveScene(scene: String): Uri = withContext(Dispatchers.IO) {
471
- val file = File
472
- .createTempFile("cesdk_export_scene_" + UUID.randomUUID().toString(), ".scene")
424
+ val file = File.createTempFile("cesdk_export_scene_" + UUID.randomUUID().toString(), ".scene")
473
425
  file.writeText(scene)
474
426
  Uri.fromFile(file)
475
427
  }
@@ -479,13 +431,19 @@ object EditorBuilderDefaults {
479
431
  engine: Engine,
480
432
  height: Int,
481
433
  ): Uri {
482
- val frames = engine.block.generateVideoThumbnailSequence(id, height, timeBegin = 0.0, timeEnd = 0.1, numberOfFrames = 1).toList()
434
+ val frames = engine.block.generateVideoThumbnailSequence(
435
+ block = id,
436
+ thumbnailHeight = height,
437
+ timeBegin = 0.0,
438
+ timeEnd = 0.1,
439
+ numberOfFrames = 1,
440
+ ).toList()
483
441
  val firstFrame = frames.first()
484
- val buffer = firstFrame.imageData
485
- val bitmap = Bitmap.createBitmap(firstFrame.width, firstFrame.height, Bitmap.Config.ARGB_8888)
486
- buffer.rewind()
487
- bitmap.copyPixelsFromBuffer(buffer)
488
442
  return withContext(Dispatchers.IO) {
443
+ val buffer = firstFrame.imageData
444
+ val bitmap = createBitmap(firstFrame.width, firstFrame.height)
445
+ buffer.rewind()
446
+ bitmap.copyPixelsFromBuffer(buffer)
489
447
  val file = File.createTempFile(UUID.randomUUID().toString(), ".png")
490
448
  FileOutputStream(file).use { out ->
491
449
  bitmap.compress(Bitmap.CompressFormat.PNG, 100, out)