@imgly/editor-react-native 1.73.0 → 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.
- package/android/build.gradle +1 -1
- package/android/src/main/assets/scene/apparel.scene +1 -0
- package/android/src/main/assets/scene/design.scene +1 -0
- package/android/src/main/assets/scene/postcard.scene +1 -0
- package/android/src/main/assets/scene/video.scene +1 -0
- package/android/src/main/kotlin/ly/img/editor/configuration/apparel/ApparelConfigurationBuilder.kt +113 -0
- package/android/src/main/kotlin/ly/img/editor/configuration/apparel/EditorActivity.kt +37 -0
- package/android/src/main/kotlin/ly/img/editor/configuration/apparel/callback/OnCreate.kt +190 -0
- package/android/src/main/kotlin/ly/img/editor/configuration/apparel/callback/OnExport.kt +82 -0
- package/android/src/main/kotlin/ly/img/editor/configuration/apparel/callback/OnLoaded.kt +88 -0
- package/android/src/main/kotlin/ly/img/editor/configuration/apparel/component/CanvasMenu.kt +45 -0
- package/android/src/main/kotlin/ly/img/editor/configuration/apparel/component/Dock.kt +37 -0
- package/android/src/main/kotlin/ly/img/editor/configuration/apparel/component/InspectorBar.kt +52 -0
- package/android/src/main/kotlin/ly/img/editor/configuration/apparel/component/NavigationBar.kt +45 -0
- package/android/src/main/kotlin/ly/img/editor/configuration/apparel/component/Overlay.kt +15 -0
- package/android/src/main/kotlin/ly/img/editor/configuration/design/DesignConfigurationBuilder.kt +106 -0
- package/android/src/main/kotlin/ly/img/editor/configuration/design/EditorActivity.kt +37 -0
- package/android/src/main/kotlin/ly/img/editor/configuration/design/callback/OnCreate.kt +162 -0
- package/android/src/main/kotlin/ly/img/editor/configuration/design/callback/OnExport.kt +82 -0
- package/android/src/main/kotlin/ly/img/editor/configuration/design/callback/OnLoaded.kt +10 -0
- package/android/src/main/kotlin/ly/img/editor/configuration/design/component/CanvasMenu.kt +45 -0
- package/android/src/main/kotlin/ly/img/editor/configuration/design/component/Dock.kt +35 -0
- package/android/src/main/kotlin/ly/img/editor/configuration/design/component/InspectorBar.kt +52 -0
- package/android/src/main/kotlin/ly/img/editor/configuration/design/component/NavigationBar.kt +45 -0
- package/android/src/main/kotlin/ly/img/editor/configuration/design/component/Overlay.kt +15 -0
- package/android/src/main/kotlin/ly/img/editor/configuration/photo/EditorActivity.kt +37 -0
- package/android/src/main/kotlin/ly/img/editor/configuration/photo/PhotoConfigurationBuilder.kt +106 -0
- package/android/src/main/kotlin/ly/img/editor/configuration/photo/callback/OnCreate.kt +143 -0
- package/android/src/main/kotlin/ly/img/editor/configuration/photo/callback/OnExport.kt +82 -0
- package/android/src/main/kotlin/ly/img/editor/configuration/photo/callback/OnLoaded.kt +49 -0
- package/android/src/main/kotlin/ly/img/editor/configuration/photo/component/CanvasMenu.kt +45 -0
- package/android/src/main/kotlin/ly/img/editor/configuration/photo/component/Dock.kt +43 -0
- package/android/src/main/kotlin/ly/img/editor/configuration/photo/component/InspectorBar.kt +52 -0
- package/android/src/main/kotlin/ly/img/editor/configuration/photo/component/NavigationBar.kt +45 -0
- package/android/src/main/kotlin/ly/img/editor/configuration/photo/component/Overlay.kt +15 -0
- package/android/src/main/kotlin/ly/img/editor/configuration/postcard/EditorActivity.kt +37 -0
- package/android/src/main/kotlin/ly/img/editor/configuration/postcard/PostcardConfigurationBuilder.kt +106 -0
- package/android/src/main/kotlin/ly/img/editor/configuration/postcard/callback/OnCreate.kt +149 -0
- package/android/src/main/kotlin/ly/img/editor/configuration/postcard/callback/OnExport.kt +82 -0
- package/android/src/main/kotlin/ly/img/editor/configuration/postcard/callback/OnLoaded.kt +58 -0
- package/android/src/main/kotlin/ly/img/editor/configuration/postcard/component/CanvasMenu.kt +45 -0
- package/android/src/main/kotlin/ly/img/editor/configuration/postcard/component/Dock.kt +243 -0
- package/android/src/main/kotlin/ly/img/editor/configuration/postcard/component/InspectorBar.kt +52 -0
- package/android/src/main/kotlin/ly/img/editor/configuration/postcard/component/NavigationBar.kt +76 -0
- package/android/src/main/kotlin/ly/img/editor/configuration/postcard/component/Overlay.kt +15 -0
- package/android/src/main/kotlin/ly/img/editor/configuration/postcard/ext/Engine.kt +107 -0
- package/android/src/main/kotlin/ly/img/editor/configuration/video/EditorActivity.kt +37 -0
- package/android/src/main/kotlin/ly/img/editor/configuration/video/VideoConfigurationBuilder.kt +135 -0
- package/android/src/main/kotlin/ly/img/editor/configuration/video/callback/OnCreate.kt +191 -0
- package/android/src/main/kotlin/ly/img/editor/configuration/video/callback/OnExport.kt +98 -0
- package/android/src/main/kotlin/ly/img/editor/configuration/video/callback/OnLoaded.kt +20 -0
- package/android/src/main/kotlin/ly/img/editor/configuration/video/component/BottomPanel.kt +13 -0
- package/android/src/main/kotlin/ly/img/editor/configuration/video/component/CanvasMenu.kt +45 -0
- package/android/src/main/kotlin/ly/img/editor/configuration/video/component/Dock.kt +71 -0
- package/android/src/main/kotlin/ly/img/editor/configuration/video/component/InspectorBar.kt +68 -0
- package/android/src/main/kotlin/ly/img/editor/configuration/video/component/NavigationBar.kt +57 -0
- package/android/src/main/kotlin/ly/img/editor/configuration/video/component/Overlay.kt +421 -0
- package/android/src/main/kotlin/ly/img/editor/configuration/video/iconPack/CheckCircleOutline.kt +79 -0
- package/android/src/main/kotlin/ly/img/editor/configuration/video/iconPack/ErrorOutline.kt +92 -0
- package/android/src/main/kotlin/ly/img/editor/configuration/video/iconPack/IconPack.kt +14 -0
- package/android/src/main/kotlin/ly/img/editor/configuration/video/model/ExportStatus.kt +39 -0
- package/ios/IMGLYEditorModule.swift +9 -1
- package/ios/StarterKits/Apparel/ApparelEditorConfiguration.swift +46 -0
- package/ios/StarterKits/Apparel/ApparelEditorStarterKit.swift +30 -0
- package/ios/StarterKits/Apparel/callbacks/OnChanged+Apparel.swift +116 -0
- package/ios/StarterKits/Apparel/callbacks/OnCreate+Apparel.swift +197 -0
- package/ios/StarterKits/Apparel/callbacks/OnExport+Apparel.swift +29 -0
- package/ios/StarterKits/Apparel/components/CanvasMenu+Apparel.swift +22 -0
- package/ios/StarterKits/Apparel/components/Dock+Apparel.swift +19 -0
- package/ios/StarterKits/Apparel/components/InspectorBar+Apparel.swift +35 -0
- package/ios/StarterKits/Apparel/components/NavigationBar+Apparel.swift +26 -0
- package/ios/StarterKits/Design/DesignEditorConfiguration.swift +43 -0
- package/ios/StarterKits/Design/DesignEditorStarterKit.swift +30 -0
- package/ios/StarterKits/Design/callbacks/OnCreate+Design.swift +131 -0
- package/ios/StarterKits/Design/callbacks/OnExport+Design.swift +30 -0
- package/ios/StarterKits/Design/components/CanvasMenu+Design.swift +22 -0
- package/ios/StarterKits/Design/components/Dock+Design.swift +23 -0
- package/ios/StarterKits/Design/components/InspectorBar+Design.swift +35 -0
- package/ios/StarterKits/Design/components/NavigationBar+Design.swift +24 -0
- package/ios/StarterKits/Photo/PhotoEditorConfiguration.swift +48 -0
- package/ios/StarterKits/Photo/PhotoEditorStarterKit.swift +30 -0
- package/ios/StarterKits/Photo/callbacks/OnChanged+Photo.swift +25 -0
- package/ios/StarterKits/Photo/callbacks/OnCreate+Photo.swift +138 -0
- package/ios/StarterKits/Photo/callbacks/OnExport+Photo.swift +29 -0
- package/ios/StarterKits/Photo/callbacks/OnLoaded+Photo.swift +18 -0
- package/ios/StarterKits/Photo/components/CanvasMenu+Photo.swift +22 -0
- package/ios/StarterKits/Photo/components/Dock+Photo.swift +23 -0
- package/ios/StarterKits/Photo/components/InspectorBar+Photo.swift +39 -0
- package/ios/StarterKits/Photo/components/NavigationBar+Photo.swift +24 -0
- package/ios/StarterKits/Photo/examples/ExampleForceCrop.swift +30 -0
- package/ios/StarterKits/Postcard/PostcardEditorConfiguration.swift +45 -0
- package/ios/StarterKits/Postcard/PostcardEditorStarterKit.swift +30 -0
- package/ios/StarterKits/Postcard/callbacks/OnChanged+Postcard.swift +92 -0
- package/ios/StarterKits/Postcard/callbacks/OnCreate+Postcard.swift +127 -0
- package/ios/StarterKits/Postcard/callbacks/OnExport+Postcard.swift +29 -0
- package/ios/StarterKits/Postcard/components/CanvasMenu+Postcard.swift +22 -0
- package/ios/StarterKits/Postcard/components/Dock+Postcard.swift +34 -0
- package/ios/StarterKits/Postcard/components/DockButtons+Postcard.swift +129 -0
- package/ios/StarterKits/Postcard/components/InspectorBar+Postcard.swift +35 -0
- package/ios/StarterKits/Postcard/components/NavigationBar+Postcard.swift +38 -0
- package/ios/StarterKits/Video/VideoEditorConfiguration.swift +54 -0
- package/ios/StarterKits/Video/VideoEditorStarterKit.swift +30 -0
- package/ios/StarterKits/Video/callbacks/OnCreate+Video.swift +137 -0
- package/ios/StarterKits/Video/callbacks/OnExport+Video.swift +46 -0
- package/ios/StarterKits/Video/components/BottomPanel+Video.swift +16 -0
- package/ios/StarterKits/Video/components/CanvasMenu+Video.swift +22 -0
- package/ios/StarterKits/Video/components/Dock+Video.swift +30 -0
- package/ios/StarterKits/Video/components/InspectorBar+Video.swift +43 -0
- package/ios/StarterKits/Video/components/NavigationBar+Video.swift +32 -0
- package/ios/StarterKits/Video/examples/ExampleVideoDurationConstraints.swift +23 -0
- package/ios/StarterKits/apparel-ui-b-empty.scene +1 -0
- package/ios/StarterKits/design-ui-empty.scene +1 -0
- package/ios/StarterKits/photo-ui-empty.png +0 -0
- package/ios/StarterKits/postcard-empty.scene +1 -0
- package/ios/StarterKits/video-empty.scene +1 -0
- package/package.json +1 -1
- package/src/NativeIMGLYEditor.ts +1 -1
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
@file:Suppress("UnusedReceiverParameter")
|
|
2
|
+
|
|
3
|
+
package ly.img.editor.configuration.postcard.callback
|
|
4
|
+
|
|
5
|
+
import androidx.core.net.toUri
|
|
6
|
+
import kotlinx.coroutines.coroutineScope
|
|
7
|
+
import kotlinx.coroutines.launch
|
|
8
|
+
import ly.img.editor.configuration.postcard.PostcardConfigurationBuilder
|
|
9
|
+
import ly.img.editor.core.library.data.AssetSourceType
|
|
10
|
+
import ly.img.editor.core.library.data.SystemGalleryAssetSource
|
|
11
|
+
import ly.img.editor.core.library.data.SystemGalleryPermission
|
|
12
|
+
import ly.img.editor.core.library.data.TextAssetSource
|
|
13
|
+
import ly.img.editor.core.library.data.TypefaceProvider
|
|
14
|
+
import ly.img.engine.DefaultAssetSource
|
|
15
|
+
import ly.img.engine.DemoAssetSource
|
|
16
|
+
import ly.img.engine.GlobalScope
|
|
17
|
+
import ly.img.engine.populateAssetSource
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* The callback that is invoked when the editor is created.
|
|
21
|
+
*/
|
|
22
|
+
suspend fun PostcardConfigurationBuilder.onCreate(
|
|
23
|
+
preCreateScene: suspend PostcardConfigurationBuilder.() -> Unit = {
|
|
24
|
+
onPreCreateScene()
|
|
25
|
+
},
|
|
26
|
+
createScene: suspend PostcardConfigurationBuilder.() -> Unit = {
|
|
27
|
+
onCreateScene()
|
|
28
|
+
},
|
|
29
|
+
loadAssetSources: suspend PostcardConfigurationBuilder.() -> Unit = {
|
|
30
|
+
onLoadAssetSources()
|
|
31
|
+
},
|
|
32
|
+
postCreateScene: suspend PostcardConfigurationBuilder.() -> Unit = {
|
|
33
|
+
onPostCreateScene()
|
|
34
|
+
},
|
|
35
|
+
finally: suspend PostcardConfigurationBuilder.() -> Unit = {
|
|
36
|
+
onCreateFinally()
|
|
37
|
+
},
|
|
38
|
+
) {
|
|
39
|
+
try {
|
|
40
|
+
preCreateScene()
|
|
41
|
+
createScene()
|
|
42
|
+
loadAssetSources()
|
|
43
|
+
postCreateScene()
|
|
44
|
+
} finally {
|
|
45
|
+
finally()
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* The callback that is invoked before the scene is created.
|
|
51
|
+
*/
|
|
52
|
+
fun PostcardConfigurationBuilder.onPreCreateScene() {
|
|
53
|
+
showLoading = true
|
|
54
|
+
editorContext.engine.editor.setGlobalScope("editor/add", GlobalScope.DEFER)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* The callback that is responsible for creating the scene.
|
|
59
|
+
*/
|
|
60
|
+
// highlight-starter-kit-on-create-scene
|
|
61
|
+
suspend fun PostcardConfigurationBuilder.onCreateScene() {
|
|
62
|
+
getOrLoadScene(sceneUri = "file:///android_asset/scene/postcard.scene".toUri())
|
|
63
|
+
}
|
|
64
|
+
// highlight-starter-kit-on-create-scene
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* The callback that loads all the required assets sources.
|
|
68
|
+
*/
|
|
69
|
+
// highlight-starter-kit-on-load-asset-sources
|
|
70
|
+
suspend fun PostcardConfigurationBuilder.onLoadAssetSources() {
|
|
71
|
+
// Load asset sources in parallel from content.json files
|
|
72
|
+
coroutineScope {
|
|
73
|
+
listOf(
|
|
74
|
+
DefaultAssetSource.STICKER.key,
|
|
75
|
+
DefaultAssetSource.VECTOR_PATH.key,
|
|
76
|
+
DefaultAssetSource.FILTER_LUT.key,
|
|
77
|
+
DefaultAssetSource.FILTER_DUO_TONE.key,
|
|
78
|
+
DefaultAssetSource.CROP_PRESETS.key,
|
|
79
|
+
DefaultAssetSource.EFFECT.key,
|
|
80
|
+
DefaultAssetSource.BLUR.key,
|
|
81
|
+
DefaultAssetSource.TYPEFACE.key,
|
|
82
|
+
DemoAssetSource.IMAGE.key,
|
|
83
|
+
DemoAssetSource.TEXT_COMPONENTS.key,
|
|
84
|
+
).forEach { assetSource ->
|
|
85
|
+
launch {
|
|
86
|
+
val baseUri = editorContext.baseUri
|
|
87
|
+
editorContext.engine.populateAssetSource(
|
|
88
|
+
id = assetSource,
|
|
89
|
+
jsonUri = "$baseUri/$assetSource/content.json".toUri(),
|
|
90
|
+
replaceBaseUri = baseUri,
|
|
91
|
+
)
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Load local asset sources
|
|
97
|
+
editorContext.engine.asset.addLocalSource(
|
|
98
|
+
sourceId = DemoAssetSource.IMAGE_UPLOAD.key,
|
|
99
|
+
supportedMimeTypes = listOf(
|
|
100
|
+
"image/jpeg",
|
|
101
|
+
"image/png",
|
|
102
|
+
"image/heic",
|
|
103
|
+
"image/heif",
|
|
104
|
+
"image/svg+xml",
|
|
105
|
+
"image/gif",
|
|
106
|
+
"image/bmp",
|
|
107
|
+
),
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
// Register gallery asset sources
|
|
111
|
+
listOf(
|
|
112
|
+
AssetSourceType.GalleryAllVisuals,
|
|
113
|
+
AssetSourceType.GalleryImage,
|
|
114
|
+
AssetSourceType.GalleryVideo,
|
|
115
|
+
).forEach { type ->
|
|
116
|
+
editorContext.engine.asset.addSource(
|
|
117
|
+
source = SystemGalleryAssetSource(
|
|
118
|
+
context = editorContext.engine.applicationContext,
|
|
119
|
+
type = type,
|
|
120
|
+
),
|
|
121
|
+
)
|
|
122
|
+
}
|
|
123
|
+
SystemGalleryPermission.setMode(systemGalleryConfiguration)
|
|
124
|
+
|
|
125
|
+
// Register text asset source
|
|
126
|
+
TypefaceProvider().provideTypeface(
|
|
127
|
+
engine = editorContext.engine,
|
|
128
|
+
name = "Roboto",
|
|
129
|
+
)?.let {
|
|
130
|
+
val textAssetSource = TextAssetSource(engine = editorContext.engine, typeface = it)
|
|
131
|
+
editorContext.engine.asset.addSource(textAssetSource)
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
// highlight-starter-kit-on-load-asset-sources
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* The callback that is invoked right after [onCreateScene], after the scene is created.
|
|
138
|
+
*/
|
|
139
|
+
fun PostcardConfigurationBuilder.onPostCreateScene() {
|
|
140
|
+
// Do nothing
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* The callback that is invoked as the last step of [onCreate].
|
|
145
|
+
* It always runs, no matter success or failure on previous steps.
|
|
146
|
+
*/
|
|
147
|
+
fun PostcardConfigurationBuilder.onCreateFinally() {
|
|
148
|
+
showLoading = false
|
|
149
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
package ly.img.editor.configuration.postcard.callback
|
|
2
|
+
|
|
3
|
+
import kotlinx.coroutines.CancellationException
|
|
4
|
+
import ly.img.editor.configuration.postcard.PostcardConfigurationBuilder
|
|
5
|
+
import ly.img.engine.MimeType
|
|
6
|
+
import java.nio.ByteBuffer
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* The callback that is invoked when the export button is clicked.
|
|
10
|
+
*/
|
|
11
|
+
suspend fun PostcardConfigurationBuilder.onExport(
|
|
12
|
+
preExport: suspend PostcardConfigurationBuilder.() -> Unit = {
|
|
13
|
+
onPreExport()
|
|
14
|
+
},
|
|
15
|
+
exportByteBuffer: suspend PostcardConfigurationBuilder.() -> ByteBuffer = {
|
|
16
|
+
onExportByteBuffer()
|
|
17
|
+
},
|
|
18
|
+
postExport: suspend PostcardConfigurationBuilder.(ByteBuffer) -> Unit = {
|
|
19
|
+
onPostExport(it)
|
|
20
|
+
},
|
|
21
|
+
error: suspend PostcardConfigurationBuilder.(Exception) -> Unit = {
|
|
22
|
+
onExportError(it)
|
|
23
|
+
},
|
|
24
|
+
finally: suspend PostcardConfigurationBuilder.() -> Unit = {
|
|
25
|
+
onExportFinally()
|
|
26
|
+
},
|
|
27
|
+
) {
|
|
28
|
+
try {
|
|
29
|
+
preExport()
|
|
30
|
+
val result = exportByteBuffer()
|
|
31
|
+
postExport(result)
|
|
32
|
+
} catch (exception: Exception) {
|
|
33
|
+
error(exception)
|
|
34
|
+
} finally {
|
|
35
|
+
finally()
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* The callback that is invoked before the export is started.
|
|
41
|
+
*/
|
|
42
|
+
fun PostcardConfigurationBuilder.onPreExport() {
|
|
43
|
+
showLoading = true
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* The callback that exports the content of the editor into [ByteBuffer].
|
|
48
|
+
*/
|
|
49
|
+
// highlight-starter-kit-on-export-byte-buffer
|
|
50
|
+
suspend fun PostcardConfigurationBuilder.onExportByteBuffer(): ByteBuffer = export(
|
|
51
|
+
block = requireNotNull(editorContext.engine.scene.get()),
|
|
52
|
+
mimeType = MimeType.PDF,
|
|
53
|
+
)
|
|
54
|
+
// highlight-starter-kit-on-export-byte-buffer
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* The callback that is invoked after [onExportByteBuffer] and handles its output.
|
|
58
|
+
*/
|
|
59
|
+
// highlight-starter-kit-on-post-export
|
|
60
|
+
suspend fun PostcardConfigurationBuilder.onPostExport(byteBuffer: ByteBuffer) {
|
|
61
|
+
val file = writeToFile(byteBuffer = byteBuffer, mimeType = MimeType.PDF)
|
|
62
|
+
shareFile(file = file, mimeType = MimeType.PDF)
|
|
63
|
+
}
|
|
64
|
+
// highlight-starter-kit-on-post-export
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* The callback that is invoked in case any of the export functions throw an exception.
|
|
68
|
+
*/
|
|
69
|
+
fun PostcardConfigurationBuilder.onExportError(error: Exception) {
|
|
70
|
+
if (error is CancellationException) {
|
|
71
|
+
throw error
|
|
72
|
+
}
|
|
73
|
+
this.error = error
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* The callback that is invoked as the last step of [onExportByteBuffer].
|
|
78
|
+
* It always runs, no matter success or failure on previous steps.
|
|
79
|
+
*/
|
|
80
|
+
fun PostcardConfigurationBuilder.onExportFinally() {
|
|
81
|
+
showLoading = false
|
|
82
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
package ly.img.editor.configuration.postcard.callback
|
|
2
|
+
|
|
3
|
+
import android.content.res.Configuration
|
|
4
|
+
import kotlinx.coroutines.coroutineScope
|
|
5
|
+
import kotlinx.coroutines.flow.distinctUntilChangedBy
|
|
6
|
+
import kotlinx.coroutines.flow.filter
|
|
7
|
+
import kotlinx.coroutines.launch
|
|
8
|
+
import ly.img.editor.configuration.postcard.PostcardConfigurationBuilder
|
|
9
|
+
import ly.img.editor.core.state.EditorViewMode
|
|
10
|
+
import ly.img.engine.DesignBlockType
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* The callback that is invoked when the editor is loaded and ready to be used.
|
|
14
|
+
*/
|
|
15
|
+
suspend fun PostcardConfigurationBuilder.onLoaded() {
|
|
16
|
+
coroutineScope {
|
|
17
|
+
launch { observeEditorViewMode() }
|
|
18
|
+
launch { observeEditorEditMode() }
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Function that displays both pages vertically stacked and zooms out so that both of the pages are visible
|
|
24
|
+
* when the [EditorViewMode] is preview.
|
|
25
|
+
*/
|
|
26
|
+
suspend fun PostcardConfigurationBuilder.observeEditorViewMode(stackSpacing: Float = 16F) {
|
|
27
|
+
editorContext.state
|
|
28
|
+
.distinctUntilChangedBy { it.viewMode to it.insets }
|
|
29
|
+
.filter { it.viewMode is EditorViewMode.Preview }
|
|
30
|
+
.collect { state ->
|
|
31
|
+
val engine = editorContext.engine
|
|
32
|
+
// Display pages vertically stacked
|
|
33
|
+
val axis = if (editorContext.activity.resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE) {
|
|
34
|
+
"Horizontal"
|
|
35
|
+
} else {
|
|
36
|
+
"Vertical"
|
|
37
|
+
}
|
|
38
|
+
engine.block
|
|
39
|
+
.findByType(DesignBlockType.Stack)
|
|
40
|
+
.firstOrNull()
|
|
41
|
+
?.let {
|
|
42
|
+
engine.block.setEnum(block = it, property = "stack/axis", value = axis)
|
|
43
|
+
engine.block.setFloat(block = it, property = "stack/spacing", value = stackSpacing)
|
|
44
|
+
}
|
|
45
|
+
// Display both pages in preview mode
|
|
46
|
+
engine.scene.getPages().forEach {
|
|
47
|
+
engine.block.setVisible(block = it, visible = true)
|
|
48
|
+
}
|
|
49
|
+
engine.scene.immediateZoomToBlock(
|
|
50
|
+
block = requireNotNull(engine.scene.get()),
|
|
51
|
+
paddingLeft = state.insets.left.value,
|
|
52
|
+
paddingTop = state.insets.top.value,
|
|
53
|
+
paddingRight = state.insets.right.value,
|
|
54
|
+
paddingBottom = 0F,
|
|
55
|
+
forceUpdate = true,
|
|
56
|
+
)
|
|
57
|
+
}
|
|
58
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
@file:Suppress("UnusedReceiverParameter")
|
|
2
|
+
|
|
3
|
+
package ly.img.editor.configuration.postcard.component
|
|
4
|
+
|
|
5
|
+
import androidx.compose.runtime.Composable
|
|
6
|
+
import ly.img.editor.configuration.postcard.PostcardConfigurationBuilder
|
|
7
|
+
import ly.img.editor.core.component.CanvasMenu
|
|
8
|
+
import ly.img.editor.core.component.EditorComponentId
|
|
9
|
+
import ly.img.editor.core.component.remember
|
|
10
|
+
import ly.img.editor.core.component.rememberBringForward
|
|
11
|
+
import ly.img.editor.core.component.rememberDelete
|
|
12
|
+
import ly.img.editor.core.component.rememberDuplicate
|
|
13
|
+
import ly.img.editor.core.component.rememberSelectGroup
|
|
14
|
+
import ly.img.editor.core.component.rememberSendBackward
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* The configuration of the component that is displayed as horizontal list of items next to
|
|
18
|
+
* the selected design block.
|
|
19
|
+
*/
|
|
20
|
+
@Composable
|
|
21
|
+
fun PostcardConfigurationBuilder.rememberCanvasMenu() = CanvasMenu.remember {
|
|
22
|
+
listBuilder = {
|
|
23
|
+
CanvasMenu.ListBuilder.remember {
|
|
24
|
+
add { CanvasMenu.Button.rememberSelectGroup() }
|
|
25
|
+
if (editorContext.isSelectionInGroup) {
|
|
26
|
+
add {
|
|
27
|
+
CanvasMenu.Divider.remember {
|
|
28
|
+
id = { EditorComponentId("ly.img.component.canvasMenu.divider1") }
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
add { CanvasMenu.Button.rememberBringForward() }
|
|
33
|
+
add { CanvasMenu.Button.rememberSendBackward() }
|
|
34
|
+
if (editorContext.canSelectionMove) {
|
|
35
|
+
add {
|
|
36
|
+
CanvasMenu.Divider.remember {
|
|
37
|
+
id = { EditorComponentId("ly.img.component.canvasMenu.divider2") }
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
add { CanvasMenu.Button.rememberDuplicate() }
|
|
42
|
+
add { CanvasMenu.Button.rememberDelete() }
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
@file:OptIn(UnstableEditorApi::class)
|
|
2
|
+
@file:Suppress("UnusedReceiverParameter", "UnusedFlow")
|
|
3
|
+
|
|
4
|
+
package ly.img.editor.configuration.postcard.component
|
|
5
|
+
|
|
6
|
+
import androidx.compose.foundation.layout.Arrangement
|
|
7
|
+
import androidx.compose.runtime.Composable
|
|
8
|
+
import androidx.compose.runtime.Stable
|
|
9
|
+
import androidx.compose.runtime.collectAsState
|
|
10
|
+
import androidx.compose.runtime.getValue
|
|
11
|
+
import androidx.compose.runtime.remember
|
|
12
|
+
import androidx.compose.ui.graphics.Color
|
|
13
|
+
import androidx.compose.ui.res.stringResource
|
|
14
|
+
import kotlinx.coroutines.flow.emptyFlow
|
|
15
|
+
import kotlinx.coroutines.flow.map
|
|
16
|
+
import ly.img.editor.configuration.postcard.PostcardConfigurationBuilder
|
|
17
|
+
import ly.img.editor.configuration.postcard.ext.getCurrentPageIndex
|
|
18
|
+
import ly.img.editor.configuration.postcard.ext.getFill
|
|
19
|
+
import ly.img.editor.configuration.postcard.ext.getStrokeColor
|
|
20
|
+
import ly.img.editor.core.EditorContext
|
|
21
|
+
import ly.img.editor.core.EditorScope
|
|
22
|
+
import ly.img.editor.core.R
|
|
23
|
+
import ly.img.editor.core.ScopedProperty
|
|
24
|
+
import ly.img.editor.core.UnstableEditorApi
|
|
25
|
+
import ly.img.editor.core.component.AbstractButtonBuilder
|
|
26
|
+
import ly.img.editor.core.component.Button
|
|
27
|
+
import ly.img.editor.core.component.DefaultDecoration
|
|
28
|
+
import ly.img.editor.core.component.Dock
|
|
29
|
+
import ly.img.editor.core.component.EditorComponentId
|
|
30
|
+
import ly.img.editor.core.component.EditorTrigger
|
|
31
|
+
import ly.img.editor.core.component.data.EditorIcon
|
|
32
|
+
import ly.img.editor.core.component.data.GradientFill
|
|
33
|
+
import ly.img.editor.core.component.data.SolidFill
|
|
34
|
+
import ly.img.editor.core.component.remember
|
|
35
|
+
import ly.img.editor.core.component.rememberAssetLibrary
|
|
36
|
+
import ly.img.editor.core.event.EditorEvent
|
|
37
|
+
import ly.img.editor.core.iconpack.IconPack
|
|
38
|
+
import ly.img.editor.core.iconpack.SizeLCircled
|
|
39
|
+
import ly.img.editor.core.iconpack.SizeMCircled
|
|
40
|
+
import ly.img.editor.core.iconpack.SizeSCircled
|
|
41
|
+
import ly.img.editor.core.iconpack.Typeface
|
|
42
|
+
import ly.img.editor.core.sheet.SheetType
|
|
43
|
+
import ly.img.editor.core.state.EditorViewMode
|
|
44
|
+
import ly.img.editor.core.ui.EditorIcon
|
|
45
|
+
import ly.img.engine.DesignBlock
|
|
46
|
+
import ly.img.engine.DesignBlockType
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* The configuration of the component that is displayed as horizontal list of items at the bottom of the editor.
|
|
50
|
+
*/
|
|
51
|
+
@Composable
|
|
52
|
+
fun PostcardConfigurationBuilder.rememberDock() = Dock.remember {
|
|
53
|
+
scope = {
|
|
54
|
+
val activeSceneTrigger by EditorTrigger.remember {
|
|
55
|
+
editorContext.engine.scene.onActiveChanged()
|
|
56
|
+
}
|
|
57
|
+
val historyTrigger by EditorTrigger.remember(activeSceneTrigger) {
|
|
58
|
+
editorContext.engine.editor.onHistoryUpdated()
|
|
59
|
+
}
|
|
60
|
+
val pageIndex by remember(this, activeSceneTrigger) {
|
|
61
|
+
if (editorContext.engine.scene.get() == null) return@remember emptyFlow()
|
|
62
|
+
val stack = editorContext.engine.block.findByType(DesignBlockType.Stack).first()
|
|
63
|
+
editorContext.engine.event.subscribe(listOf(stack))
|
|
64
|
+
.map { editorContext.engine.getCurrentPageIndex() }
|
|
65
|
+
}.collectAsState(initial = 0)
|
|
66
|
+
// Update Dock whenever the active scene, editor history or current page index changes.
|
|
67
|
+
remember(this, pageIndex, historyTrigger) {
|
|
68
|
+
Dock.Scope(parentScope = this)
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
visible = {
|
|
72
|
+
val state by editorContext.state.collectAsState()
|
|
73
|
+
// Hide Dock in preview mode
|
|
74
|
+
state.viewMode !is EditorViewMode.Preview
|
|
75
|
+
}
|
|
76
|
+
decoration = {
|
|
77
|
+
// Show transparent background
|
|
78
|
+
Dock.DefaultDecoration(
|
|
79
|
+
background = Color.Transparent,
|
|
80
|
+
) { it() }
|
|
81
|
+
}
|
|
82
|
+
horizontalArrangement = {
|
|
83
|
+
remember(this) {
|
|
84
|
+
val isFirstPage = editorContext.engine.scene.get() != null &&
|
|
85
|
+
editorContext.engine.getCurrentPageIndex() == 0
|
|
86
|
+
// Show Dock start aligned on the first page and centered on the second page
|
|
87
|
+
if (isFirstPage) Arrangement.Start else Arrangement.Center
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
listBuilder = {
|
|
91
|
+
Dock.ListBuilder.remember {
|
|
92
|
+
add {
|
|
93
|
+
Dock.Button.rememberAssetLibrary {
|
|
94
|
+
visible = {
|
|
95
|
+
remember(this) {
|
|
96
|
+
editorContext.engine.getCurrentPageIndex() == 0
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
// Show divider only on the first page.
|
|
102
|
+
if (editorContext.engine.getCurrentPageIndex() == 0) {
|
|
103
|
+
add { Dock.Divider.remember() }
|
|
104
|
+
}
|
|
105
|
+
add { Dock.Button.rememberGreetingFont() }
|
|
106
|
+
add { Dock.Button.rememberGreetingSize() }
|
|
107
|
+
add { Dock.Button.rememberColors() }
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Greeting font button at the dock.
|
|
114
|
+
*/
|
|
115
|
+
@Composable
|
|
116
|
+
fun Dock.Button.rememberGreetingFont() = Dock.Button.remember {
|
|
117
|
+
id = { EditorComponentId("ly.img.component.dock.button.greetingFont") }
|
|
118
|
+
visible = {
|
|
119
|
+
remember(this) {
|
|
120
|
+
editorContext.engine.scene.run { getPages().indexOf(getCurrentPage()) == 1 }
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
vectorIcon = { IconPack.Typeface }
|
|
124
|
+
textString = { stringResource(R.string.ly_img_editor_dock_button_font) }
|
|
125
|
+
onClick = {
|
|
126
|
+
val designBlock = editorContext.engine.block.findByName("Greeting").first()
|
|
127
|
+
editorContext.eventHandler.send(
|
|
128
|
+
EditorEvent.Sheet.Open(SheetType.Font(designBlock = designBlock)),
|
|
129
|
+
)
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Greeting size button of the dock.
|
|
135
|
+
*/
|
|
136
|
+
@Composable
|
|
137
|
+
fun Dock.Button.rememberGreetingSize() = Dock.Button.remember {
|
|
138
|
+
id = { EditorComponentId("ly.img.component.dock.button.greetingSize") }
|
|
139
|
+
visible = {
|
|
140
|
+
remember(this) {
|
|
141
|
+
editorContext.engine.scene.run { getPages().indexOf(getCurrentPage()) == 1 }
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
vectorIcon = {
|
|
145
|
+
remember(this) {
|
|
146
|
+
val block = editorContext.engine.block.findByName("Greeting").firstOrNull()
|
|
147
|
+
requireNotNull(block) { "Page must have design block with name \"Greeting\"." }
|
|
148
|
+
val size = editorContext.engine.block.getFloat(block, "text/fontSize")
|
|
149
|
+
when {
|
|
150
|
+
size <= 14F -> IconPack.SizeSCircled
|
|
151
|
+
size > 18F -> IconPack.SizeLCircled
|
|
152
|
+
else -> IconPack.SizeMCircled
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
textString = { stringResource(R.string.ly_img_editor_dock_button_size) }
|
|
157
|
+
onClick = {
|
|
158
|
+
val designBlock = editorContext.engine.block.findByName("Greeting").first()
|
|
159
|
+
editorContext.eventHandler.send(
|
|
160
|
+
EditorEvent.Sheet.Open(SheetType.FontSize(designBlock = designBlock)),
|
|
161
|
+
)
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Colors button of the dock.
|
|
167
|
+
*/
|
|
168
|
+
@Stable
|
|
169
|
+
open class ColorsButtonScope(
|
|
170
|
+
parentScope: EditorScope,
|
|
171
|
+
private val colors: Map<DesignBlock, Color>,
|
|
172
|
+
) : Dock.ItemScope(parentScope) {
|
|
173
|
+
val EditorContext.colors: Map<DesignBlock, Color>
|
|
174
|
+
get() = this@ColorsButtonScope.colors
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Button builder of the [rememberColors] button.
|
|
179
|
+
*/
|
|
180
|
+
@Stable
|
|
181
|
+
class ColorsButtonBuilder : AbstractButtonBuilder<ColorsButtonScope>() {
|
|
182
|
+
override var scope: ScopedProperty<EditorScope, ColorsButtonScope> = {
|
|
183
|
+
remember(this) {
|
|
184
|
+
val engine = editorContext.engine
|
|
185
|
+
val colorMapping = sortedMapOf<String, Pair<DesignBlock, Color>>()
|
|
186
|
+
engine.scene.getCurrentPage()?.let { currentPage ->
|
|
187
|
+
val target = engine.block.findByName("Greeting")
|
|
188
|
+
.firstOrNull()
|
|
189
|
+
?.takeIf { engine.block.getParent(it) == currentPage }
|
|
190
|
+
?: currentPage
|
|
191
|
+
editorContext.collectColorsRecursively(target, colorMapping)
|
|
192
|
+
}
|
|
193
|
+
val colors = colorMapping.values.associate { (block, color) -> block to color }
|
|
194
|
+
ColorsButtonScope(parentScope = this, colors = colors)
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
private fun EditorContext.collectColorsRecursively(
|
|
199
|
+
designBlock: DesignBlock,
|
|
200
|
+
colorMapping: MutableMap<String, Pair<DesignBlock, Color>>,
|
|
201
|
+
) {
|
|
202
|
+
val name = engine.block.getName(designBlock)
|
|
203
|
+
if (name.isNotEmpty()) {
|
|
204
|
+
val color = if (engine.block.supportsFill(designBlock) && engine.block.isFillEnabled(designBlock)) {
|
|
205
|
+
when (val fillInfo = engine.getFill(designBlock)) {
|
|
206
|
+
is SolidFill, is GradientFill -> fillInfo.mainColor
|
|
207
|
+
else -> null
|
|
208
|
+
}
|
|
209
|
+
} else if (engine.block.supportsStroke(designBlock) && engine.block.isStrokeEnabled(designBlock)) {
|
|
210
|
+
engine.getStrokeColor(designBlock)
|
|
211
|
+
} else {
|
|
212
|
+
null
|
|
213
|
+
}
|
|
214
|
+
color?.let { colorMapping[name] = designBlock to color }
|
|
215
|
+
}
|
|
216
|
+
engine.block.getChildren(designBlock).forEach {
|
|
217
|
+
collectColorsRecursively(it, colorMapping)
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* Colors button of the dock.
|
|
224
|
+
*/
|
|
225
|
+
@Composable
|
|
226
|
+
fun Dock.Button.rememberColors() = Button.remember(::ColorsButtonBuilder) {
|
|
227
|
+
id = { EditorComponentId("ly.img.component.dock.button.colors") }
|
|
228
|
+
icon = {
|
|
229
|
+
val icon = remember(this) {
|
|
230
|
+
EditorIcon.Colors(
|
|
231
|
+
colors = editorContext.colors.values.toList(),
|
|
232
|
+
)
|
|
233
|
+
}
|
|
234
|
+
EditorIcon(icon = icon)
|
|
235
|
+
}
|
|
236
|
+
textString = { stringResource(R.string.ly_img_editor_dock_button_colors) }
|
|
237
|
+
onClick = {
|
|
238
|
+
editorContext.colors
|
|
239
|
+
.let { SheetType.Colors(designBlocks = it.keys.toList()) }
|
|
240
|
+
.let(EditorEvent.Sheet::Open)
|
|
241
|
+
.let(editorContext.eventHandler::send)
|
|
242
|
+
}
|
|
243
|
+
}
|
package/android/src/main/kotlin/ly/img/editor/configuration/postcard/component/InspectorBar.kt
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
@file:Suppress("UnusedReceiverParameter")
|
|
2
|
+
|
|
3
|
+
package ly.img.editor.configuration.postcard.component
|
|
4
|
+
|
|
5
|
+
import androidx.compose.runtime.Composable
|
|
6
|
+
import ly.img.editor.configuration.postcard.PostcardConfigurationBuilder
|
|
7
|
+
import ly.img.editor.core.component.InspectorBar
|
|
8
|
+
import ly.img.editor.core.component.remember
|
|
9
|
+
import ly.img.editor.core.component.rememberAdjustments
|
|
10
|
+
import ly.img.editor.core.component.rememberBlur
|
|
11
|
+
import ly.img.editor.core.component.rememberCrop
|
|
12
|
+
import ly.img.editor.core.component.rememberDelete
|
|
13
|
+
import ly.img.editor.core.component.rememberDuplicate
|
|
14
|
+
import ly.img.editor.core.component.rememberEditText
|
|
15
|
+
import ly.img.editor.core.component.rememberEffect
|
|
16
|
+
import ly.img.editor.core.component.rememberEnterGroup
|
|
17
|
+
import ly.img.editor.core.component.rememberFillStroke
|
|
18
|
+
import ly.img.editor.core.component.rememberFilter
|
|
19
|
+
import ly.img.editor.core.component.rememberFormatText
|
|
20
|
+
import ly.img.editor.core.component.rememberLayer
|
|
21
|
+
import ly.img.editor.core.component.rememberReplace
|
|
22
|
+
import ly.img.editor.core.component.rememberSelectGroup
|
|
23
|
+
import ly.img.editor.core.component.rememberShape
|
|
24
|
+
import ly.img.editor.core.component.rememberTextBackground
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* The configuration of the component that is displayed as horizontal list of items at the
|
|
28
|
+
* bottom of the editor when a design block is selected.
|
|
29
|
+
*/
|
|
30
|
+
@Composable
|
|
31
|
+
fun PostcardConfigurationBuilder.rememberInspectorBar() = InspectorBar.remember {
|
|
32
|
+
listBuilder = {
|
|
33
|
+
InspectorBar.ListBuilder.remember {
|
|
34
|
+
add { InspectorBar.Button.rememberReplace() } // Image, Sticker, Audio
|
|
35
|
+
add { InspectorBar.Button.rememberEditText() } // Text
|
|
36
|
+
add { InspectorBar.Button.rememberFormatText() } // Text
|
|
37
|
+
add { InspectorBar.Button.rememberFillStroke() } // Page, Image, Shape, Text
|
|
38
|
+
add { InspectorBar.Button.rememberTextBackground() } // Text
|
|
39
|
+
add { InspectorBar.Button.rememberCrop() } // Image
|
|
40
|
+
add { InspectorBar.Button.rememberAdjustments() } // Image
|
|
41
|
+
add { InspectorBar.Button.rememberFilter() } // Image
|
|
42
|
+
add { InspectorBar.Button.rememberEffect() } // Image
|
|
43
|
+
add { InspectorBar.Button.rememberBlur() } // Image
|
|
44
|
+
add { InspectorBar.Button.rememberShape() } // Image, Shape
|
|
45
|
+
add { InspectorBar.Button.rememberSelectGroup() } // Image, Sticker, Shape, Text
|
|
46
|
+
add { InspectorBar.Button.rememberEnterGroup() } // Group
|
|
47
|
+
add { InspectorBar.Button.rememberLayer() } // Image, Sticker, Shape, Text
|
|
48
|
+
add { InspectorBar.Button.rememberDuplicate() } // Image, Sticker, Shape, Text
|
|
49
|
+
add { InspectorBar.Button.rememberDelete() } // Image, Sticker, Shape, Text
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|