react-native-photo-video-editor 0.2.2 → 0.3.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/CHANGELOG.md CHANGED
@@ -2,6 +2,13 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## 0.3.0
6
+
7
+ - Breaking API change: migrate `initialStickerId: 'brand'` to `initialStickerIds: ['brand']`.
8
+ - Replace `initialStickerId` with `initialStickerIds` and add a top-right control on the selected default sticker to cycle through default stickers on Android and iOS. Swaps preserve transforms and support undo/redo; the button is enabled only for multiple IDs.
9
+ - Place the swap control on the sticker’s top-right corner, above the scale control, so it follows dragging and rotation.
10
+ - Remove dummy sticker data from the example; default stickers are supplied by the caller.
11
+
5
12
  ## 0.2.2
6
13
 
7
14
  - Add `initialStickerId` to place a matching `stickerAssets` image at the center when opening the photo or video editor on Android and iOS.
package/README.md CHANGED
@@ -57,18 +57,28 @@ See [API](docs/api.md), [architecture](docs/architecture.md), [photo editor](doc
57
57
  For local work, run `yarn`, then `yarn typecheck`, `yarn lint`, `yarn test`, and `yarn prepare`. See [CONTRIBUTING.md](CONTRIBUTING.md). MIT licensed; see [LICENSE](LICENSE).
58
58
 
59
59
  To place a sticker at the center automatically when opening either editor, pass
60
- `initialStickerId` matching exactly one entry in `stickerAssets`:
60
+ `initialStickerIds` containing unique IDs from `stickerAssets`:
61
61
 
62
62
  ```ts
63
63
  await openPhotoEditor({
64
64
  source: { uri: photoUri, type: 'photo' },
65
- stickerAssets: [{ id: 'brand', uri: 'https://example.com/brand-sticker.png' }],
66
- initialStickerId: 'brand',
65
+ stickerAssets: [
66
+ { id: 'brand', uri: 'https://example.com/brand-sticker.png' },
67
+ { id: 'alternate', uri: 'https://example.com/alternate.png' },
68
+ ],
69
+ initialStickerIds: ['brand', 'alternate'],
67
70
  });
68
71
  ```
69
72
 
70
- The sticker starts at the center of the media and can be moved, resized, or
71
- removed. The same option works with `openVideoEditor` and `openEditor`, even if
73
+ The first sticker starts at the center of the media and can be moved, resized, or
74
+ removed. The “Switch default sticker” control at the selected default sticker’s top-right
75
+ corner, above its bottom-right scale control, cycles through the IDs in
76
+ order and wraps around, replacing the current default sticker while preserving
77
+ its transforms. Switching is undoable. After deletion, use Undo to restore the sticker and its
78
+ controls. The swap control is disabled for one ID and appears only on the selected
79
+ default sticker. Failed swaps leave the existing sticker in place. The same option works with `openVideoEditor` and `openEditor`, even if
72
80
  `features.stickers` hides the sticker picker. Omit it to start without a sticker.
73
81
  An unknown or duplicate ID rejects with `E_INVALID_OPTIONS`; an unreadable image
74
82
  rejects with `E_SOURCE_UNREADABLE`. HTTPS and local sticker URIs are supported.
83
+
84
+ Migration: replace `initialStickerId: 'brand'` with `initialStickerIds: ['brand']`.
@@ -188,13 +188,32 @@ class PhotoVideoEditorActivity : Activity() {
188
188
  if (!isFinishing) insertInitialSticker()
189
189
  }
190
190
 
191
- private fun insertInitialSticker() {
192
- val id = request.optString("initialStickerId").takeIf { it.isNotBlank() } ?: return
191
+ private val initialStickerIds: List<String> by lazy {
192
+ val ids = request.optJSONArray("initialStickerIds")
193
+ if (ids == null) emptyList() else (0 until ids.length()).map { ids.optString(it) }.filter { it.isNotBlank() }.distinct()
194
+ }
195
+ private val initialStickerLayerId = java.util.UUID.randomUUID().toString()
196
+ private val initialStickerPaths = mutableMapOf<String, String>()
197
+ private var initialStickerLoading = false
198
+
199
+ private fun currentInitialSticker(): PhotoLayer? =
200
+ (photoSession?.layerStack?.layers ?: videoSession?.layerStack?.layers)?.firstOrNull { it.id == initialStickerLayerId }
201
+
202
+ private fun switchInitialSticker() {
203
+ if (initialStickerLoading || initialStickerIds.size < 2) return
204
+ val currentIndex = initialStickerIds.indexOf(currentInitialSticker()?.stickerId)
205
+ insertInitialSticker((currentIndex + 1) % initialStickerIds.size)
206
+ }
207
+
208
+ private fun insertInitialSticker(index: Int = 0) {
209
+ if (initialStickerLoading) return
210
+ val id = initialStickerIds.getOrNull(index) ?: return
193
211
  val asset = runtimeStickerAssets().firstOrNull { it.id == id } ?: return
212
+ initialStickerLoading = true
194
213
  window.setFlags(android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE, android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE)
195
214
  Thread {
196
215
  val path = try {
197
- val localPath = if (asset.uri.startsWith("https://", ignoreCase = true)) {
216
+ val localPath = initialStickerPaths[id] ?: if (asset.uri.startsWith("https://", ignoreCase = true)) {
198
217
  val output = File.createTempFile("pve_initial_sticker_", ".img", cacheDir)
199
218
  val connection = java.net.URL(asset.uri).openConnection().apply {
200
219
  connectTimeout = 10_000
@@ -210,20 +229,31 @@ class PhotoVideoEditorActivity : Activity() {
210
229
  }
211
230
  } catch (_: Exception) { null }
212
231
  runOnUiThread {
232
+ initialStickerLoading = false
213
233
  window.clearFlags(android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE)
214
234
  if (isFinishing || isDestroyed) return@runOnUiThread
215
235
  if (path == null) {
216
- finishWithError("The initial sticker could not be loaded.", "E_SOURCE_UNREADABLE")
236
+ if (initialStickerPaths.isEmpty()) finishWithError("The initial sticker could not be loaded.", "E_SOURCE_UNREADABLE")
237
+ else Toast.makeText(this, "Could not load this sticker. Try again.", Toast.LENGTH_SHORT).show()
217
238
  return@runOnUiThread
218
239
  }
240
+ initialStickerPaths[id] = path
219
241
  window.decorView.post {
220
242
  if (isFinishing || isDestroyed) return@post
221
- val layer = newSticker(stickerId = id, stickerUri = Uri.fromFile(File(path)).toString())
243
+ val uri = Uri.fromFile(File(path)).toString()
244
+ val fresh = newSticker(stickerId = id, stickerUri = uri)
245
+ val layer = currentInitialSticker()?.copy(stickerId = id, stickerUri = uri, overlayAspectRatio = fresh.overlayAspectRatio)
246
+ ?: fresh.copy(id = initialStickerLayerId)
247
+ val replace: (List<PhotoLayer>) -> List<PhotoLayer> = { layers ->
248
+ if (layers.any { it.id == initialStickerLayerId }) layers.map { if (it.id == initialStickerLayerId) layer else it }
249
+ else layers + layer
250
+ }
222
251
  if (mediaType == "photo") {
223
- photoSession?.layerStack?.commit { it + layer }
252
+ photoSession?.layerStack?.commit(replace)
253
+ onLayerStackChanged()
224
254
  selectLayer(layer.id)
225
255
  } else videoSession?.let { session ->
226
- session.layerStack.commit { it + layer }
256
+ session.layerStack.commit(replace)
227
257
  onVideoLayerStackChanged()
228
258
  selectVideoLayer(layer.id, session)
229
259
  }
@@ -320,6 +350,9 @@ class PhotoVideoEditorActivity : Activity() {
320
350
  previewContainer.addView(overlay, FrameLayout.LayoutParams(MATCH, MATCH))
321
351
 
322
352
  val layers = LayerOverlayView(this)
353
+ layers.swappableLayerId = initialStickerLayerId
354
+ layers.stickerSwapEnabled = initialStickerIds.size > 1
355
+ layers.onStickerSwap = { switchInitialSticker() }
323
356
  layerOverlay = layers
324
357
  previewContainer.addView(layers, FrameLayout.LayoutParams(MATCH, MATCH))
325
358
 
@@ -1501,6 +1534,9 @@ class PhotoVideoEditorActivity : Activity() {
1501
1534
  if (videoCropMode) videoCropOverlay.restore(videoMediaBounds(session, playerView, false), session.state.crop)
1502
1535
  }
1503
1536
  val layerOverlay = LayerOverlayView(this)
1537
+ layerOverlay.swappableLayerId = initialStickerLayerId
1538
+ layerOverlay.stickerSwapEnabled = initialStickerIds.size > 1
1539
+ layerOverlay.onStickerSwap = { switchInitialSticker() }
1504
1540
  videoLayerOverlay = layerOverlay
1505
1541
  preview.addView(layerOverlay, FrameLayout.LayoutParams(MATCH, MATCH))
1506
1542
  layerOverlay.onLayerDelete = { id ->
@@ -28,6 +28,11 @@ class LayerOverlayView(context: Context) : View(context) {
28
28
  set(value) { field = value; invalidate() }
29
29
  var selectedLayerId: String? = null
30
30
  set(value) { field = value; invalidate() }
31
+ var swappableLayerId: String? = null
32
+ set(value) { field = value; invalidate() }
33
+ var stickerSwapEnabled = false
34
+ set(value) { field = value; invalidate() }
35
+ var onStickerSwap: (() -> Unit)? = null
31
36
  var onLayerDelete: ((String) -> Unit)? = null
32
37
  var onLayerTapped: ((String?) -> Unit)? = null
33
38
  var onLayerDoubleTapped: ((String) -> Unit)? = null
@@ -71,6 +76,10 @@ class LayerOverlayView(context: Context) : View(context) {
71
76
  }
72
77
  drawControl(canvas, -half.first, -half.second, R.drawable.ic_close, Color.rgb(255, 100, 115))
73
78
  drawControl(canvas, half.first, half.second, R.drawable.ic_fullscreen, Color.rgb(167, 139, 250))
79
+ if (selected.type == LayerType.STICKER && selected.id == swappableLayerId) {
80
+ drawControl(canvas, half.first, -half.second, R.drawable.ic_swap_sticker,
81
+ if (stickerSwapEnabled && !selected.locked) Color.rgb(167, 139, 250) else Color.GRAY)
82
+ }
74
83
  canvas.restore()
75
84
  }
76
85
 
@@ -92,6 +101,17 @@ class LayerOverlayView(context: Context) : View(context) {
92
101
  if (selected != null && !selected.locked) {
93
102
  val handle = handlePoint(selected)
94
103
  val center = centerOf(selected)
104
+ if (selected.type == LayerType.STICKER && selected.id == swappableLayerId) {
105
+ val swap = swapPoint(selected)
106
+ val swapDistance = hypot(event.x - swap.first, event.y - swap.second)
107
+ val deleteDistance = hypot(event.x - (2 * center.first - handle.first), event.y - (2 * center.second - handle.second))
108
+ val scaleDistance = hypot(event.x - handle.first, event.y - handle.second)
109
+ if (swapDistance <= handleTouchRadius && swapDistance <= deleteDistance && swapDistance <= scaleDistance) {
110
+ resetGesture()
111
+ if (stickerSwapEnabled) onStickerSwap?.invoke()
112
+ return true
113
+ }
114
+ }
95
115
  if (hypot(event.x - (2 * center.first - handle.first), event.y - (2 * center.second - handle.second)) <= handleTouchRadius) {
96
116
  onLayerDelete?.invoke(selected.id); resetGesture(); return true
97
117
  }
@@ -225,6 +245,12 @@ class LayerOverlayView(context: Context) : View(context) {
225
245
  return Pair(center.first + (half.first * cos(radians) - half.second * sin(radians)).toFloat(), center.second + (half.first * sin(radians) + half.second * cos(radians)).toFloat())
226
246
  }
227
247
 
248
+ private fun swapPoint(layer: PhotoLayer): Pair<Float, Float> {
249
+ val center = centerOf(layer); val half = selectionHalfExtents(layer)
250
+ val radians = Math.toRadians(layer.rotationDegrees.toDouble())
251
+ return Pair(center.first + (half.first * cos(radians) + half.second * sin(radians)).toFloat(), center.second + (half.first * sin(radians) - half.second * cos(radians)).toFloat())
252
+ }
253
+
228
254
  private fun isHandleHit(layer: PhotoLayer, x: Float, y: Float): Boolean {
229
255
  val handle = handlePoint(layer)
230
256
  return hypot(x - handle.first, y - handle.second) <= handleTouchRadius
@@ -0,0 +1,3 @@
1
+ <vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="24dp" android:height="24dp" android:viewportWidth="24" android:viewportHeight="24">
2
+ <path android:fillColor="#FFFFFFFF" android:pathData="M7,7h11l-3,-3 1.4,-1.4L22,8l-5.6,5.4L15,12l3,-3H7zM17,17H6l3,3 -1.4,1.4L2,16l5.6,-5.4L9,12l-3,3h11z" />
3
+ </vector>
@@ -15,7 +15,10 @@ final class PhotoVideoEditorViewController: UIViewController {
15
15
  private let features: [String: Any]
16
16
  private let theme: [String: Any]
17
17
  private let exportOptions: [String: Any]
18
- private let initialStickerId: String?
18
+ private let initialStickerIds: [String]
19
+ private let initialStickerLayerID = UUID().uuidString
20
+ private var initialStickerImages: [String: (URL, UIImage)] = [:]
21
+ private var initialStickerLoading = false
19
22
  private let stickerAssets: [[String: Any]]
20
23
  var completion: ((PhotoVideoEditorOutcome) -> Void)?
21
24
 
@@ -119,7 +122,7 @@ final class PhotoVideoEditorViewController: UIViewController {
119
122
  theme: [String: Any] = [:],
120
123
  exportOptions: [String: Any] = [:],
121
124
  stickerAssets: [[String: Any]] = [],
122
- initialStickerId: String? = nil
125
+ initialStickerIds: [String] = []
123
126
  ) {
124
127
  self.uri = uri
125
128
  self.mediaType = mediaType
@@ -127,7 +130,7 @@ final class PhotoVideoEditorViewController: UIViewController {
127
130
  self.theme = theme
128
131
  self.exportOptions = exportOptions
129
132
  self.stickerAssets = stickerAssets
130
- self.initialStickerId = initialStickerId
133
+ self.initialStickerIds = initialStickerIds
131
134
  super.init(nibName: nil, bundle: nil)
132
135
  modalPresentationStyle = .fullScreen
133
136
  }
@@ -160,21 +163,68 @@ final class PhotoVideoEditorViewController: UIViewController {
160
163
  insertInitialSticker()
161
164
  }
162
165
 
163
- private func insertInitialSticker() {
164
- guard let id = initialStickerId,
165
- let asset = consumerStickerAssets().first(where: { $0.id == id }) else { return }
166
+ private func currentInitialSticker() -> PhotoLayer? {
167
+ (photoSession?.layerStack.layers ?? videoSession?.layerStack.layers ?? []).first { $0.id == initialStickerLayerID }
168
+ }
169
+
170
+ private func switchInitialSticker() {
171
+ guard !initialStickerLoading, initialStickerIds.count > 1 else { return }
172
+ let currentID = currentInitialSticker()?.stickerId
173
+ let currentIndex = currentID.flatMap { initialStickerIds.firstIndex(of: $0) } ?? -1
174
+ insertInitialSticker(index: (currentIndex + 1) % initialStickerIds.count)
175
+ }
176
+
177
+ private func insertInitialSticker(index: Int = 0) {
178
+ guard !initialStickerLoading, initialStickerIds.indices.contains(index) else { return }
179
+ let id = initialStickerIds[index]
180
+ guard let asset = consumerStickerAssets().first(where: { $0.id == id }) else { return }
181
+ initialStickerLoading = true
166
182
  view.isUserInteractionEnabled = false
167
- let loader = OnlineStickerSheetViewController()
168
- loader.loadRuntimeSticker(.init(id: id, uri: asset.uri)) { [weak self, loader] url, image in
169
- _ = loader // Keep the loader alive until its download finishes.
183
+ let apply: (URL?, UIImage?) -> Void = { [weak self] url, image in
170
184
  guard let self else { return }
185
+ self.initialStickerLoading = false
171
186
  self.view.isUserInteractionEnabled = true
172
187
  guard let url, let image else {
173
- self.completion?(.failure(code: "E_SOURCE_UNREADABLE", message: "The initial sticker could not be loaded."))
188
+ if self.initialStickerImages.isEmpty {
189
+ self.completion?(.failure(code: "E_SOURCE_UNREADABLE", message: "The initial sticker could not be loaded."))
190
+ } else {
191
+ let alert = UIAlertController(title: "Couldn't load sticker", message: "Please try again.", preferredStyle: .alert)
192
+ alert.addAction(UIAlertAction(title: "OK", style: .default))
193
+ self.present(alert, animated: true)
194
+ }
174
195
  return
175
196
  }
197
+ self.initialStickerImages[id] = (url, image)
176
198
  self.view.layoutIfNeeded()
177
- self.handlePickedImage(url, image: image, purpose: self.mediaType == "photo" ? .photoSticker : .videoSticker)
199
+ var layer = self.currentInitialSticker() ?? self.newSticker()
200
+ layer.id = self.initialStickerLayerID
201
+ layer.stickerId = id
202
+ layer.stickerUri = url.absoluteString
203
+ layer.overlayAspectRatio = max(image.size.width, 1) / max(image.size.height, 1)
204
+ let replace: ([PhotoLayer]) -> [PhotoLayer] = { layers in
205
+ if layers.contains(where: { $0.id == self.initialStickerLayerID }) {
206
+ return layers.map { $0.id == self.initialStickerLayerID ? layer : $0 }
207
+ }
208
+ return layers + [layer]
209
+ }
210
+ if let session = self.photoSession {
211
+ session.layerStack.commit(replace)
212
+ self.onLayerStackChanged()
213
+ self.selectLayer(layer.id)
214
+ } else if let session = self.videoSession {
215
+ session.layerStack.commit(replace)
216
+ self.onVideoLayerStackChanged()
217
+ self.selectVideoLayer(layer.id, session: session)
218
+ }
219
+ }
220
+ if let cached = initialStickerImages[id] {
221
+ apply(cached.0, cached.1)
222
+ } else {
223
+ let loader = OnlineStickerSheetViewController()
224
+ loader.loadRuntimeSticker(.init(id: id, uri: asset.uri)) { [loader] url, image in
225
+ _ = loader // Keep the loader alive until its download finishes.
226
+ apply(url, image)
227
+ }
178
228
  }
179
229
  }
180
230
 
@@ -233,7 +283,10 @@ final class PhotoVideoEditorViewController: UIViewController {
233
283
  overlay.bottomAnchor.constraint(equalTo: preview.bottomAnchor),
234
284
  ])
235
285
 
236
- let layers = LayerOverlayView()
286
+ let layers = LayerOverlayView(frame: .zero)
287
+ layers.swappableLayerID = initialStickerLayerID
288
+ layers.stickerSwapEnabled = initialStickerIds.count > 1
289
+ layers.onStickerSwap = { [weak self] in self?.switchInitialSticker() }
237
290
  layerOverlay = layers
238
291
  preview.addSubview(layers)
239
292
  layers.translatesAutoresizingMaskIntoConstraints = false
@@ -1568,7 +1621,10 @@ final class PhotoVideoEditorViewController: UIViewController {
1568
1621
  let scale = bounds.width/max(fitted.width,0.001)
1569
1622
  playerView.transform = CGAffineTransform(translationX:bounds.midX-fitted.midX,y:bounds.midY-fitted.midY).scaledBy(x:scale,y:scale)
1570
1623
  }
1571
- let videoLayers = LayerOverlayView()
1624
+ let videoLayers = LayerOverlayView(frame: .zero)
1625
+ videoLayers.swappableLayerID = initialStickerLayerID
1626
+ videoLayers.stickerSwapEnabled = initialStickerIds.count > 1
1627
+ videoLayers.onStickerSwap = { [weak self] in self?.switchInitialSticker() }
1572
1628
  videoLayerOverlay = videoLayers
1573
1629
  preview.addSubview(videoLayers)
1574
1630
  videoLayers.translatesAutoresizingMaskIntoConstraints = false
@@ -8,6 +8,9 @@ final class LayerOverlayView: UIView {
8
8
  var maxScale: CGFloat = 8
9
9
  var layers: [PhotoLayer] = [] { didSet { setNeedsDisplay() } }
10
10
  var selectedLayerID: String? { didSet { setNeedsDisplay() } }
11
+ var swappableLayerID: String? { didSet { setNeedsDisplay() } }
12
+ var stickerSwapEnabled = false { didSet { setNeedsDisplay() } }
13
+ var onStickerSwap: (() -> Void)?
11
14
  var onLayerDelete: ((String) -> Void)?
12
15
  var onLayerTapped: ((String?) -> Void)?
13
16
  var onLayerDoubleTapped: ((String) -> Void)?
@@ -52,6 +55,9 @@ final class LayerOverlayView: UIView {
52
55
  }
53
56
  drawControl(context, point: CGPoint(x: -half.width, y: -half.height), symbol: "xmark", tint: .systemRed)
54
57
  drawControl(context, point: CGPoint(x: half.width, y: half.height), symbol: "arrow.up.left.and.arrow.down.right", tint: DesignTokens.primary)
58
+ if layer.type == .sticker && layer.id == swappableLayerID {
59
+ drawControl(context, point: CGPoint(x: half.width, y: -half.height), symbol: "arrow.left.arrow.right", tint: stickerSwapEnabled && !layer.locked ? DesignTokens.primary : .gray)
60
+ }
55
61
  context.restoreGState()
56
62
  }
57
63
 
@@ -80,6 +86,14 @@ final class LayerOverlayView: UIView {
80
86
  if let selected, !selected.locked {
81
87
  let center = center(of: selected); let handle = handlePoint(selected)
82
88
  let deletePoint = CGPoint(x: center.x * 2 - handle.x, y: center.y * 2 - handle.y)
89
+ if selected.type == .sticker && selected.id == swappableLayerID {
90
+ let swapDistance = distance(swapPoint(selected), point)
91
+ if swapDistance <= handleTouchRadius && swapDistance <= distance(deletePoint, point) && swapDistance <= distance(handle, point) {
92
+ resetGesture()
93
+ if stickerSwapEnabled { onStickerSwap?() }
94
+ return
95
+ }
96
+ }
83
97
  if distance(deletePoint, point) <= handleTouchRadius { onLayerDelete?(selected.id); resetGesture(); return }
84
98
  }
85
99
  let handleHit = selected.flatMap { !$0.locked && isHandleHit($0, point) ? $0 : nil }
@@ -178,6 +192,10 @@ final class LayerOverlayView: UIView {
178
192
  let center = center(of: layer); let half = selectionHalfExtents(layer); let radians = layer.rotationDegrees * .pi / 180
179
193
  return CGPoint(x: center.x + half.width * cos(radians) - half.height * sin(radians), y: center.y + half.width * sin(radians) + half.height * cos(radians))
180
194
  }
195
+ private func swapPoint(_ layer: PhotoLayer) -> CGPoint {
196
+ let center = center(of: layer); let half = selectionHalfExtents(layer); let radians = layer.rotationDegrees * .pi / 180
197
+ return CGPoint(x: center.x + half.width * cos(radians) + half.height * sin(radians), y: center.y + half.width * sin(radians) - half.height * cos(radians))
198
+ }
181
199
  private func isHandleHit(_ layer: PhotoLayer, _ point: CGPoint) -> Bool { distance(handlePoint(layer), point) <= handleTouchRadius }
182
200
  private func hitTest(_ point: CGPoint) -> PhotoLayer? {
183
201
  for layer in layers.reversed() where layer.visible {
@@ -31,7 +31,7 @@ public class PhotoVideoEditorSwift: NSObject {
31
31
  theme: payload["theme"] as? [String: Any] ?? [:],
32
32
  exportOptions: payload["export"] as? [String: Any] ?? [:],
33
33
  stickerAssets: payload["stickerAssets"] as? [[String: Any]] ?? [],
34
- initialStickerId: payload["initialStickerId"] as? String
34
+ initialStickerIds: payload["initialStickerIds"] as? [String] ?? []
35
35
  )
36
36
  controller.completion = { [weak self, weak controller] outcome in
37
37
  guard let self else { return }
@@ -39,10 +39,13 @@ function normalizeOptions(input) {
39
39
  positive(output.frameRate, 'export.frameRate');
40
40
  if (input.source.type === 'photo' && output.videoFormat !== undefined) invalid('videoFormat is only valid for video sources.');
41
41
  if (input.source.type === 'video' && output.imageFormat !== undefined) invalid('imageFormat is only valid for photo sources.');
42
- if (input.initialStickerId !== undefined) {
43
- if (typeof input.initialStickerId !== 'string' || !input.initialStickerId.trim()) invalid('initialStickerId must be a non-empty string.');
44
- const matches = Array.isArray(input.stickerAssets) ? input.stickerAssets.filter(asset => asset?.id === input.initialStickerId) : [];
45
- if (matches.length !== 1 || typeof matches[0]?.uri !== 'string' || !matches[0].uri.trim()) invalid('initialStickerId must match exactly one stickerAssets entry with a non-empty uri.');
42
+ if (input.initialStickerIds !== undefined) {
43
+ if (!Array.isArray(input.initialStickerIds) || input.initialStickerIds.some(id => typeof id !== 'string' || !id.trim())) invalid('initialStickerIds must be an array of non-empty strings.');
44
+ if (new Set(input.initialStickerIds).size !== input.initialStickerIds.length) invalid('initialStickerIds must contain unique IDs.');
45
+ for (const id of input.initialStickerIds) {
46
+ const matches = Array.isArray(input.stickerAssets) ? input.stickerAssets.filter(asset => asset?.id === id) : [];
47
+ if (matches.length !== 1 || typeof matches[0]?.uri !== 'string' || !matches[0].uri.trim()) invalid('Each initialStickerIds entry must match exactly one stickerAssets entry with a non-empty uri.');
48
+ }
46
49
  }
47
50
  const features = {
48
51
  ...defaultFeatures,
@@ -1 +1 @@
1
- {"version":3,"names":["NativePhotoVideoEditor","PhotoVideoEditorError","normalizeEditorError","addEditorEventListener","addExportProgressListener","EDITOR_PROJECT_SCHEMA_VERSION","mediaTypes","Set","qualities","imageFormats","videoFormats","defaultFeatures","crop","rotate","trim","filters","text","stickers","draw","overlays","invalid","message","positive","value","name","undefined","Number","isFinite","normalizeOptions","input","source","uri","has","type","output","export","quality","imageFormat","videoFormat","maxWidth","maxHeight","videoBitrate","frameRate","initialStickerId","matches","Array","isArray","stickerAssets","filter","asset","id","length","features","preserveMetadata","saveToGallery","openEditor","options","JSON","parse","stringify","error","openPhotoEditor","openVideoEditor","cancelExport","jobId","isAvailable"],"sourceRoot":"../../src","sources":["index.ts"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"names":["NativePhotoVideoEditor","PhotoVideoEditorError","normalizeEditorError","addEditorEventListener","addExportProgressListener","EDITOR_PROJECT_SCHEMA_VERSION","mediaTypes","Set","qualities","imageFormats","videoFormats","defaultFeatures","crop","rotate","trim","filters","text","stickers","draw","overlays","invalid","message","positive","value","name","undefined","Number","isFinite","normalizeOptions","input","source","uri","has","type","output","export","quality","imageFormat","videoFormat","maxWidth","maxHeight","videoBitrate","frameRate","initialStickerIds","Array","isArray","some","id","size","length","matches","stickerAssets","filter","asset","features","preserveMetadata","saveToGallery","openEditor","options","JSON","parse","stringify","error","openPhotoEditor","openVideoEditor","cancelExport","jobId","isAvailable"],"sourceRoot":"../../src","sources":["index.ts"],"mappings":"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","ignoreList":[]}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,aAAa,EACb,YAAY,EAIZ,kBAAkB,EAElB,kBAAkB,EACnB,MAAM,YAAS,CAAC;AAEjB,OAAO,EAAE,sBAAsB,EAAE,yBAAyB,EAAE,MAAM,aAAU,CAAC;AAC7E,OAAO,EAAE,qBAAqB,EAAE,MAAM,aAAU,CAAC;AACjD,mBAAmB,YAAS,CAAC;AAC7B,OAAO,EAAE,6BAA6B,EAAE,MAAM,cAAW,CAAC;AAC1D,YAAY,EAAE,aAAa,EAAE,MAAM,cAAW,CAAC;AA0F/C,mEAAmE;AACnE,wBAAsB,UAAU,CAC9B,OAAO,EAAE,aAAa,GACrB,OAAO,CAAC,YAAY,CAAC,CAUvB;AACD,wBAAgB,eAAe,CAC7B,OAAO,EAAE,kBAAkB,GAC1B,OAAO,CAAC,YAAY,CAAC,CAEvB;AACD,wBAAgB,eAAe,CAC7B,OAAO,EAAE,kBAAkB,GAC1B,OAAO,CAAC,YAAY,CAAC,CAEvB;AACD,0FAA0F;AAC1F,wBAAsB,YAAY,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAMnE;AACD,4EAA4E;AAC5E,wBAAgB,WAAW,IAAI,OAAO,CAErC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,aAAa,EACb,YAAY,EAIZ,kBAAkB,EAElB,kBAAkB,EACnB,MAAM,YAAS,CAAC;AAEjB,OAAO,EAAE,sBAAsB,EAAE,yBAAyB,EAAE,MAAM,aAAU,CAAC;AAC7E,OAAO,EAAE,qBAAqB,EAAE,MAAM,aAAU,CAAC;AACjD,mBAAmB,YAAS,CAAC;AAC7B,OAAO,EAAE,6BAA6B,EAAE,MAAM,cAAW,CAAC;AAC1D,YAAY,EAAE,aAAa,EAAE,MAAM,cAAW,CAAC;AA8F/C,mEAAmE;AACnE,wBAAsB,UAAU,CAC9B,OAAO,EAAE,aAAa,GACrB,OAAO,CAAC,YAAY,CAAC,CAUvB;AACD,wBAAgB,eAAe,CAC7B,OAAO,EAAE,kBAAkB,GAC1B,OAAO,CAAC,YAAY,CAAC,CAEvB;AACD,wBAAgB,eAAe,CAC7B,OAAO,EAAE,kBAAkB,GAC1B,OAAO,CAAC,YAAY,CAAC,CAEvB;AACD,0FAA0F;AAC1F,wBAAsB,YAAY,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAMnE;AACD,4EAA4E;AAC5E,wBAAgB,WAAW,IAAI,OAAO,CAErC"}
@@ -62,7 +62,7 @@ export interface EditorOptions {
62
62
  /** Native UI theme. */ theme?: EditorTheme;
63
63
  /** Export preferences. */ export?: ExportOptions;
64
64
  /** Requests saving to the gallery. Currently ignored by the placeholder. */ saveToGallery?: boolean;
65
- /** ID in stickerAssets to insert at the media center when the editor opens. */ initialStickerId?: string;
65
+ /** Ordered, unique IDs in stickerAssets. The first starts centered; the sticker’s top-right control cycles through the rest. */ initialStickerIds?: string[];
66
66
  /** Consumer-provided stickers offered by the Stickers tool, in addition to the small built-in set and end-user uploads. */ stickerAssets?: StickerAsset[];
67
67
  /** Consumer-provided fonts selectable from the Text tool. */ fonts?: FontAsset[];
68
68
  }
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/types.ts"],"names":[],"mappings":"AAAA,kDAAkD;AAClD,MAAM,MAAM,SAAS,GAAG,OAAO,GAAG,OAAO,CAAC;AAC1C,uCAAuC;AACvC,MAAM,MAAM,aAAa,GAAG,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,UAAU,CAAC;AACnE,wCAAwC;AACxC,MAAM,MAAM,iBAAiB,GAAG,MAAM,GAAG,KAAK,GAAG,MAAM,CAAC;AACxD,wCAAwC;AACxC,MAAM,MAAM,iBAAiB,GAAG,KAAK,GAAG,KAAK,CAAC;AAC9C,sDAAsD;AACtD,MAAM,MAAM,YAAY,GACpB,MAAM,GACN,WAAW,GACX,SAAS,GACT,WAAW,GACX,WAAW,GACX,WAAW,GACX,QAAQ,CAAC;AAEb,2EAA2E;AAC3E,MAAM,WAAW,YAAY;IAC3B,8BAA8B,CAAC,GAAG,EAAE,MAAM,CAAC;IAC3C,kBAAkB,CAAC,IAAI,EAAE,SAAS,CAAC;IACnC,+BAA+B,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClD,iCAAiC,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;CACrD;AACD,2EAA2E;AAC3E,MAAM,WAAW,cAAc;IAC7B,wBAAwB,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC;IACxC,wBAAwB,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC;IAC1C,8BAA8B,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC;IAC9C,uBAAuB,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;IAC1C,6BAA6B,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC;IAC7C,yEAAyE,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAC7F,0EAA0E,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC;IAC1F,oDAAoD,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;CACzE;AACD,+CAA+C;AAC/C,MAAM,WAAW,WAAW;IAC1B,+BAA+B,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtD,+BAA+B,CAAC,eAAe,CAAC,EAAE,MAAM,CAAC;IACzD,qBAAqB,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC5C,6BAA6B,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IACjD,gCAAgC,CAAC,cAAc,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;CACpE;AACD,+EAA+E;AAC/E,MAAM,WAAW,aAAa;IAC5B,sBAAsB,CAAC,OAAO,CAAC,EAAE,aAAa,CAAC;IAC/C,+CAA+C,CAAC,WAAW,CAAC,EAAE,iBAAiB,CAAC;IAChF,+CAA+C,CAAC,WAAW,CAAC,EAAE,iBAAiB,CAAC;IAChF,wDAAwD,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3E,yDAAyD,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC7E,0DAA0D,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IACjF,+DAA+D,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnF,0DAA0D,CAAC,gBAAgB,CAAC,EAAE,OAAO,CAAC;CACvF;AACD,4FAA4F;AAC5F,MAAM,WAAW,SAAS;IACxB,mEAAmE,CAAC,MAAM,EAAE,MAAM,CAAC;IACnF,wDAAwD,CAAC,GAAG,EAAE,MAAM,CAAC;CACtE;AACD,4EAA4E;AAC5E,MAAM,WAAW,YAAY;IAC3B,wEAAwE,CAAC,EAAE,EAAE,MAAM,CAAC;IACpF,8GAA8G,CAAC,GAAG,EAAE,MAAM,CAAC;CAC5H;AACD,8CAA8C;AAC9C,MAAM,WAAW,aAAa;IAC5B,4BAA4B,CAAC,MAAM,EAAE,YAAY,CAAC;IAClD,qBAAqB,CAAC,QAAQ,CAAC,EAAE,cAAc,CAAC;IAChD,uBAAuB,CAAC,KAAK,CAAC,EAAE,WAAW,CAAC;IAC5C,0BAA0B,CAAC,MAAM,CAAC,EAAE,aAAa,CAAC;IAClD,4EAA4E,CAAC,aAAa,CAAC,EAAE,OAAO,CAAC;IACrG,gIAAgI,CAAC,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC9J,2HAA2H,CAAC,aAAa,CAAC,EAAE,YAAY,EAAE,CAAC;IAC3J,6DAA6D,CAAC,KAAK,CAAC,EAAE,SAAS,EAAE,CAAC;CACnF;AACD,MAAM,WAAW,kBAAmB,SAAQ,IAAI,CAAC,aAAa,EAAE,QAAQ,CAAC;IACvE,MAAM,EAAE,YAAY,GAAG;QAAE,IAAI,EAAE,OAAO,CAAA;KAAE,CAAC;CAC1C;AACD,MAAM,WAAW,kBAAmB,SAAQ,IAAI,CAAC,aAAa,EAAE,QAAQ,CAAC;IACvE,MAAM,EAAE,YAAY,GAAG;QAAE,IAAI,EAAE,OAAO,CAAA;KAAE,CAAC;CAC1C;AACD,MAAM,MAAM,eAAe,GACvB,cAAc,GACd,aAAa,GACb,kBAAkB,GAClB,gBAAgB,GAChB,eAAe,GACf,gBAAgB,GAChB,iBAAiB,GACjB,iBAAiB,GACjB,cAAc,GACd,OAAO,CAAC;AACZ,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,eAAe,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,YAAY,CAAC;CACvB;AACD,MAAM,MAAM,mBAAmB,GAAG,CAAC,KAAK,EAAE,WAAW,KAAK,IAAI,CAAC;AAC/D,8CAA8C;AAC9C,MAAM,WAAW,YAAY;IAC3B,wBAAwB,CAAC,GAAG,EAAE,MAAM,CAAC;IACrC,yBAAyB,CAAC,IAAI,EAAE,SAAS,CAAC;IAC1C,4BAA4B,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC/C,kCAAkC,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAClD,mCAAmC,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACpD,iDAAiD,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IACpE,qCAAqC,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IACxD,4CAA4C,CAAC,SAAS,EAAE,OAAO,CAAC;CACjE;AACD,oDAAoD;AACpD,MAAM,WAAW,mBAAmB;IAClC,6BAA6B,CAAC,KAAK,EAAE,MAAM,CAAC;IAC5C,sCAAsC,CAAC,QAAQ,EAAE,MAAM,CAAC;IACxD,+BAA+B,CAAC,MAAM,EAAE,YAAY,CAAC;CACtD;AACD,oCAAoC;AACpC,MAAM,WAAW,kBAAkB;IACjC,uDAAuD,CAAC,MAAM,IAAI,IAAI,CAAC;CACxE"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-photo-video-editor",
3
- "version": "0.2.2",
3
+ "version": "0.3.0",
4
4
  "description": "Native photo and video editor for React Native, powered by Kotlin and Swift.",
5
5
  "main": "./lib/module/index.js",
6
6
  "module": "./lib/module/index.js",
package/src/index.ts CHANGED
@@ -72,25 +72,29 @@ function normalizeOptions(input: EditorOptions): EditorOptions {
72
72
  invalid('videoFormat is only valid for video sources.');
73
73
  if (input.source.type === 'video' && output.imageFormat !== undefined)
74
74
  invalid('imageFormat is only valid for photo sources.');
75
- if (input.initialStickerId !== undefined) {
75
+ if (input.initialStickerIds !== undefined) {
76
76
  if (
77
- typeof input.initialStickerId !== 'string' ||
78
- !input.initialStickerId.trim()
77
+ !Array.isArray(input.initialStickerIds) ||
78
+ input.initialStickerIds.some((id) => typeof id !== 'string' || !id.trim())
79
79
  )
80
- invalid('initialStickerId must be a non-empty string.');
81
- const matches = Array.isArray(input.stickerAssets)
82
- ? input.stickerAssets.filter(
83
- (asset) => asset?.id === input.initialStickerId
84
- )
85
- : [];
80
+ invalid('initialStickerIds must be an array of non-empty strings.');
86
81
  if (
87
- matches.length !== 1 ||
88
- typeof matches[0]?.uri !== 'string' ||
89
- !matches[0].uri.trim()
82
+ new Set(input.initialStickerIds).size !== input.initialStickerIds.length
90
83
  )
91
- invalid(
92
- 'initialStickerId must match exactly one stickerAssets entry with a non-empty uri.'
93
- );
84
+ invalid('initialStickerIds must contain unique IDs.');
85
+ for (const id of input.initialStickerIds) {
86
+ const matches = Array.isArray(input.stickerAssets)
87
+ ? input.stickerAssets.filter((asset) => asset?.id === id)
88
+ : [];
89
+ if (
90
+ matches.length !== 1 ||
91
+ typeof matches[0]?.uri !== 'string' ||
92
+ !matches[0].uri.trim()
93
+ )
94
+ invalid(
95
+ 'Each initialStickerIds entry must match exactly one stickerAssets entry with a non-empty uri.'
96
+ );
97
+ }
94
98
  }
95
99
  const features = { ...defaultFeatures, ...input.features };
96
100
  if (input.source.type === 'photo') {
package/src/types.ts CHANGED
@@ -70,7 +70,7 @@ export interface EditorOptions {
70
70
  /** Native UI theme. */ theme?: EditorTheme;
71
71
  /** Export preferences. */ export?: ExportOptions;
72
72
  /** Requests saving to the gallery. Currently ignored by the placeholder. */ saveToGallery?: boolean;
73
- /** ID in stickerAssets to insert at the media center when the editor opens. */ initialStickerId?: string;
73
+ /** Ordered, unique IDs in stickerAssets. The first starts centered; the sticker’s top-right control cycles through the rest. */ initialStickerIds?: string[];
74
74
  /** Consumer-provided stickers offered by the Stickers tool, in addition to the small built-in set and end-user uploads. */ stickerAssets?: StickerAsset[];
75
75
  /** Consumer-provided fonts selectable from the Text tool. */ fonts?: FontAsset[];
76
76
  }