@imgly/editor-react-native 1.73.0 → 1.74.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.
Files changed (118) hide show
  1. package/IMGLYEditorModule.podspec +0 -21
  2. package/android/build.gradle +1 -5
  3. package/android/src/main/assets/scene/apparel.scene +1 -0
  4. package/android/src/main/assets/scene/design.scene +1 -0
  5. package/android/src/main/assets/scene/postcard.scene +1 -0
  6. package/android/src/main/assets/scene/video.scene +1 -0
  7. package/android/src/main/kotlin/ly/img/editor/configuration/apparel/ApparelConfigurationBuilder.kt +113 -0
  8. package/android/src/main/kotlin/ly/img/editor/configuration/apparel/EditorActivity.kt +37 -0
  9. package/android/src/main/kotlin/ly/img/editor/configuration/apparel/callback/OnCreate.kt +190 -0
  10. package/android/src/main/kotlin/ly/img/editor/configuration/apparel/callback/OnExport.kt +82 -0
  11. package/android/src/main/kotlin/ly/img/editor/configuration/apparel/callback/OnLoaded.kt +88 -0
  12. package/android/src/main/kotlin/ly/img/editor/configuration/apparel/component/CanvasMenu.kt +45 -0
  13. package/android/src/main/kotlin/ly/img/editor/configuration/apparel/component/Dock.kt +37 -0
  14. package/android/src/main/kotlin/ly/img/editor/configuration/apparel/component/InspectorBar.kt +52 -0
  15. package/android/src/main/kotlin/ly/img/editor/configuration/apparel/component/NavigationBar.kt +45 -0
  16. package/android/src/main/kotlin/ly/img/editor/configuration/apparel/component/Overlay.kt +15 -0
  17. package/android/src/main/kotlin/ly/img/editor/configuration/design/DesignConfigurationBuilder.kt +106 -0
  18. package/android/src/main/kotlin/ly/img/editor/configuration/design/EditorActivity.kt +37 -0
  19. package/android/src/main/kotlin/ly/img/editor/configuration/design/callback/OnCreate.kt +162 -0
  20. package/android/src/main/kotlin/ly/img/editor/configuration/design/callback/OnExport.kt +82 -0
  21. package/android/src/main/kotlin/ly/img/editor/configuration/design/callback/OnLoaded.kt +10 -0
  22. package/android/src/main/kotlin/ly/img/editor/configuration/design/component/CanvasMenu.kt +45 -0
  23. package/android/src/main/kotlin/ly/img/editor/configuration/design/component/Dock.kt +35 -0
  24. package/android/src/main/kotlin/ly/img/editor/configuration/design/component/InspectorBar.kt +52 -0
  25. package/android/src/main/kotlin/ly/img/editor/configuration/design/component/NavigationBar.kt +45 -0
  26. package/android/src/main/kotlin/ly/img/editor/configuration/design/component/Overlay.kt +15 -0
  27. package/android/src/main/kotlin/ly/img/editor/configuration/photo/EditorActivity.kt +37 -0
  28. package/android/src/main/kotlin/ly/img/editor/configuration/photo/PhotoConfigurationBuilder.kt +106 -0
  29. package/android/src/main/kotlin/ly/img/editor/configuration/photo/callback/OnCreate.kt +143 -0
  30. package/android/src/main/kotlin/ly/img/editor/configuration/photo/callback/OnExport.kt +82 -0
  31. package/android/src/main/kotlin/ly/img/editor/configuration/photo/callback/OnLoaded.kt +49 -0
  32. package/android/src/main/kotlin/ly/img/editor/configuration/photo/component/CanvasMenu.kt +45 -0
  33. package/android/src/main/kotlin/ly/img/editor/configuration/photo/component/Dock.kt +43 -0
  34. package/android/src/main/kotlin/ly/img/editor/configuration/photo/component/InspectorBar.kt +52 -0
  35. package/android/src/main/kotlin/ly/img/editor/configuration/photo/component/NavigationBar.kt +45 -0
  36. package/android/src/main/kotlin/ly/img/editor/configuration/photo/component/Overlay.kt +15 -0
  37. package/android/src/main/kotlin/ly/img/editor/configuration/postcard/EditorActivity.kt +37 -0
  38. package/android/src/main/kotlin/ly/img/editor/configuration/postcard/PostcardConfigurationBuilder.kt +106 -0
  39. package/android/src/main/kotlin/ly/img/editor/configuration/postcard/callback/OnCreate.kt +149 -0
  40. package/android/src/main/kotlin/ly/img/editor/configuration/postcard/callback/OnExport.kt +82 -0
  41. package/android/src/main/kotlin/ly/img/editor/configuration/postcard/callback/OnLoaded.kt +58 -0
  42. package/android/src/main/kotlin/ly/img/editor/configuration/postcard/component/CanvasMenu.kt +45 -0
  43. package/android/src/main/kotlin/ly/img/editor/configuration/postcard/component/Dock.kt +243 -0
  44. package/android/src/main/kotlin/ly/img/editor/configuration/postcard/component/InspectorBar.kt +52 -0
  45. package/android/src/main/kotlin/ly/img/editor/configuration/postcard/component/NavigationBar.kt +76 -0
  46. package/android/src/main/kotlin/ly/img/editor/configuration/postcard/component/Overlay.kt +15 -0
  47. package/android/src/main/kotlin/ly/img/editor/configuration/postcard/ext/Engine.kt +107 -0
  48. package/android/src/main/kotlin/ly/img/editor/configuration/video/EditorActivity.kt +37 -0
  49. package/android/src/main/kotlin/ly/img/editor/configuration/video/VideoConfigurationBuilder.kt +135 -0
  50. package/android/src/main/kotlin/ly/img/editor/configuration/video/callback/OnCreate.kt +191 -0
  51. package/android/src/main/kotlin/ly/img/editor/configuration/video/callback/OnExport.kt +98 -0
  52. package/android/src/main/kotlin/ly/img/editor/configuration/video/callback/OnLoaded.kt +20 -0
  53. package/android/src/main/kotlin/ly/img/editor/configuration/video/component/BottomPanel.kt +13 -0
  54. package/android/src/main/kotlin/ly/img/editor/configuration/video/component/CanvasMenu.kt +45 -0
  55. package/android/src/main/kotlin/ly/img/editor/configuration/video/component/Dock.kt +71 -0
  56. package/android/src/main/kotlin/ly/img/editor/configuration/video/component/InspectorBar.kt +68 -0
  57. package/android/src/main/kotlin/ly/img/editor/configuration/video/component/NavigationBar.kt +57 -0
  58. package/android/src/main/kotlin/ly/img/editor/configuration/video/component/Overlay.kt +421 -0
  59. package/android/src/main/kotlin/ly/img/editor/configuration/video/iconPack/CheckCircleOutline.kt +79 -0
  60. package/android/src/main/kotlin/ly/img/editor/configuration/video/iconPack/ErrorOutline.kt +92 -0
  61. package/android/src/main/kotlin/ly/img/editor/configuration/video/iconPack/IconPack.kt +14 -0
  62. package/android/src/main/kotlin/ly/img/editor/configuration/video/model/ExportStatus.kt +39 -0
  63. package/ios/IMGLYEditorModule.swift +9 -1
  64. package/ios/StarterKits/Apparel/ApparelEditorConfiguration.swift +46 -0
  65. package/ios/StarterKits/Apparel/ApparelEditorStarterKit.swift +30 -0
  66. package/ios/StarterKits/Apparel/callbacks/OnChanged+Apparel.swift +116 -0
  67. package/ios/StarterKits/Apparel/callbacks/OnCreate+Apparel.swift +197 -0
  68. package/ios/StarterKits/Apparel/callbacks/OnExport+Apparel.swift +29 -0
  69. package/ios/StarterKits/Apparel/components/CanvasMenu+Apparel.swift +22 -0
  70. package/ios/StarterKits/Apparel/components/Dock+Apparel.swift +19 -0
  71. package/ios/StarterKits/Apparel/components/InspectorBar+Apparel.swift +35 -0
  72. package/ios/StarterKits/Apparel/components/NavigationBar+Apparel.swift +26 -0
  73. package/ios/StarterKits/Design/DesignEditorConfiguration.swift +43 -0
  74. package/ios/StarterKits/Design/DesignEditorStarterKit.swift +30 -0
  75. package/ios/StarterKits/Design/callbacks/OnCreate+Design.swift +131 -0
  76. package/ios/StarterKits/Design/callbacks/OnExport+Design.swift +30 -0
  77. package/ios/StarterKits/Design/components/CanvasMenu+Design.swift +22 -0
  78. package/ios/StarterKits/Design/components/Dock+Design.swift +23 -0
  79. package/ios/StarterKits/Design/components/InspectorBar+Design.swift +35 -0
  80. package/ios/StarterKits/Design/components/NavigationBar+Design.swift +24 -0
  81. package/ios/StarterKits/Photo/PhotoEditorConfiguration.swift +48 -0
  82. package/ios/StarterKits/Photo/PhotoEditorStarterKit.swift +30 -0
  83. package/ios/StarterKits/Photo/callbacks/OnChanged+Photo.swift +25 -0
  84. package/ios/StarterKits/Photo/callbacks/OnCreate+Photo.swift +138 -0
  85. package/ios/StarterKits/Photo/callbacks/OnExport+Photo.swift +29 -0
  86. package/ios/StarterKits/Photo/callbacks/OnLoaded+Photo.swift +18 -0
  87. package/ios/StarterKits/Photo/components/CanvasMenu+Photo.swift +22 -0
  88. package/ios/StarterKits/Photo/components/Dock+Photo.swift +23 -0
  89. package/ios/StarterKits/Photo/components/InspectorBar+Photo.swift +39 -0
  90. package/ios/StarterKits/Photo/components/NavigationBar+Photo.swift +24 -0
  91. package/ios/StarterKits/Photo/examples/ExampleForceCrop.swift +30 -0
  92. package/ios/StarterKits/Postcard/PostcardEditorConfiguration.swift +45 -0
  93. package/ios/StarterKits/Postcard/PostcardEditorStarterKit.swift +30 -0
  94. package/ios/StarterKits/Postcard/callbacks/OnChanged+Postcard.swift +92 -0
  95. package/ios/StarterKits/Postcard/callbacks/OnCreate+Postcard.swift +127 -0
  96. package/ios/StarterKits/Postcard/callbacks/OnExport+Postcard.swift +29 -0
  97. package/ios/StarterKits/Postcard/components/CanvasMenu+Postcard.swift +22 -0
  98. package/ios/StarterKits/Postcard/components/Dock+Postcard.swift +34 -0
  99. package/ios/StarterKits/Postcard/components/DockButtons+Postcard.swift +129 -0
  100. package/ios/StarterKits/Postcard/components/InspectorBar+Postcard.swift +35 -0
  101. package/ios/StarterKits/Postcard/components/NavigationBar+Postcard.swift +38 -0
  102. package/ios/StarterKits/Video/VideoEditorConfiguration.swift +54 -0
  103. package/ios/StarterKits/Video/VideoEditorStarterKit.swift +30 -0
  104. package/ios/StarterKits/Video/callbacks/OnCreate+Video.swift +137 -0
  105. package/ios/StarterKits/Video/callbacks/OnExport+Video.swift +46 -0
  106. package/ios/StarterKits/Video/components/BottomPanel+Video.swift +16 -0
  107. package/ios/StarterKits/Video/components/CanvasMenu+Video.swift +22 -0
  108. package/ios/StarterKits/Video/components/Dock+Video.swift +30 -0
  109. package/ios/StarterKits/Video/components/InspectorBar+Video.swift +43 -0
  110. package/ios/StarterKits/Video/components/NavigationBar+Video.swift +32 -0
  111. package/ios/StarterKits/Video/examples/ExampleVideoDurationConstraints.swift +23 -0
  112. package/ios/StarterKits/apparel-ui-b-empty.scene +1 -0
  113. package/ios/StarterKits/design-ui-empty.scene +1 -0
  114. package/ios/StarterKits/photo-ui-empty.png +0 -0
  115. package/ios/StarterKits/postcard-empty.scene +1 -0
  116. package/ios/StarterKits/video-empty.scene +1 -0
  117. package/package.json +1 -1
  118. package/src/NativeIMGLYEditor.ts +1 -1
