@technotoil/image-video-editor 0.1.4 → 0.1.6

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.
@@ -449,11 +449,11 @@ class MediaEditorModule(private val reactContext: ReactApplicationContext) :
449
449
  if (File(fontPath).exists()) {
450
450
  val textFilters = mutableListOf<String>()
451
451
  for (i in 0 until overlays.size()) {
452
- val o = overlays.getMap(i)
452
+ val o = overlays.getMap(i) ?: continue
453
453
  val text = o.getString("text") ?: continue
454
454
  val x = if (o.hasKey("x")) o.getDouble("x") else 0.0
455
455
  val y = if (o.hasKey("y")) o.getDouble("y") else 0.0
456
- val colorHex = if (o.hasKey("color")) o.getString("color") else "#FFFFFF"
456
+ val colorHex = if (o.hasKey("color")) o.getString("color") ?: "#FFFFFF" else "#FFFFFF"
457
457
  val fontSize = if (o.hasKey("fontSize")) o.getDouble("fontSize") else 24.0
458
458
 
459
459
  val safeText = text.replace(":", "\\:").replace("'", "\\'")
@@ -1027,13 +1027,14 @@ function EditorScreen({
1027
1027
  const containerHeight = showMusicModal ? SCREEN_WIDTH * 0.72 : SCREEN_WIDTH * 1.25;
1028
1028
  const maxPan = (0, _react.useMemo)(() => {
1029
1029
  // If no cropRatio, we still want to allow panning/zooming if zoomScale > 1
1030
- const actualRatio = typeof cropRatio === 'number' ? cropRatio : dimensions.width / (dimensions.height || 1);
1031
- let imgW = dimensions.width;
1032
- let imgH = dimensions.height;
1030
+ let imgW = dimensions.width || item.width || 1080;
1031
+ let imgH = dimensions.height || item.height || 1920;
1033
1032
  if ((imageOptions.rotateDegrees || 0) % 180 !== 0) {
1034
- imgW = dimensions.height;
1035
- imgH = dimensions.width;
1033
+ const temp = imgW;
1034
+ imgW = imgH;
1035
+ imgH = temp;
1036
1036
  }
1037
+ const actualRatio = typeof cropRatio === 'number' ? cropRatio : imgW / (imgH || 1);
1037
1038
  const baseH = actualRatio <= 1 ? containerHeight - 24 : (SCREEN_WIDTH - 24) / actualRatio;
1038
1039
  const baseW = actualRatio > 1 ? SCREEN_WIDTH - 24 : baseH * actualRatio;
1039
1040
  const boxW = baseW * (cropRatio === 'custom' ? cropResizeScaleX : cropResizeScale);
@@ -1047,7 +1048,7 @@ function EditorScreen({
1047
1048
  boxW,
1048
1049
  boxH
1049
1050
  };
1050
- }, [cropRatio, dimensions, imageOptions.rotateDegrees, zoomScale, cropResizeScale, cropResizeScaleX, cropResizeScaleY, showMusicModal, containerHeight]);
1051
+ }, [cropRatio, dimensions, item, imageOptions.rotateDegrees, zoomScale, cropResizeScale, cropResizeScaleX, cropResizeScaleY, showMusicModal, containerHeight]);
1051
1052
  const maxPanRef = (0, _react.useRef)(maxPan);
1052
1053
  (0, _react.useEffect)(() => {
1053
1054
  maxPanRef.current = maxPan;
@@ -1093,11 +1094,12 @@ function EditorScreen({
1093
1094
  }
1094
1095
  })).current;
1095
1096
  const activeOptions = (0, _react.useMemo)(() => {
1096
- let imgW = dimensions.width;
1097
- let imgH = dimensions.height;
1097
+ let imgW = dimensions.width || item.width || 1080;
1098
+ let imgH = dimensions.height || item.height || 1920;
1098
1099
  if ((imageOptions.rotateDegrees || 0) % 180 !== 0) {
1099
- imgW = dimensions.height;
1100
- imgH = dimensions.width;
1100
+ const temp = imgW;
1101
+ imgW = imgH;
1102
+ imgH = temp;
1101
1103
  }
1102
1104
  const actualRatio = typeof cropRatio === 'number' ? cropRatio : imgW / (imgH || 1);
1103
1105
  const scale = maxPan.scale;
@@ -1129,7 +1131,7 @@ function EditorScreen({
1129
1131
  ...(hasCrop ? {
1130
1132
  crop: finalCrop
1131
1133
  } : {}),
1132
- imageAspectRatio: dimensions.width / (dimensions.height || 1),
1134
+ imageAspectRatio: imgW / (imgH || 1),
1133
1135
  frameScale: imageOptions.frame ? frameConfig.scale : 1,
1134
1136
  frameOffsetY: imageOptions.frame ? frameConfig.offsetY || 0 : 0,
1135
1137
  overlays: overlays.map(o => ({
@@ -1142,7 +1144,7 @@ function EditorScreen({
1142
1144
  })),
1143
1145
  frameUri: imageOptions.frame && FRAME_IMAGES[imageOptions.frame] ? _reactNative.Image.resolveAssetSource(FRAME_IMAGES[imageOptions.frame]).uri : undefined
1144
1146
  };
1145
- }, [imageOptions, cropOffset, maxPan, dimensions, cropRatio, straightenAngle, overlays]);
1147
+ }, [imageOptions, cropOffset, maxPan, dimensions, item, cropRatio, straightenAngle, overlays]);
1146
1148
 
1147
1149
  // For visual trim
1148
1150
 
@@ -2242,10 +2244,9 @@ function EditorScreen({
2242
2244
  cumulativeMusicOffsetMs += newDuration;
2243
2245
  }
2244
2246
  } else {
2245
- if (selectedMusic) {
2246
- let outUri = targetItem.uri;
2247
- if (targetItem.type === 'image') {
2248
- outUri = await (0, _MediaEditor.trimVideo)(targetItem.uri, {
2247
+ if (targetItem.type === 'image') {
2248
+ if (selectedMusic) {
2249
+ const outUri = await (0, _MediaEditor.trimVideo)(targetItem.uri, {
2249
2250
  isImage: true,
2250
2251
  musicUri: selectedMusic.url,
2251
2252
  musicOffsetMs: cumulativeMusicOffsetMs,
@@ -2258,9 +2259,17 @@ function EditorScreen({
2258
2259
  grayscale: false
2259
2260
  });
2260
2261
  cumulativeMusicOffsetMs += 10000;
2261
- } else {
2262
- const safeEndMs = targetItem.durationMs || 10000;
2263
- outUri = await (0, _MediaEditor.trimVideo)(targetItem.uri, {
2262
+ updatedItems[i] = {
2263
+ ...targetItem,
2264
+ uri: outUri,
2265
+ thumbnailUri: outUri
2266
+ };
2267
+ }
2268
+ } else {
2269
+ const needsTrim = selectedMusic || maxVideoDurationMs && (!targetItem.durationMs || targetItem.durationMs > maxVideoDurationMs);
2270
+ if (needsTrim) {
2271
+ const safeEndMs = maxVideoDurationMs ? Math.min(targetItem.durationMs || 10000, maxVideoDurationMs) : targetItem.durationMs || 10000;
2272
+ const outUri = await (0, _MediaEditor.trimVideo)(targetItem.uri, {
2264
2273
  startMs: 0,
2265
2274
  endMs: safeEndMs,
2266
2275
  mute: isMuted,
@@ -2276,13 +2285,24 @@ function EditorScreen({
2276
2285
  saturation: 1,
2277
2286
  grayscale: false
2278
2287
  });
2288
+ let newThumb = undefined;
2289
+ try {
2290
+ newThumb = await (0, _FrameGrabber.captureFrame)(outUri, {
2291
+ timeMs: 0
2292
+ });
2293
+ } catch (e) {
2294
+ console.warn('Could not generate filtered thumb', e);
2295
+ }
2296
+ updatedItems[i] = {
2297
+ ...targetItem,
2298
+ uri: outUri,
2299
+ thumbnailUri: newThumb ? newThumb : targetItem.thumbnailUri,
2300
+ durationMs: safeEndMs
2301
+ };
2279
2302
  cumulativeMusicOffsetMs += safeEndMs;
2303
+ } else {
2304
+ cumulativeMusicOffsetMs += targetItem.durationMs || 10000;
2280
2305
  }
2281
- updatedItems[i] = {
2282
- ...targetItem,
2283
- uri: outUri,
2284
- thumbnailUri: targetItem.type === 'image' ? outUri : targetItem.thumbnailUri
2285
- };
2286
2306
  }
2287
2307
  }
2288
2308
  }
@@ -2818,32 +2838,40 @@ function EditorScreen({
2818
2838
  },
2819
2839
  style: styles.filmstripImage
2820
2840
  }, idx)), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
2841
+ ref: leftOverlayRef,
2821
2842
  style: [styles.timelineOverlay, {
2822
2843
  left: 0,
2823
- width: trimStart / duration * TIMELINE_WIDTH
2844
+ width: startX.current
2824
2845
  }]
2825
2846
  }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
2847
+ ref: rightOverlayRef,
2826
2848
  style: [styles.timelineOverlay, {
2827
- left: trimEnd / duration * TIMELINE_WIDTH,
2849
+ left: endX.current,
2828
2850
  right: 0
2829
2851
  }]
2830
2852
  }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
2853
+ ref: selectionRangeRef,
2831
2854
  style: [styles.selectionRange, {
2832
- left: trimStart / duration * TIMELINE_WIDTH,
2833
- width: (trimEnd - trimStart) / duration * TIMELINE_WIDTH
2834
- }]
2855
+ left: startX.current,
2856
+ width: endX.current - startX.current
2857
+ }],
2858
+ ...middlePan.panHandlers
2835
2859
  })]
2836
2860
  }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
2861
+ ref: leftHandleRef,
2837
2862
  style: [styles.customHandle, styles.customHandleLeft, {
2838
- left: trimStart / duration * TIMELINE_WIDTH - 16
2863
+ left: startX.current - 16
2839
2864
  }],
2865
+ ...startPan.panHandlers,
2840
2866
  children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
2841
2867
  style: styles.handleBarLine
2842
2868
  })
2843
2869
  }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
2870
+ ref: rightHandleRef,
2844
2871
  style: [styles.customHandle, styles.customHandleRight, {
2845
- left: trimEnd / duration * TIMELINE_WIDTH - 16
2872
+ left: endX.current - 16
2846
2873
  }],
2874
+ ...endPan.panHandlers,
2847
2875
  children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
2848
2876
  style: styles.handleBarLine
2849
2877
  })
@@ -3462,8 +3490,8 @@ function EditorScreen({
3462
3490
  keyExtractor: it => it.id,
3463
3491
  initialScrollIndex: activeIndex,
3464
3492
  getItemLayout: (_, index) => ({
3465
- length: SCREEN_WIDTH,
3466
- offset: SCREEN_WIDTH * index,
3493
+ length: SNAP_INTERVAL,
3494
+ offset: SNAP_INTERVAL * index,
3467
3495
  index
3468
3496
  }),
3469
3497
  horizontal: true,