@imgly/editor-react-native 1.40.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/IMGLYEditorModule.podspec +21 -0
- package/LICENSE.md +137 -0
- package/README.md +31 -0
- package/android/.gradle/8.9/checksums/checksums.lock +0 -0
- package/android/.gradle/8.9/dependencies-accessors/gc.properties +0 -0
- package/android/.gradle/8.9/fileChanges/last-build.bin +0 -0
- package/android/.gradle/8.9/fileHashes/fileHashes.lock +0 -0
- package/android/.gradle/8.9/gc.properties +0 -0
- package/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock +0 -0
- package/android/.gradle/buildOutputCleanup/cache.properties +2 -0
- package/android/.gradle/vcs-1/gc.properties +0 -0
- package/android/build.gradle +65 -0
- package/android/src/main/AndroidManifest.xml +8 -0
- package/android/src/main/assets/photo-ui-empty.png +0 -0
- package/android/src/main/kotlin/ly/img/editor/reactnative/module/IMGLYEditorModule.kt +252 -0
- package/android/src/main/kotlin/ly/img/editor/reactnative/module/IMGLYEditorPackage.kt +35 -0
- package/android/src/main/kotlin/ly/img/editor/reactnative/module/activity/EditorActivity.kt +112 -0
- package/android/src/main/kotlin/ly/img/editor/reactnative/module/builder/EditorBuilder.kt +478 -0
- package/android/src/main/kotlin/ly/img/editor/reactnative/module/helper/AssetHelper.kt +18 -0
- package/android/src/main/kotlin/ly/img/editor/reactnative/module/helper/IntentHelper.kt +61 -0
- package/android/src/main/kotlin/ly/img/editor/reactnative/module/model/EditorPreset.kt +47 -0
- package/android/src/main/kotlin/ly/img/editor/reactnative/module/model/EditorResult.kt +73 -0
- package/android/src/main/kotlin/ly/img/editor/reactnative/module/model/EditorSettings.kt +63 -0
- package/android/src/main/kotlin/ly/img/editor/reactnative/module/model/EditorSourceType.kt +39 -0
- package/android/src/main/kotlin/ly/img/editor/reactnative/module/model/Source.kt +44 -0
- package/android/src/newarch/IMGLYEditorModuleSpec.kt +7 -0
- package/android/src/oldarch/IMGLYEditorModuleSpec.kt +18 -0
- package/index.d.ts +3 -0
- package/index.js +3 -0
- package/ios/Constants/IMGLYConstants.h +13 -0
- package/ios/Constants/IMGLYConstants.m +13 -0
- package/ios/Extensions/OnCreate+.swift +75 -0
- package/ios/Extensions/OnExport+.swift +64 -0
- package/ios/Extensions/String+.swift +7 -0
- package/ios/Helper/ExportHelper.swift +67 -0
- package/ios/IMGLYEditorModule-Bridging-Header.h +3 -0
- package/ios/IMGLYEditorModule.h +11 -0
- package/ios/IMGLYEditorModule.mm +86 -0
- package/ios/IMGLYEditorModule.swift +110 -0
- package/ios/Model/EditorBuilder.swift +293 -0
- package/ios/Model/EditorPreset.swift +52 -0
- package/ios/Model/EditorResult.swift +27 -0
- package/ios/Model/EditorSettings.swift +33 -0
- package/ios/Model/EditorSourceType.swift +11 -0
- package/ios/Model/Source.swift +8 -0
- package/ios/View/ModalEditor.swift +55 -0
- package/package.json +46 -0
- package/src/NativeIMGLYEditor.ts +195 -0
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import UIKit
|
|
2
|
+
|
|
3
|
+
/// The iOS implementation for the `@imgly/editor-react-native` React Native module.
|
|
4
|
+
@objc(IMGLYEditorModuleSwiftAdapter) @objcMembers public class IMGLYEditorModuleSwiftAdapter: NSObject {
|
|
5
|
+
// MARK: - Typealias
|
|
6
|
+
|
|
7
|
+
/// A closure to specify an `EditorBuilder.Builder` based on a given `preset` and `metadata`.
|
|
8
|
+
public typealias IMGLYBuilderClosure = (_ preset: EditorPreset?, _ metadata: [String: Any]?) -> EditorBuilder.Builder
|
|
9
|
+
|
|
10
|
+
// MARK: - Properties
|
|
11
|
+
|
|
12
|
+
/// The shared instance.
|
|
13
|
+
public static var shared = IMGLYEditorModuleSwiftAdapter()
|
|
14
|
+
|
|
15
|
+
/// The `IMGLYBuilderClosure` to use for UI creation.
|
|
16
|
+
public var builderClosure: IMGLYBuilderClosure?
|
|
17
|
+
|
|
18
|
+
/// The `UIViewController` hosting the editor.
|
|
19
|
+
private var presentationController: UIViewController?
|
|
20
|
+
|
|
21
|
+
/// The current `EditorBuilder.EditorBuilderResult`.
|
|
22
|
+
private var currentResultHandler: EditorBuilder.EditorBuilderResult?
|
|
23
|
+
|
|
24
|
+
// MARK: - Editor
|
|
25
|
+
|
|
26
|
+
/// Opens the creative editor.
|
|
27
|
+
/// - Parameters:
|
|
28
|
+
/// - preset: The `EditorPreset` used to determine which UI preset to use.
|
|
29
|
+
/// - settings: The `EditorSettings` containing all relevant information for the editor.
|
|
30
|
+
/// - metadata: Any custom metadata used for the `EditorBuilder.Builder`.
|
|
31
|
+
/// - completion: The completion handler to execute once the editor failed, cancelled or exported.
|
|
32
|
+
public func openEditor(
|
|
33
|
+
_ preset: EditorPreset,
|
|
34
|
+
settings: EditorSettings,
|
|
35
|
+
metadata: [String: Any]?,
|
|
36
|
+
completion: @escaping (_ result: EditorResult?, _ error: NSError?) -> Void
|
|
37
|
+
) {
|
|
38
|
+
_openEditor(preset, settings: settings, metadata: metadata, completion: completion)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/// Opens the creative editor.
|
|
42
|
+
/// - Parameters:
|
|
43
|
+
/// - settings: The `EditorSettings` containing all relevant information for the editor.
|
|
44
|
+
/// - metadata: Any custom metadata used for the `EditorBuilder.Builder`.
|
|
45
|
+
/// - completion: The completion handler to execute once the editor failed, cancelled or exported.
|
|
46
|
+
public func openEditor(
|
|
47
|
+
settings: EditorSettings,
|
|
48
|
+
metadata: [String: Any]?,
|
|
49
|
+
completion: @escaping (_ result: EditorResult?, _ error: NSError?) -> Void
|
|
50
|
+
) {
|
|
51
|
+
_openEditor(nil, settings: settings, metadata: metadata, completion: completion)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
private func _openEditor(
|
|
55
|
+
_ preset: EditorPreset?,
|
|
56
|
+
settings: EditorSettings,
|
|
57
|
+
metadata: [String: Any]?,
|
|
58
|
+
completion: @escaping (_ result: EditorResult?, _ error: NSError?) -> Void
|
|
59
|
+
) {
|
|
60
|
+
let builder = builderClosure?(preset, metadata) ?? builderForPreset(preset)
|
|
61
|
+
// Assign the `currentResultHandler` in order to manage the calls to the completion handler.
|
|
62
|
+
currentResultHandler = { [weak self] result in
|
|
63
|
+
switch result {
|
|
64
|
+
case let .success(artifact):
|
|
65
|
+
completion(artifact, nil)
|
|
66
|
+
case let .failure(error):
|
|
67
|
+
completion(nil, error as NSError)
|
|
68
|
+
}
|
|
69
|
+
// Remove the handler to prevent multiple invokations.
|
|
70
|
+
self?.currentResultHandler = nil
|
|
71
|
+
self?.presentationController?.presentingViewController?.dismiss(animated: true)
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
presentationController = builder(settings, preset, metadata) { [weak self] result in
|
|
75
|
+
self?.currentResultHandler?(result)
|
|
76
|
+
}
|
|
77
|
+
presentationController?.modalPresentationStyle = .fullScreen
|
|
78
|
+
|
|
79
|
+
if let presentationController, let windowScene = UIApplication.shared.connectedScenes
|
|
80
|
+
.filter({ $0.activationState == .foregroundActive })
|
|
81
|
+
.first as? UIWindowScene {
|
|
82
|
+
if let rootViewController = windowScene.windows
|
|
83
|
+
.filter(\.isKeyWindow).first?.rootViewController {
|
|
84
|
+
rootViewController.present(presentationController, animated: true, completion: nil)
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// MARK: - Helpers
|
|
90
|
+
|
|
91
|
+
/// Returns the suitable `EditorBuilder.Builder` for a given `EditorPreset`.
|
|
92
|
+
/// - Parameter preset: The `EditorPreset`.
|
|
93
|
+
/// - Returns: The suitable `EditorBuilder.Builder`. Defaults to `EditorPreset.design`.
|
|
94
|
+
private func builderForPreset(_ preset: EditorPreset?) -> EditorBuilder.Builder {
|
|
95
|
+
switch preset {
|
|
96
|
+
case .apparel:
|
|
97
|
+
EditorBuilder.apparel()
|
|
98
|
+
case .postcard:
|
|
99
|
+
EditorBuilder.postcard()
|
|
100
|
+
case .photo:
|
|
101
|
+
EditorBuilder.photo()
|
|
102
|
+
case .video:
|
|
103
|
+
EditorBuilder.video()
|
|
104
|
+
case .design:
|
|
105
|
+
EditorBuilder.design()
|
|
106
|
+
default:
|
|
107
|
+
EditorBuilder.design()
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
import IMGLYApparelEditor
|
|
2
|
+
import IMGLYDesignEditor
|
|
3
|
+
import IMGLYPhotoEditor
|
|
4
|
+
import IMGLYPostcardEditor
|
|
5
|
+
import IMGLYVideoEditor
|
|
6
|
+
import SwiftUI
|
|
7
|
+
import UIKit
|
|
8
|
+
|
|
9
|
+
/// The `EditorBuilder` is used to build different editor configurations.
|
|
10
|
+
public enum EditorBuilder {
|
|
11
|
+
/// A closure used to return a `Result<EditorResult?, Error>` from the editor.
|
|
12
|
+
public typealias EditorBuilderResult = (Result<EditorResult?, Error>) -> Void
|
|
13
|
+
|
|
14
|
+
/// Closure allowing to return a custom UI based on various input.
|
|
15
|
+
/// - Parameters:
|
|
16
|
+
/// - settings: The `EditorSettings`.
|
|
17
|
+
/// - preset: The `EditorPreset` pointing to a prebuild UI configuration.
|
|
18
|
+
/// - metadata: The metadata.
|
|
19
|
+
/// - result: The `EditorBuilderResult` used to return a result.
|
|
20
|
+
/// - Returns: A `UIViewController`.
|
|
21
|
+
public typealias Builder = (
|
|
22
|
+
_ settings: EditorSettings,
|
|
23
|
+
_ preset: EditorPreset?,
|
|
24
|
+
_ metadata: [String: Any]?,
|
|
25
|
+
_ result: @escaping EditorBuilderResult
|
|
26
|
+
) -> UIViewController
|
|
27
|
+
|
|
28
|
+
/// The default apparel editor.
|
|
29
|
+
public static func apparel() -> Builder {
|
|
30
|
+
{ config, _, _, result in
|
|
31
|
+
@ViewBuilder func apparelEditor(settings _: EditorSettings, result: @escaping EditorBuilderResult) -> some View {
|
|
32
|
+
ModalApparelEditor(settings: config, result: result)
|
|
33
|
+
}
|
|
34
|
+
return UIHostingController(rootView: apparelEditor(settings: config, result: result))
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/// The default postcard editor.
|
|
39
|
+
public static func postcard() -> Builder {
|
|
40
|
+
{ config, _, _, result in
|
|
41
|
+
@ViewBuilder func postcardEditor(settings _: EditorSettings, result: @escaping EditorBuilderResult) -> some View {
|
|
42
|
+
ModalPostcardEditor(settings: config, result: result)
|
|
43
|
+
}
|
|
44
|
+
return UIHostingController(rootView: postcardEditor(settings: config, result: result))
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/// The default design editor.
|
|
49
|
+
public static func design() -> Builder {
|
|
50
|
+
{ settings, _, _, result in
|
|
51
|
+
@ViewBuilder func designEditor(settings: EditorSettings, result: @escaping EditorBuilderResult) -> some View {
|
|
52
|
+
ModalDesignEditor(settings: settings, result: result)
|
|
53
|
+
}
|
|
54
|
+
return UIHostingController(rootView: designEditor(settings: settings, result: result))
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/// The default photo editor.
|
|
59
|
+
public static func photo() -> Builder {
|
|
60
|
+
{ settings, _, _, result in
|
|
61
|
+
@ViewBuilder func photoEditor(settings: EditorSettings, result: @escaping EditorBuilderResult) -> some View {
|
|
62
|
+
ModalPhotoEditor(settings: settings, result: result)
|
|
63
|
+
}
|
|
64
|
+
return UIHostingController(rootView: photoEditor(settings: settings, result: result))
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/// The default video editor.
|
|
69
|
+
public static func video() -> Builder {
|
|
70
|
+
{ settings, _, _, result in
|
|
71
|
+
@ViewBuilder func videoEditor(settings: EditorSettings, result: @escaping EditorBuilderResult) -> some View {
|
|
72
|
+
ModalVideoEditor(settings: settings, result: result)
|
|
73
|
+
}
|
|
74
|
+
return UIHostingController(rootView: videoEditor(settings: settings, result: result))
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/// A custom editor implementation.
|
|
79
|
+
/// - Parameter contentProvider:
|
|
80
|
+
/// - Returns: A `Builder` providing the custom view.
|
|
81
|
+
public static func custom(_ contentProvider: @escaping (
|
|
82
|
+
_ settings: EditorSettings,
|
|
83
|
+
_ preset: EditorPreset?,
|
|
84
|
+
_ metadata: [String: Any]?,
|
|
85
|
+
_ result: @escaping EditorBuilderResult
|
|
86
|
+
) -> some View) -> Builder {
|
|
87
|
+
{ settings, preset, metadata, result in
|
|
88
|
+
let hostingController = UIHostingController(rootView: contentProvider(settings, preset, metadata, result))
|
|
89
|
+
return hostingController
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// MARK: - Custom
|
|
95
|
+
|
|
96
|
+
/// An extension for the editor views.
|
|
97
|
+
extension EditorBuilder {
|
|
98
|
+
/// The message to send if the native error has been dismissed after throwing an error.
|
|
99
|
+
private static let exportFailedMessage =
|
|
100
|
+
"Failed to initialize the editor. Please verify that the loaded license is correct."
|
|
101
|
+
|
|
102
|
+
/// Generates `EngineSettings` based on an `EditorSettings`.
|
|
103
|
+
/// - Parameter settings: The `EditorSettings`.
|
|
104
|
+
/// - Returns: The derived `EngineSettings`.
|
|
105
|
+
private static func engineSettings(for settings: EditorSettings) -> EngineSettings {
|
|
106
|
+
if let url = URL(string: settings.sceneBaseUri) {
|
|
107
|
+
EngineSettings(license: settings.license, userID: settings.userId, baseURL: url)
|
|
108
|
+
} else {
|
|
109
|
+
EngineSettings(license: settings.license, userID: settings.userId)
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/// A modal apparel editor handling native errors.
|
|
114
|
+
private struct ModalApparelEditor: View {
|
|
115
|
+
@Environment(\.dismiss) private var dismiss
|
|
116
|
+
private let settings: EditorSettings
|
|
117
|
+
private let result: EditorBuilderResult
|
|
118
|
+
|
|
119
|
+
init(settings: EditorSettings, result: @escaping EditorBuilderResult) {
|
|
120
|
+
self.settings = settings
|
|
121
|
+
self.result = result
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
var body: some View {
|
|
125
|
+
ModalEditor {
|
|
126
|
+
ApparelEditor(engineSettings(for: settings))
|
|
127
|
+
.imgly.onCreate { engine in
|
|
128
|
+
try await OnCreate.load(settings, defaultSource: ApparelEditor.defaultScene)(engine)
|
|
129
|
+
}
|
|
130
|
+
.imgly.onExport { engine, _ in
|
|
131
|
+
do {
|
|
132
|
+
let editorResult = try await OnExport.export(engine, .pdf)
|
|
133
|
+
result(.success(editorResult))
|
|
134
|
+
} catch {
|
|
135
|
+
result(.failure(error))
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
} onDismiss: { cancelled in
|
|
139
|
+
if cancelled {
|
|
140
|
+
result(.success(nil))
|
|
141
|
+
dismiss()
|
|
142
|
+
} else {
|
|
143
|
+
result(.failure(exportFailedMessage))
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/// A modal postcard editor handling native errors.
|
|
150
|
+
private struct ModalPostcardEditor: View {
|
|
151
|
+
@Environment(\.dismiss) private var dismiss
|
|
152
|
+
private let settings: EditorSettings
|
|
153
|
+
private let result: EditorBuilderResult
|
|
154
|
+
|
|
155
|
+
init(settings: EditorSettings, result: @escaping EditorBuilderResult) {
|
|
156
|
+
self.settings = settings
|
|
157
|
+
self.result = result
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
var body: some View {
|
|
161
|
+
ModalEditor {
|
|
162
|
+
PostcardEditor(engineSettings(for: settings))
|
|
163
|
+
.imgly.onCreate { engine in
|
|
164
|
+
try await OnCreate.load(settings, defaultSource: PostcardEditor.defaultScene)(engine)
|
|
165
|
+
}
|
|
166
|
+
.imgly.onExport { engine, _ in
|
|
167
|
+
do {
|
|
168
|
+
let editorResult = try await OnExport.export(engine, .pdf)
|
|
169
|
+
result(.success(editorResult))
|
|
170
|
+
} catch {
|
|
171
|
+
result(.failure(error))
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
} onDismiss: { cancelled in
|
|
175
|
+
if cancelled {
|
|
176
|
+
result(.success(nil))
|
|
177
|
+
dismiss()
|
|
178
|
+
} else {
|
|
179
|
+
result(.failure(exportFailedMessage))
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/// A modal design editor handling native errors.
|
|
186
|
+
private struct ModalDesignEditor: View {
|
|
187
|
+
@Environment(\.dismiss) private var dismiss
|
|
188
|
+
private let settings: EditorSettings
|
|
189
|
+
private let result: EditorBuilderResult
|
|
190
|
+
|
|
191
|
+
init(settings: EditorSettings, result: @escaping EditorBuilderResult) {
|
|
192
|
+
self.settings = settings
|
|
193
|
+
self.result = result
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
var body: some View {
|
|
197
|
+
ModalEditor {
|
|
198
|
+
DesignEditor(engineSettings(for: settings))
|
|
199
|
+
.imgly.onCreate { engine in
|
|
200
|
+
try await OnCreate.load(settings, defaultSource: DesignEditor.defaultScene)(engine)
|
|
201
|
+
}
|
|
202
|
+
.imgly.onExport { engine, _ in
|
|
203
|
+
do {
|
|
204
|
+
let editorResult = try await OnExport.export(engine, .pdf)
|
|
205
|
+
result(.success(editorResult))
|
|
206
|
+
} catch {
|
|
207
|
+
result(.failure(error))
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
} onDismiss: { cancelled in
|
|
211
|
+
if cancelled {
|
|
212
|
+
result(.success(nil))
|
|
213
|
+
dismiss()
|
|
214
|
+
} else {
|
|
215
|
+
result(.failure(exportFailedMessage))
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/// A modal photo editor handling native errors.
|
|
222
|
+
private struct ModalPhotoEditor: View {
|
|
223
|
+
@Environment(\.dismiss) private var dismiss
|
|
224
|
+
private let settings: EditorSettings
|
|
225
|
+
private let result: EditorBuilderResult
|
|
226
|
+
|
|
227
|
+
init(settings: EditorSettings, result: @escaping EditorBuilderResult) {
|
|
228
|
+
self.settings = settings
|
|
229
|
+
self.result = result
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
var body: some View {
|
|
233
|
+
ModalEditor {
|
|
234
|
+
PhotoEditor(engineSettings(for: settings))
|
|
235
|
+
.imgly.onCreate { engine in
|
|
236
|
+
try await OnCreate
|
|
237
|
+
.load(settings, settings.source?.type ?? .image, defaultSource: PhotoEditor.defaultImage)(engine)
|
|
238
|
+
}
|
|
239
|
+
.imgly.onExport { engine, _ in
|
|
240
|
+
do {
|
|
241
|
+
let editorResult = try await OnExport.export(engine, .png)
|
|
242
|
+
result(.success(editorResult))
|
|
243
|
+
} catch {
|
|
244
|
+
result(.failure(error))
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
} onDismiss: { cancelled in
|
|
248
|
+
if cancelled {
|
|
249
|
+
result(.success(nil))
|
|
250
|
+
dismiss()
|
|
251
|
+
} else {
|
|
252
|
+
result(.failure(exportFailedMessage))
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/// A modal video editor handling native errors.
|
|
259
|
+
private struct ModalVideoEditor: View {
|
|
260
|
+
@Environment(\.dismiss) private var dismiss
|
|
261
|
+
private let settings: EditorSettings
|
|
262
|
+
private let result: EditorBuilderResult
|
|
263
|
+
|
|
264
|
+
init(settings: EditorSettings, result: @escaping EditorBuilderResult) {
|
|
265
|
+
self.settings = settings
|
|
266
|
+
self.result = result
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
var body: some View {
|
|
270
|
+
ModalEditor {
|
|
271
|
+
VideoEditor(engineSettings(for: settings))
|
|
272
|
+
.imgly.onCreate { engine in
|
|
273
|
+
try await OnCreate.load(settings, defaultSource: VideoEditor.defaultScene)(engine)
|
|
274
|
+
}
|
|
275
|
+
.imgly.onExport { engine, eventHandler in
|
|
276
|
+
do {
|
|
277
|
+
let editorResult = try await OnExport.exportVideo(engine, eventHandler, .mp4)
|
|
278
|
+
result(.success(editorResult))
|
|
279
|
+
} catch {
|
|
280
|
+
result(.failure(error))
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
} onDismiss: { cancelled in
|
|
284
|
+
if cancelled {
|
|
285
|
+
result(.success(nil))
|
|
286
|
+
dismiss()
|
|
287
|
+
} else {
|
|
288
|
+
result(.failure(exportFailedMessage))
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/// An enum containing all prebuild editor configurations.
|
|
2
|
+
@objc public enum EditorPreset: Int {
|
|
3
|
+
/// The apparel editor.
|
|
4
|
+
case apparel
|
|
5
|
+
|
|
6
|
+
/// The postcard editor.
|
|
7
|
+
case postcard
|
|
8
|
+
|
|
9
|
+
/// The photo editor.
|
|
10
|
+
case photo
|
|
11
|
+
|
|
12
|
+
/// The video editor.
|
|
13
|
+
case video
|
|
14
|
+
|
|
15
|
+
/// The design editor.
|
|
16
|
+
case design
|
|
17
|
+
|
|
18
|
+
// Converts enum case to the corresponding string
|
|
19
|
+
public var stringValue: String {
|
|
20
|
+
switch self {
|
|
21
|
+
case .apparel: "apparel"
|
|
22
|
+
case .postcard: "postcard"
|
|
23
|
+
case .photo: "photo"
|
|
24
|
+
case .video: "video"
|
|
25
|
+
case .design: "design"
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Initialize from string
|
|
30
|
+
public static func fromString(_ rawValue: String) -> EditorPreset {
|
|
31
|
+
switch rawValue {
|
|
32
|
+
case "apparel": .apparel
|
|
33
|
+
case "postcard": .postcard
|
|
34
|
+
case "photo": .photo
|
|
35
|
+
case "video": .video
|
|
36
|
+
case "design": .design
|
|
37
|
+
default: .design
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
@objc @objcMembers public class EditorPresetParser: NSObject {
|
|
43
|
+
// Method to convert from NSString to EditorPreset enum
|
|
44
|
+
public static func fromString(_ rawValue: NSString) -> EditorPreset {
|
|
45
|
+
EditorPreset.fromString(rawValue as String)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Method to convert from EditorPreset enum to NSString
|
|
49
|
+
public static func toString(_ preset: EditorPreset) -> NSString {
|
|
50
|
+
preset.stringValue as NSString
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/// A struct representing the result of an editor export.
|
|
2
|
+
@objc @objcMembers public class EditorResult: NSObject {
|
|
3
|
+
/// The source of the exported scene.
|
|
4
|
+
public let scene: String?
|
|
5
|
+
|
|
6
|
+
/// The source of the exported artifact, e.g. image, video.
|
|
7
|
+
public let artifact: String?
|
|
8
|
+
|
|
9
|
+
/// The source of the exported thumbnail.
|
|
10
|
+
public let thumbnail: String?
|
|
11
|
+
|
|
12
|
+
/// The associated metadata.
|
|
13
|
+
public let metadata: [String: Any]
|
|
14
|
+
|
|
15
|
+
/// Creates a new `EditorResult`.
|
|
16
|
+
/// - Parameters:
|
|
17
|
+
/// - scene: The source of the exported scene.
|
|
18
|
+
/// - artifact: The source of the exported artifact, e.g. image, video.
|
|
19
|
+
/// - thumbnail: The source of the exported thumbnail.
|
|
20
|
+
/// - metadata: The associated metadata.
|
|
21
|
+
public init(scene: String?, artifact: String?, thumbnail: String?, metadata: [String: Any] = [:]) {
|
|
22
|
+
self.scene = scene
|
|
23
|
+
self.artifact = artifact
|
|
24
|
+
self.thumbnail = thumbnail
|
|
25
|
+
self.metadata = metadata
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/// A struct containing all necessary settings to setup the editor.
|
|
2
|
+
@objc @objcMembers public class EditorSettings: NSObject, Codable {
|
|
3
|
+
/// The license key.
|
|
4
|
+
public let license: String
|
|
5
|
+
|
|
6
|
+
/// The base uri for the assets included in the scene that have a relative source.
|
|
7
|
+
public let sceneBaseUri: String
|
|
8
|
+
|
|
9
|
+
/// The base uri of the default assets in the asset library.
|
|
10
|
+
public let assetBaseUri: String?
|
|
11
|
+
|
|
12
|
+
/// The id of the current user.
|
|
13
|
+
public let userId: String?
|
|
14
|
+
|
|
15
|
+
/// The source to load into the editor.
|
|
16
|
+
public var source: Source?
|
|
17
|
+
|
|
18
|
+
/// Creates a new instance from a given dictionary.
|
|
19
|
+
///
|
|
20
|
+
/// - Parameters:
|
|
21
|
+
/// - dictionary: The dictionary to convert the instance from.
|
|
22
|
+
/// - Returns: The `EditorSettings` instance.
|
|
23
|
+
public static func fromDictionary(_ dictionary: [String: Any]) -> EditorSettings? {
|
|
24
|
+
do {
|
|
25
|
+
let data = try JSONSerialization.data(withJSONObject: dictionary, options: [])
|
|
26
|
+
let settings = try JSONDecoder().decode(EditorSettings.self, from: data)
|
|
27
|
+
return settings
|
|
28
|
+
} catch {
|
|
29
|
+
print("Error decoding dictionary: \(error)")
|
|
30
|
+
return nil
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/// The `EditorSourceType` defines the type of source that is loaded into the editor.
|
|
2
|
+
public enum EditorSourceType: String, Codable {
|
|
3
|
+
/// A `.scene` file.
|
|
4
|
+
case scene
|
|
5
|
+
|
|
6
|
+
/// An image file, e.g. `.png`.
|
|
7
|
+
case image
|
|
8
|
+
|
|
9
|
+
/// A video file, e.g. `.mp4`.
|
|
10
|
+
case video
|
|
11
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import IMGLYEditor
|
|
2
|
+
import SwiftUI
|
|
3
|
+
|
|
4
|
+
/// The `ModalEditor` contains an editor and adds the top navigation bar.
|
|
5
|
+
public struct ModalEditor<Editor: View, Label: View>: View {
|
|
6
|
+
@ViewBuilder private let editor: () -> Editor
|
|
7
|
+
@ViewBuilder private let dismissLabel: () -> Label
|
|
8
|
+
private let onDismiss: (_ cancelled: Bool) -> Void
|
|
9
|
+
|
|
10
|
+
/// Initializes a new `ModalEditor`.
|
|
11
|
+
/// - Parameters:
|
|
12
|
+
/// - editor: The editor that is contained.
|
|
13
|
+
/// - dismissLabel: The label used for the dismiss action.
|
|
14
|
+
/// - onDismiss: The closure called when the editor is dismissed.
|
|
15
|
+
/// - cancelled: Indicates whether the editor has been dismissed by the user.
|
|
16
|
+
/// If `false`, the editor has been closed due to an error.
|
|
17
|
+
public init(@ViewBuilder editor: @escaping () -> Editor,
|
|
18
|
+
@ViewBuilder dismissLabel: @escaping () -> Label = { SwiftUI.Label("Home", systemImage: "house") },
|
|
19
|
+
onDismiss: @escaping (_ cancelled: Bool) -> Void) {
|
|
20
|
+
self.editor = editor
|
|
21
|
+
self.dismissLabel = dismissLabel
|
|
22
|
+
self.onDismiss = onDismiss
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
@State private var isBackButtonHidden = false
|
|
26
|
+
@Environment(\.dismiss) private var dismiss
|
|
27
|
+
|
|
28
|
+
@ViewBuilder private var dismissButton: some View {
|
|
29
|
+
Button {
|
|
30
|
+
onDismiss(true)
|
|
31
|
+
} label: {
|
|
32
|
+
dismissLabel()
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
public var body: some View {
|
|
37
|
+
NavigationView {
|
|
38
|
+
editor()
|
|
39
|
+
.onPreferenceChange(BackButtonHiddenKey.self) { newValue in
|
|
40
|
+
isBackButtonHidden = newValue
|
|
41
|
+
}
|
|
42
|
+
.toolbar {
|
|
43
|
+
ToolbarItem(placement: .navigationBarLeading) {
|
|
44
|
+
if !isBackButtonHidden {
|
|
45
|
+
dismissButton
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
.onDisappear(perform: {
|
|
50
|
+
onDismiss(false)
|
|
51
|
+
})
|
|
52
|
+
}
|
|
53
|
+
.navigationViewStyle(.stack)
|
|
54
|
+
}
|
|
55
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@imgly/editor-react-native",
|
|
3
|
+
"version": "1.40.0",
|
|
4
|
+
"description": "CreativeEditor SDK for React Native - enable photo, video and design editing for your users on iOS and Android.",
|
|
5
|
+
"react-native": "index.js",
|
|
6
|
+
"source": "index.js",
|
|
7
|
+
"types": "index.d.ts",
|
|
8
|
+
"files": [
|
|
9
|
+
"src",
|
|
10
|
+
"index.js",
|
|
11
|
+
"index.d.ts",
|
|
12
|
+
"android",
|
|
13
|
+
"ios",
|
|
14
|
+
"IMGLYEditorModule.podspec",
|
|
15
|
+
"README.md",
|
|
16
|
+
"LICENSE.md",
|
|
17
|
+
"!android/build",
|
|
18
|
+
"!ios/build",
|
|
19
|
+
"!**/__tests__",
|
|
20
|
+
"!**/__fixtures__",
|
|
21
|
+
"!**/__mocks__"
|
|
22
|
+
],
|
|
23
|
+
"keywords": [
|
|
24
|
+
"react-native",
|
|
25
|
+
"ios",
|
|
26
|
+
"android",
|
|
27
|
+
"cesdk",
|
|
28
|
+
"editor",
|
|
29
|
+
"imgly"
|
|
30
|
+
],
|
|
31
|
+
"author": "IMG.LY GmbH",
|
|
32
|
+
"license": "SEE LICENSE IN LICENSE.md",
|
|
33
|
+
"homepage": "https://img.ly",
|
|
34
|
+
"peerDependencies": {
|
|
35
|
+
"react": "*",
|
|
36
|
+
"react-native": "*"
|
|
37
|
+
},
|
|
38
|
+
"codegenConfig": {
|
|
39
|
+
"name": "IMGLYEditorModuleSpec",
|
|
40
|
+
"type": "modules",
|
|
41
|
+
"jsSrcsDir": "./",
|
|
42
|
+
"android": {
|
|
43
|
+
"javaPackageName": "ly.img.editor.reactnative.module"
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|