@@ -0,0 +1,76 @@
1
+ @file:Suppress("UnusedReceiverParameter", "UnusedFlow")
2
+
3
+ package ly.img.editor.configuration.postcard.component
4
+
5
+ import androidx.compose.runtime.Composable
6
+ import androidx.compose.runtime.collectAsState
7
+ import androidx.compose.runtime.getValue
8
+ import androidx.compose.runtime.remember
9
+ import androidx.compose.ui.Alignment
10
+ import androidx.compose.ui.res.stringResource
11
+ import kotlinx.coroutines.flow.emptyFlow
12
+ import kotlinx.coroutines.flow.map
13
+ import ly.img.editor.configuration.postcard.PostcardConfigurationBuilder
14
+ import ly.img.editor.configuration.postcard.ext.getCurrentPageIndex
15
+ import ly.img.editor.core.R
16
+ import ly.img.editor.core.component.EditorTrigger
17
+ import ly.img.editor.core.component.NavigationBar
18
+ import ly.img.editor.core.component.remember
19
+ import ly.img.editor.core.component.rememberCloseEditor
20
+ import ly.img.editor.core.component.rememberExport
21
+ import ly.img.editor.core.component.rememberNextPage
22
+ import ly.img.editor.core.component.rememberPreviousPage
23
+ import ly.img.editor.core.component.rememberRedo
24
+ import ly.img.editor.core.component.rememberTogglePreviewMode
25
+ import ly.img.editor.core.component.rememberUndo
26
+ import ly.img.engine.DesignBlockType
27
+
28
+ /**
29
+ * The configuration of the component that is displayed as horizontal list of items at the top of the editor.
30
+ */
31
+ @Composable
32
+ fun PostcardConfigurationBuilder.rememberNavigationBar() = NavigationBar.remember {
33
+ scope = {
34
+ val activeSceneTrigger by EditorTrigger.remember {
35
+ editorContext.engine.scene.onActiveChanged()
36
+ }
37
+ val historyTrigger by EditorTrigger.remember(activeSceneTrigger) {
38
+ editorContext.engine.editor.onHistoryUpdated()
39
+ }
40
+ val pageIndex by remember(this, activeSceneTrigger) {
41
+ if (editorContext.engine.scene.get() == null) return@remember emptyFlow()
42
+ val stack = editorContext.engine.block.findByType(DesignBlockType.Stack).first()
43
+ editorContext.engine.event.subscribe(listOf(stack))
44
+ .map { editorContext.engine.getCurrentPageIndex() }
45
+ }.collectAsState(initial = 0)
46
+ // Update NavigationBar whenever the active scene, editor history or current page index changes
47
+ remember(this, pageIndex, historyTrigger) {
48
+ NavigationBar.Scope(parentScope = this)
49
+ }
50
+ }
51
+ listBuilder = {
52
+ NavigationBar.ListBuilder.remember {
53
+ aligned(alignment = Alignment.Start) {
54
+ add { NavigationBar.Button.rememberCloseEditor() }
55
+ add {
56
+ NavigationBar.Button.rememberPreviousPage {
57
+ textString = { stringResource(R.string.ly_img_editor_navigation_bar_button_design) }
58
+ }
59
+ }
60
+ }
61
+ aligned(alignment = Alignment.CenterHorizontally) {
62
+ add { NavigationBar.Button.rememberUndo() }
63
+ add { NavigationBar.Button.rememberRedo() }
64
+ add { NavigationBar.Button.rememberTogglePreviewMode() }
65
+ }
66
+ aligned(alignment = Alignment.End) {
67
+ add {
68
+ NavigationBar.Button.rememberNextPage {
69
+ textString = { stringResource(R.string.ly_img_editor_navigation_bar_button_write) }
70
+ }
71
+ }
72
+ add { NavigationBar.Button.rememberExport() }
73
+ }
74
+ }
75
+ }
76
+ }
@@ -0,0 +1,15 @@
1
+ package ly.img.editor.configuration.postcard.component
2
+
3
+ import androidx.compose.runtime.Composable
4
+ import ly.img.editor.configuration.postcard.PostcardConfigurationBuilder
5
+ import ly.img.editor.core.component.EditorComponent
6
+ import ly.img.editor.core.component.remember
7
+
8
+ /**
9
+ * The configuration of the component that is displayed over the editor. It is useful if you want to display a popup dialog or anything in the
10
+ * overlay.
11
+ */
12
+ @Composable
13
+ fun PostcardConfigurationBuilder.rememberOverlay() = EditorComponent.remember {
14
+ decoration = { Overlay() }
15
+ }
@@ -0,0 +1,107 @@
1
+ package ly.img.editor.configuration.postcard.ext
2
+
3
+ import androidx.compose.ui.graphics.Color
4
+ import ly.img.editor.core.component.data.ConicalGradientFill
5
+ import ly.img.editor.core.component.data.Fill
6
+ import ly.img.editor.core.component.data.LinearGradientFill
7
+ import ly.img.editor.core.component.data.RadialGradientFill
8
+ import ly.img.editor.core.component.data.SolidFill
9
+ import ly.img.engine.ColorSpace
10
+ import ly.img.engine.DesignBlock
11
+ import ly.img.engine.DesignBlockType
12
+ import ly.img.engine.Engine
13
+ import ly.img.engine.FillType
14
+ import ly.img.engine.RGBAColor
15
+
16
+ /**
17
+ * Returns current page index.
18
+ */
19
+ internal fun Engine.getCurrentPageIndex() = scene.run { getPages().indexOf(getCurrentPage()) }
20
+
21
+ /**
22
+ * Converts engine color into compose color.
23
+ */
24
+ internal fun Engine.toComposeColor(color: ly.img.engine.Color): Color {
25
+ val rgbaEngineColor = color as? RGBAColor
26
+ ?: editor.convertColorToColorSpace(color, ColorSpace.SRGB) as RGBAColor
27
+ return Color(
28
+ red = rgbaEngineColor.r,
29
+ green = rgbaEngineColor.g,
30
+ blue = rgbaEngineColor.b,
31
+ alpha = rgbaEngineColor.a,
32
+ )
33
+ }
34
+
35
+ /**
36
+ * An extension function that returns [FillType] of the design block.
37
+ *
38
+ * @param designBlock the design block that is queried.
39
+ */
40
+ internal fun Engine.getFillType(designBlock: DesignBlock): FillType? = if (!block.supportsFill(designBlock)) {
41
+ null
42
+ } else {
43
+ FillType.Companion.get(block.getType(block.getFill(designBlock)))
44
+ }
45
+
46
+ /**
47
+ * An extension function that returns [Fill] of the design block.
48
+ *
49
+ * @param designBlock the design block that is queried.
50
+ */
51
+ internal fun Engine.getFill(designBlock: DesignBlock): Fill? = if (!block.supportsFill(designBlock)) {
52
+ null
53
+ } else {
54
+ when (getFillType(designBlock)) {
55
+ FillType.Color -> {
56
+ val rgbaColor = if (DesignBlockType.Companion.getOrNull(block.getType(designBlock)) == DesignBlockType.Text) {
57
+ block.getTextColors(designBlock).first()
58
+ } else {
59
+ block.getColor(designBlock, "fill/solid/color")
60
+ }
61
+ SolidFill(toComposeColor(rgbaColor))
62
+ }
63
+
64
+ FillType.LinearGradient -> {
65
+ val fill = block.getFill(designBlock)
66
+ LinearGradientFill(
67
+ startPointX = block.getFloat(fill, "fill/gradient/linear/startPointX"),
68
+ startPointY = block.getFloat(fill, "fill/gradient/linear/startPointY"),
69
+ endPointX = block.getFloat(fill, "fill/gradient/linear/endPointX"),
70
+ endPointY = block.getFloat(fill, "fill/gradient/linear/endPointY"),
71
+ colorStops = block.getGradientColorStops(fill, "fill/gradient/colors"),
72
+ )
73
+ }
74
+
75
+ FillType.RadialGradient -> {
76
+ val fill = block.getFill(designBlock)
77
+ RadialGradientFill(
78
+ centerX = block.getFloat(fill, "fill/gradient/radial/centerPointX"),
79
+ centerY = block.getFloat(fill, "fill/gradient/radial/centerPointY"),
80
+ radius = block.getFloat(fill, "fill/gradient/radial/radius"),
81
+ colorStops = block.getGradientColorStops(fill, "fill/gradient/colors"),
82
+ )
83
+ }
84
+
85
+ FillType.ConicalGradient -> {
86
+ val fill = block.getFill(designBlock)
87
+ ConicalGradientFill(
88
+ centerX = block.getFloat(fill, "fill/gradient/conical/centerPointX"),
89
+ centerY = block.getFloat(fill, "fill/gradient/conical/centerPointY"),
90
+ colorStops = block.getGradientColorStops(fill, "fill/gradient/colors"),
91
+ )
92
+ }
93
+
94
+ // Image fill and Video fill are not supported yet
95
+ else -> null
96
+ }
97
+ }
98
+
99
+ /**
100
+ * An extension function that returns stroke color of the design block.
101
+ *
102
+ * @param designBlock the design block that is queried.
103
+ */
104
+ internal fun Engine.getStrokeColor(designBlock: DesignBlock): Color? {
105
+ if (!block.supportsStroke(designBlock)) return null
106
+ return toComposeColor(block.getColor(designBlock, "stroke/color"))
107
+ }
@@ -0,0 +1,37 @@
1
+ // highlight-starter-kit-activity-full
2
+ package ly.img.editor.configuration.video
3
+
4
+ import android.os.Bundle
5
+ import androidx.activity.ComponentActivity
6
+ import androidx.activity.compose.setContent
7
+ import androidx.activity.enableEdgeToEdge
8
+ import ly.img.editor.Editor
9
+ import ly.img.editor.core.configuration.EditorConfiguration
10
+ import ly.img.editor.core.configuration.remember
11
+
12
+ /**
13
+ * Encapsulated editor to be used in legacy activity navigation.
14
+ * Delete this file if you are using jetpack compose navigation.
15
+ */
16
+ class EditorActivity : ComponentActivity() {
17
+ override fun onCreate(savedInstanceState: Bundle?) {
18
+ super.onCreate(savedInstanceState)
19
+ // This is required to remove the default action bar on top.
20
+ setTheme(android.R.style.Theme_Material_Light_NoActionBar)
21
+ // This is required, so that the editor is displayed full screen on relatively older devices.
22
+ enableEdgeToEdge()
23
+ setContent {
24
+ Editor(
25
+ license = null, // pass null or empty for evaluation mode with watermark
26
+ configuration = {
27
+ EditorConfiguration.remember(::VideoConfigurationBuilder)
28
+ },
29
+ onClose = {
30
+ // Finish the activity, potentially handle errors.
31
+ finish()
32
+ },
33
+ )
34
+ }
35
+ }
36
+ }
37
+ // highlight-starter-kit-activity-full
@@ -0,0 +1,135 @@
1
+ package ly.img.editor.configuration.video
2
+
3
+ import androidx.compose.runtime.Stable
4
+ import androidx.compose.runtime.getValue
5
+ import androidx.compose.runtime.setValue
6
+ import ly.img.editor.BasicConfigurationBuilder
7
+ import ly.img.editor.configuration.video.callback.onCreate
8
+ import ly.img.editor.configuration.video.callback.onExport
9
+ import ly.img.editor.configuration.video.callback.onLoaded
10
+ import ly.img.editor.configuration.video.component.rememberBottomPanel
11
+ import ly.img.editor.configuration.video.component.rememberCanvasMenu
12
+ import ly.img.editor.configuration.video.component.rememberDock
13
+ import ly.img.editor.configuration.video.component.rememberInspectorBar
14
+ import ly.img.editor.configuration.video.component.rememberNavigationBar
15
+ import ly.img.editor.configuration.video.component.rememberOverlay
16
+ import ly.img.editor.configuration.video.model.ExportStatus
17
+ import ly.img.editor.core.EditorScope
18
+ import ly.img.editor.core.ScopedProperty
19
+ import ly.img.editor.core.component.EditorComponent
20
+ import ly.img.editor.core.event.EditorEvent
21
+
22
+ /**
23
+ * Configuration builder class for video editor starter kit.
24
+ */
25
+ @Stable
26
+ class VideoConfigurationBuilder : BasicConfigurationBuilder() {
27
+ /**
28
+ * Current export status of the editor.
29
+ */
30
+ var exportStatus: ExportStatus? by editorContext.mutableStateOf(
31
+ key = "ly.img.editor.configuration.video.state.exportStatus",
32
+ initial = null,
33
+ )
34
+
35
+ /**
36
+ * Whether export cancellation confirmation dialog should be displayed.
37
+ */
38
+ var showCancelExportConfirmationDialog: Boolean by editorContext.mutableStateOf(
39
+ key = "ly.img.editor.configuration.video.state.showCancelExportConfirmationDialog",
40
+ initial = false,
41
+ )
42
+
43
+ /**
44
+ * The callback that is invoked when the editor is created.
45
+ * Check parent class declaration for more details.
46
+ */
47
+ override var onCreate: (suspend EditorScope.() -> Unit)? = {
48
+ onCreate()
49
+ }
50
+
51
+ /**
52
+ * The callback that is invoked when the editor is loaded and ready to be used.
53
+ * Check parent class declaration for more details.
54
+ */
55
+ override var onLoaded: (suspend EditorScope.() -> Unit)? = {
56
+ onLoaded()
57
+ }
58
+
59
+ /**
60
+ * The callback that is invoked when the export button is clicked.
61
+ * Check parent class declaration for more details.
62
+ */
63
+ override var onExport: (suspend EditorScope.() -> Unit)? = {
64
+ onExport()
65
+ }
66
+
67
+ /**
68
+ * The callback that is invoked after [EditorEvent.OnClose] event is triggered or when the system back button is clicked
69
+ * and editor cannot handle the event internally.
70
+ * Check parent class declaration for more details.
71
+ */
72
+ override var onClose: (suspend EditorScope.() -> Unit)? = {
73
+ showConfirmationOrCloseEditor()
74
+ }
75
+
76
+ /**
77
+ * The callback that is invoked after the editor captures an error.
78
+ * Check parent class declaration for more details.
79
+ */
80
+ override var onError: (suspend EditorScope.(Throwable) -> Unit)? = {
81
+ error = it
82
+ }
83
+
84
+ /**
85
+ * The configuration of the component that is displayed as horizontal list of items at the bottom of the editor.
86
+ * Check parent class declaration for more details.
87
+ */
88
+ override var dock: ScopedProperty<EditorScope, EditorComponent<*>>? = {
89
+ rememberDock()
90
+ }
91
+
92
+ /**
93
+ * The configuration of the component that is displayed as horizontal list of items at the top of the editor.
94
+ * Check parent class declaration for more details.
95
+ */
96
+ override var navigationBar: ScopedProperty<EditorScope, EditorComponent<*>>? = {
97
+ rememberNavigationBar()
98
+ }
99
+
100
+ /**
101
+ * The configuration of the component that is displayed as horizontal list of items at the
102
+ * bottom of the editor when a design block is selected.
103
+ * Check parent class declaration for more details.
104
+ */
105
+ override var inspectorBar: ScopedProperty<EditorScope, EditorComponent<*>>? = {
106
+ rememberInspectorBar()
107
+ }
108
+
109
+ /**
110
+ * The configuration of the component that is displayed as horizontal list of items next to
111
+ * the selected design block.
112
+ * Check parent class declaration for more details.
113
+ */
114
+ override var canvasMenu: ScopedProperty<EditorScope, EditorComponent<*>>? = {
115
+ rememberCanvasMenu()
116
+ }
117
+
118
+ /**
119
+ * The configuration of the component that is displayed over the editor. It is useful if you want to display a popup dialog or anything in the
120
+ * overlay.
121
+ * Check parent class declaration for more details.
122
+ */
123
+ override var bottomPanel: ScopedProperty<EditorScope, EditorComponent<*>>? = {
124
+ rememberBottomPanel()
125
+ }
126
+
127
+ /**
128
+ * The configuration of the component that is displayed over the editor. It is useful if you want to display a popup dialog or anything in the
129
+ * overlay.
130
+ * Check parent class declaration for more details.
131
+ */
132
+ override var overlay: ScopedProperty<EditorScope, EditorComponent<*>>? = {
133
+ rememberOverlay()
134
+ }
135
+ }
@@ -0,0 +1,191 @@
1
+ @file:OptIn(UnstableEditorApi::class)
2
+ @file:Suppress("UnusedReceiverParameter")
3
+
4
+ package ly.img.editor.configuration.video.callback
5
+
6
+ import androidx.core.net.toUri
7
+ import kotlinx.coroutines.coroutineScope
8
+ import kotlinx.coroutines.launch
9
+ import ly.img.editor.configuration.video.VideoConfigurationBuilder
10
+ import ly.img.editor.core.UnstableEditorApi
11
+ import ly.img.editor.core.library.data.AssetSourceType
12
+ import ly.img.editor.core.library.data.SystemGalleryAssetSource
13
+ import ly.img.editor.core.library.data.SystemGalleryPermission
14
+ import ly.img.editor.core.library.data.TextAssetSource
15
+ import ly.img.editor.core.library.data.TypefaceProvider
16
+ import ly.img.engine.Color
17
+ import ly.img.engine.DefaultAssetSource
18
+ import ly.img.engine.DemoAssetSource
19
+ import ly.img.engine.populateAssetSource
20
+
21
+ /**
22
+ * The callback that is invoked when the editor is created.
23
+ */
24
+ suspend fun VideoConfigurationBuilder.onCreate(
25
+ preCreateScene: suspend VideoConfigurationBuilder.() -> Unit = {
26
+ onPreCreateScene()
27
+ },
28
+ createScene: suspend VideoConfigurationBuilder.() -> Unit = {
29
+ onCreateScene()
30
+ },
31
+ loadAssetSources: suspend VideoConfigurationBuilder.() -> Unit = {
32
+ onLoadAssetSources()
33
+ },
34
+ postCreateScene: suspend VideoConfigurationBuilder.() -> Unit = {
35
+ onPostCreateScene()
36
+ },
37
+ finally: suspend VideoConfigurationBuilder.() -> Unit = {
38
+ onCreateFinally()
39
+ },
40
+ ) {
41
+ try {
42
+ preCreateScene()
43
+ createScene()
44
+ loadAssetSources()
45
+ postCreateScene()
46
+ } finally {
47
+ finally()
48
+ }
49
+ }
50
+
51
+ /**
52
+ * The callback that is invoked before the scene is created.
53
+ */
54
+ fun VideoConfigurationBuilder.onPreCreateScene() {
55
+ showLoading = true
56
+ val engine = editorContext.engine
57
+ engine.editor.setSettingEnum(keypath = "touch/pinchAction", value = "Scale")
58
+ engine.editor.setSettingBoolean(
59
+ keypath = "controlGizmo/showRotateHandles",
60
+ value = false,
61
+ )
62
+ engine.editor.setSettingBoolean(
63
+ keypath = "controlGizmo/showScaleHandles",
64
+ value = false,
65
+ )
66
+ engine.editor.setSettingBoolean(keypath = "controlGizmo/showMoveHandles", value = false)
67
+ engine.editor.setSettingBoolean(keypath = "touch/singlePointPanning", value = false)
68
+ engine.editor.setSettingColor(
69
+ keypath = "page/innerBorderColor",
70
+ value = Color.fromRGBA(0.67f, 0.67f, 0.67f, 0.5f),
71
+ )
72
+ }
73
+
74
+ /**
75
+ * The callback that is responsible for creating the scene.
76
+ */
77
+ // highlight-starter-kit-on-create-scene
78
+ suspend fun VideoConfigurationBuilder.onCreateScene() {
79
+ getOrLoadScene(sceneUri = "file:///android_asset/scene/video.scene".toUri())
80
+ }
81
+ // highlight-starter-kit-on-create-scene
82
+
83
+ /**
84
+ * The callback that loads all the required assets sources.
85
+ */
86
+ // highlight-starter-kit-on-load-asset-sources
87
+ suspend fun VideoConfigurationBuilder.onLoadAssetSources() {
88
+ // Load asset sources in parallel from content.json files
89
+ coroutineScope {
90
+ listOf(
91
+ DefaultAssetSource.STICKER.key,
92
+ DefaultAssetSource.VECTOR_PATH.key,
93
+ DefaultAssetSource.FILTER_LUT.key,
94
+ DefaultAssetSource.FILTER_DUO_TONE.key,
95
+ DefaultAssetSource.CROP_PRESETS.key,
96
+ DefaultAssetSource.PAGE_PRESETS.key,
97
+ DefaultAssetSource.EFFECT.key,
98
+ DefaultAssetSource.BLUR.key,
99
+ DefaultAssetSource.TYPEFACE.key,
100
+ DemoAssetSource.IMAGE.key,
101
+ DemoAssetSource.AUDIO.key,
102
+ DemoAssetSource.VIDEO.key,
103
+ DemoAssetSource.TEXT_COMPONENTS.key,
104
+ ).forEach { assetSource ->
105
+ launch {
106
+ val baseUri = editorContext.baseUri
107
+ editorContext.engine.populateAssetSource(
108
+ id = assetSource,
109
+ jsonUri = "$baseUri/$assetSource/content.json".toUri(),
110
+ replaceBaseUri = baseUri,
111
+ )
112
+ }
113
+ }
114
+ }
115
+
116
+ // Required for animations
117
+ editorContext.engine.block.setMetadata(
118
+ block = requireNotNull(editorContext.engine.scene.get()),
119
+ key = "ly.img.defaultAssetSourcesBaseUri",
120
+ value = editorContext.baseUri.toString(),
121
+ )
122
+
123
+ // Load local asset sources
124
+ editorContext.engine.asset.addLocalSource(
125
+ sourceId = DemoAssetSource.IMAGE_UPLOAD.key,
126
+ supportedMimeTypes = listOf(
127
+ "image/jpeg",
128
+ "image/png",
129
+ "image/heic",
130
+ "image/heif",
131
+ "image/svg+xml",
132
+ "image/gif",
133
+ "image/bmp",
134
+ ),
135
+ )
136
+
137
+ editorContext.engine.asset.addLocalSource(
138
+ sourceId = DemoAssetSource.AUDIO_UPLOAD.key,
139
+ supportedMimeTypes = listOf(
140
+ "audio/x-m4a",
141
+ "audio/mp3",
142
+ "audio/mpeg",
143
+ ),
144
+ )
145
+ editorContext.engine.asset.addLocalSource(
146
+ sourceId = DemoAssetSource.VIDEO_UPLOAD.key,
147
+ supportedMimeTypes = listOf(
148
+ "video/mp4",
149
+ ),
150
+ )
151
+
152
+ // Register gallery asset sources
153
+ listOf(
154
+ AssetSourceType.GalleryAllVisuals,
155
+ AssetSourceType.GalleryImage,
156
+ AssetSourceType.GalleryVideo,
157
+ ).forEach { type ->
158
+ editorContext.engine.asset.addSource(
159
+ source = SystemGalleryAssetSource(
160
+ context = editorContext.engine.applicationContext,
161
+ type = type,
162
+ ),
163
+ )
164
+ }
165
+ SystemGalleryPermission.setMode(systemGalleryConfiguration)
166
+
167
+ // Register text asset source
168
+ TypefaceProvider().provideTypeface(
169
+ engine = editorContext.engine,
170
+ name = "Roboto",
171
+ )?.let {
172
+ val textAssetSource = TextAssetSource(engine = editorContext.engine, typeface = it)
173
+ editorContext.engine.asset.addSource(textAssetSource)
174
+ }
175
+ }
176
+ // highlight-starter-kit-on-load-asset-sources
177
+
178
+ /**
179
+ * The callback that is invoked right after [onCreateScene], after the scene is created.
180
+ */
181
+ fun VideoConfigurationBuilder.onPostCreateScene() {
182
+ // Do nothing
183
+ }
184
+
185
+ /**
186
+ * The callback that is invoked as the last step of [onCreate].
187
+ * It always runs, no matter success or failure on previous steps.
188
+ */
189
+ fun VideoConfigurationBuilder.onCreateFinally() {
190
+ showLoading = false
191
+ }
@@ -0,0 +1,98 @@
1
+ package ly.img.editor.configuration.video.callback
2
+
3
+ import kotlinx.coroutines.CancellationException
4
+ import ly.img.editor.configuration.video.VideoConfigurationBuilder
5
+ import ly.img.editor.configuration.video.model.ExportStatus
6
+ import ly.img.engine.MimeType
7
+ import java.nio.ByteBuffer
8
+
9
+ /**
10
+ * The callback that is invoked when the export button is clicked.
11
+ */
12
+ suspend fun VideoConfigurationBuilder.onExport(
13
+ preExport: suspend VideoConfigurationBuilder.() -> Unit = {
14
+ onPreExport()
15
+ },
16
+ exportByteBuffer: suspend VideoConfigurationBuilder.() -> ByteBuffer = {
17
+ onExportByteBuffer()
18
+ },
19
+ postExport: suspend VideoConfigurationBuilder.(ByteBuffer) -> Unit = {
20
+ onPostExport(it)
21
+ },
22
+ error: suspend VideoConfigurationBuilder.(Exception) -> Unit = {
23
+ onExportError(it)
24
+ },
25
+ finally: suspend VideoConfigurationBuilder.() -> Unit = {
26
+ onExportFinally()
27
+ },
28
+ ) {
29
+ try {
30
+ preExport()
31
+ val result = exportByteBuffer()
32
+ postExport(result)
33
+ } catch (exception: Exception) {
34
+ error(exception)
35
+ } finally {
36
+ finally()
37
+ }
38
+ }
39
+
40
+ /**
41
+ * The callback that is invoked before the export is started.
42
+ */
43
+ fun VideoConfigurationBuilder.onPreExport() {
44
+ exportStatus = ExportStatus.Loading(progress = 0F)
45
+ }
46
+
47
+ /**
48
+ * The callback that exports the content of the editor into [ByteBuffer].
49
+ */
50
+ // highlight-starter-kit-on-export-byte-buffer
51
+ suspend fun VideoConfigurationBuilder.onExportByteBuffer(): ByteBuffer {
52
+ val targetDesignBlock = requireNotNull(editorContext.engine.scene.getCurrentPage())
53
+ return editorContext.engine.block.exportVideo(
54
+ block = targetDesignBlock,
55
+ timeOffset = 0.0,
56
+ duration = editorContext.engine.block.getDuration(targetDesignBlock),
57
+ mimeType = MimeType.MP4,
58
+ progressCallback = { progress ->
59
+ val lastExportStatus = exportStatus
60
+ val newProgress = progress.encodedFrames.toFloat() / progress.totalFrames
61
+ // Update export UI whenever the progress changes
62
+ if (lastExportStatus !is ExportStatus.Loading || newProgress >= lastExportStatus.progress + 0.01F) {
63
+ exportStatus = ExportStatus.Loading(progress = newProgress)
64
+ }
65
+ },
66
+ )
67
+ }
68
+ // highlight-starter-kit-on-export-byte-buffer
69
+
70
+ /**
71
+ * The callback that is invoked after [onExportByteBuffer] and handles its output.
72
+ */
73
+ // highlight-starter-kit-on-post-export
74
+ suspend fun VideoConfigurationBuilder.onPostExport(byteBuffer: ByteBuffer) {
75
+ val file = writeToFile(byteBuffer = byteBuffer, mimeType = MimeType.MP4)
76
+ exportStatus = ExportStatus.Success(file = file, mimeType = MimeType.MP4)
77
+ }
78
+ // highlight-starter-kit-on-post-export
79
+
80
+ /**
81
+ * The callback that is invoked in case any of the export functions throw an exception.
82
+ */
83
+ fun VideoConfigurationBuilder.onExportError(error: Exception) {
84
+ if (error is CancellationException) {
85
+ exportStatus = null
86
+ throw error
87
+ } else {
88
+ exportStatus = ExportStatus.Error(exception = error)
89
+ }
90
+ }
91
+
92
+ /**
93
+ * The callback that is invoked as the last step of [onExportByteBuffer].
94
+ * It always runs, no matter success or failure on previous steps.
95
+ */
96
+ fun VideoConfigurationBuilder.onExportFinally() {
97
+ showCancelExportConfirmationDialog = false
98
+ }
@@ -0,0 +1,20 @@
1
+ package ly.img.editor.configuration.video.callback
2
+
3
+ import androidx.compose.ui.unit.dp
4
+ import ly.img.editor.configuration.video.VideoConfigurationBuilder
5
+ import ly.img.editor.core.component.data.Insets
6
+
7
+ /**
8
+ * The callback that is invoked when the editor is loaded and ready to be used.
9
+ */
10
+ suspend fun VideoConfigurationBuilder.onLoaded() {
11
+ observeEditorEditMode(
12
+ extraInsets = {
13
+ if (it == "Crop") {
14
+ Insets(value = 24.dp)
15
+ } else {
16
+ Insets(horizontal = 16.dp, vertical = 8.dp)
17
+ }
18
+ },
19
+ )
20
+ }