react-native-video-trim 6.0.13 → 6.2.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.
@@ -21,6 +21,7 @@ import android.util.AttributeSet;
21
21
  import android.util.Log;
22
22
  import android.util.TypedValue;
23
23
  import android.view.LayoutInflater;
24
+ import android.view.GestureDetector;
24
25
  import android.view.MotionEvent;
25
26
  import android.view.View;
26
27
  import android.widget.FrameLayout;
@@ -104,6 +105,13 @@ public class VideoTrimmerView extends FrameLayout implements IVideoTrimmerView {
104
105
  private long zoomedInRangeDuration = 0;
105
106
  private boolean isTrimmingLeading = false;
106
107
 
108
+ // range drag
109
+ private boolean isRangeDragging = false;
110
+ private float rangeDragInitialRawX = 0;
111
+ private long rangeDragInitialStartTime = 0;
112
+ private long rangeDragInitialEndTime = 0;
113
+ private GestureDetector rangeDragGestureDetector;
114
+
107
115
  // thumbnail caching for zoom functionality
108
116
  private final java.util.List<ImageView> cachedFullViewThumbnails = new java.util.ArrayList<>();
109
117
  private volatile boolean isGeneratingThumbnails = false;
@@ -155,9 +163,24 @@ public class VideoTrimmerView extends FrameLayout implements IVideoTrimmerView {
155
163
  initializeViews();
156
164
  configure(config);
157
165
  setUpListeners();
166
+ initRangeDragDetector();
158
167
  setProgressIndicatorTouchListener();
159
168
  }
160
169
 
170
+ private void initRangeDragDetector() {
171
+ rangeDragGestureDetector = new GestureDetector(mContext, new GestureDetector.SimpleOnGestureListener() {
172
+ @Override
173
+ public void onLongPress(MotionEvent e) {
174
+ isRangeDragging = true;
175
+ rangeDragInitialRawX = e.getRawX();
176
+ rangeDragInitialStartTime = startTime;
177
+ rangeDragInitialEndTime = endTime;
178
+ playHapticFeedback(true);
179
+ fadeOutProgressIndicator();
180
+ }
181
+ });
182
+ }
183
+
161
184
  private void initializeViews() {
162
185
  mThumbnailContainer = findViewById(R.id.thumbnailContainer);
163
186
  mVideoView = findViewById(R.id.video_loader);
@@ -486,11 +509,11 @@ public class VideoTrimmerView extends FrameLayout implements IVideoTrimmerView {
486
509
 
487
510
  private void configure(ReadableMap config) {
488
511
  if (config.hasKey("maxDuration") && config.getDouble("maxDuration") > 0) {
489
- mMaxDuration = (long) Math.max(0, config.getDouble("maxDuration") * 1000L);
512
+ mMaxDuration = (long) Math.max(0, config.getDouble("maxDuration"));
490
513
  }
491
514
 
492
515
  if (config.hasKey("minDuration") && config.getDouble("minDuration") > 0) {
493
- mMinDuration = (long) Math.max(1000L, config.getDouble("minDuration") * 1000L);
516
+ mMinDuration = (long) Math.max(1000L, config.getDouble("minDuration"));
494
517
  }
495
518
 
496
519
  cancelBtn.setText(config.getString("cancelButtonText"));
@@ -664,17 +687,29 @@ public class VideoTrimmerView extends FrameLayout implements IVideoTrimmerView {
664
687
 
665
688
  private void setProgressIndicatorTouchListener() {
666
689
  trimmerContainerBg.setOnTouchListener((view, event) -> {
690
+ rangeDragGestureDetector.onTouchEvent(event);
691
+
667
692
  switch (event.getAction()) {
668
693
  case MotionEvent.ACTION_DOWN:
694
+ isRangeDragging = false;
669
695
  didClampWhilePanning = false;
670
696
  onMediaPause();
671
697
  onTrimmerContainerPanned(event);
672
698
  playHapticFeedback(true);
673
699
  break;
674
700
  case MotionEvent.ACTION_MOVE:
675
- onTrimmerContainerPanned(event);
701
+ if (isRangeDragging) {
702
+ onRangeDrag(event);
703
+ } else {
704
+ onTrimmerContainerPanned(event);
705
+ }
676
706
  break;
677
707
  case MotionEvent.ACTION_UP:
708
+ if (isRangeDragging) {
709
+ isRangeDragging = false;
710
+ fadeInProgressIndicator();
711
+ updateCurrentTime(true);
712
+ }
678
713
  view.performClick();
679
714
  break;
680
715
  default:
@@ -730,6 +765,45 @@ public class VideoTrimmerView extends FrameLayout implements IVideoTrimmerView {
730
765
  seekTo(newVideoPosition, false);
731
766
  }
732
767
 
768
+ private void onRangeDrag(MotionEvent event) {
769
+ float deltaX = event.getRawX() - rangeDragInitialRawX;
770
+ float containerWidth = trimmerContainerBg.getWidth();
771
+ if (containerWidth <= 0) return;
772
+
773
+ long rangeDuration = rangeDragInitialEndTime - rangeDragInitialStartTime;
774
+ long deltaTime;
775
+ if (isZoomedIn) {
776
+ deltaTime = (long) (deltaX / containerWidth * zoomedInRangeDuration);
777
+ } else {
778
+ deltaTime = (long) (deltaX / containerWidth * mDuration);
779
+ }
780
+
781
+ long newStart = rangeDragInitialStartTime + deltaTime;
782
+ long newEnd = newStart + rangeDuration;
783
+
784
+ boolean didClamp = false;
785
+ if (newStart < 0) {
786
+ newStart = 0;
787
+ newEnd = rangeDuration;
788
+ didClamp = true;
789
+ }
790
+ if (newEnd > mDuration) {
791
+ newEnd = mDuration;
792
+ newStart = newEnd - rangeDuration;
793
+ didClamp = true;
794
+ }
795
+
796
+ if (didClamp && !didClampWhilePanning) {
797
+ playHapticFeedback(false);
798
+ }
799
+ didClampWhilePanning = didClamp;
800
+
801
+ startTime = newStart;
802
+ endTime = newEnd;
803
+ updateHandlePositions();
804
+ seekTo(startTime, false);
805
+ }
806
+
733
807
  private void setHandleTouchListener(View handle, boolean isLeading) {
734
808
  handle.setOnTouchListener((view, event) -> {
735
809
  boolean draggingDisabled = mDuration < mMinDuration; // if the video is shorter than the minimum duration, disable dragging
@@ -26,6 +26,11 @@ import AVFoundation
26
26
  static let progressChanged = UIControl.Event(rawValue: 0b00010000 << 24)
27
27
  static let didEndScrubbing = UIControl.Event(rawValue: 0b00100000 << 24)
28
28
 
29
+ // events for dragging the entire selected range
30
+ static let didBeginDraggingRange = UIControl.Event(rawValue: 0b01000000 << 24)
31
+ static let rangeDragChanged = UIControl.Event(rawValue: 0b10000000 << 24)
32
+ static let didEndDraggingRange = UIControl.Event(rawValue: 1 << 25)
33
+
29
34
  private struct Thumbnail {
30
35
  let uuid = UUID()
31
36
  let imageView: UIImageView
@@ -249,6 +254,12 @@ import AVFoundation
249
254
  private (set) var trailingGestureRecognizer: UILongPressGestureRecognizer!
250
255
  private (set) var progressGestureRecognizer: UILongPressGestureRecognizer!
251
256
  private (set) var thumbnailInteractionGestureRecognizer: UILongPressGestureRecognizer!
257
+ private (set) var rangeDragGestureRecognizer: UILongPressGestureRecognizer!
258
+
259
+ // range drag state
260
+ private(set) var isDraggingRange = false
261
+ private var rangeDragInitialRange: CMTimeRange = .zero
262
+ private var rangeDragInitialLocationX: CGFloat = 0
252
263
 
253
264
  // private stuff
254
265
  private var grabberOffset = CGFloat(0)
@@ -369,11 +380,18 @@ import AVFoundation
369
380
  progressGestureRecognizer.require(toFail: trailingGestureRecognizer)
370
381
  progressIndicatorControl.addGestureRecognizer(progressGestureRecognizer)
371
382
 
383
+ // Range drag: platform-default long press (0.5s hold, 10pt allowable movement)
384
+ rangeDragGestureRecognizer = UILongPressGestureRecognizer(target: self, action: #selector(rangeDragPanned(_:)))
385
+ rangeDragGestureRecognizer.require(toFail: leadingGestureRecognizer)
386
+ rangeDragGestureRecognizer.require(toFail: trailingGestureRecognizer)
387
+ thumbView.addGestureRecognizer(rangeDragGestureRecognizer)
388
+
372
389
  thumbnailInteractionGestureRecognizer = UILongPressGestureRecognizer(target: self, action: #selector(thumbnailPanned(_:)))
373
390
  thumbnailInteractionGestureRecognizer.allowableMovement = CGFloat.greatestFiniteMagnitude
374
391
  thumbnailInteractionGestureRecognizer.minimumPressDuration = 0
375
392
  thumbnailInteractionGestureRecognizer.require(toFail: leadingGestureRecognizer)
376
393
  thumbnailInteractionGestureRecognizer.require(toFail: trailingGestureRecognizer)
394
+ thumbnailInteractionGestureRecognizer.require(toFail: rangeDragGestureRecognizer)
377
395
  thumbView.addGestureRecognizer(thumbnailInteractionGestureRecognizer)
378
396
  }
379
397
 
@@ -583,9 +601,10 @@ import AVFoundation
583
601
  setNeedsLayout()
584
602
 
585
603
  case .hiddenOnlyWhenTrimming:
586
- progressIndicator.alpha = (trimmingState == .none ? 1 : 0)
587
- progressIndicatorControl.isUserInteractionEnabled = (trimmingState == .none)
588
- if trimmingState == .none {
604
+ let shouldShow = trimmingState == .none && !isDraggingRange
605
+ progressIndicator.alpha = (shouldShow ? 1 : 0)
606
+ progressIndicatorControl.isUserInteractionEnabled = shouldShow
607
+ if shouldShow {
589
608
  setNeedsLayout()
590
609
  if UIView.inheritedAnimationDuration > 0 {
591
610
  UIView.performWithoutAnimation {
@@ -780,6 +799,86 @@ import AVFoundation
780
799
  }
781
800
  }
782
801
 
802
+
803
+ @objc private func rangeDragPanned(_ sender: UILongPressGestureRecognizer) {
804
+ switch sender.state {
805
+ case .began:
806
+ isDraggingRange = true
807
+ rangeDragInitialRange = selectedRange
808
+ rangeDragInitialLocationX = sender.location(in: self).x
809
+ didClampWhilePanning = false
810
+
811
+ if enableHapticFeedback {
812
+ UISelectionFeedbackGenerator().selectionChanged()
813
+ impactFeedbackGenerator = UIImpactFeedbackGenerator(style: .heavy)
814
+ impactFeedbackGenerator?.prepare()
815
+ }
816
+
817
+ UIView.animate(withDuration: 0.25, delay: 0, options: [.beginFromCurrentState, .allowUserInteraction], animations: {
818
+ self.updateProgressIndicator()
819
+ })
820
+ sendActions(for: Self.didBeginDraggingRange)
821
+
822
+ case .changed:
823
+ let currentX = sender.location(in: self).x
824
+ let deltaX = currentX - rangeDragInitialLocationX
825
+ let inset = thumbView.chevronWidth + horizontalInset
826
+ let availableWidth = bounds.width - inset * 2
827
+ let visibleDurationInSeconds = CGFloat(visibleRange.duration.seconds)
828
+ guard availableWidth > 0 && visibleDurationInSeconds > 0 else { return }
829
+
830
+ let deltaTime = CMTime(
831
+ seconds: Double(deltaX / availableWidth) * Double(visibleDurationInSeconds),
832
+ preferredTimescale: 600
833
+ )
834
+ let duration = rangeDragInitialRange.duration
835
+ var newStart = CMTimeAdd(rangeDragInitialRange.start, deltaTime)
836
+ var newEnd = CMTimeAdd(newStart, duration)
837
+
838
+ var didClamp = false
839
+ if CMTimeCompare(newStart, range.start) == -1 {
840
+ newStart = range.start
841
+ newEnd = CMTimeAdd(newStart, duration)
842
+ didClamp = true
843
+ }
844
+ if CMTimeCompare(newEnd, range.end) == 1 {
845
+ newEnd = range.end
846
+ newStart = CMTimeSubtract(newEnd, duration)
847
+ didClamp = true
848
+ }
849
+
850
+ if didClamp && !didClampWhilePanning {
851
+ impactFeedbackGenerator?.impactOccurred()
852
+ }
853
+ didClampWhilePanning = didClamp
854
+
855
+ selectedRange = CMTimeRange(start: newStart, end: newEnd)
856
+ setNeedsLayout()
857
+ sendActions(for: Self.rangeDragChanged)
858
+
859
+ case .ended:
860
+ isDraggingRange = false
861
+ impactFeedbackGenerator = nil
862
+ UIView.animate(withDuration: 0.25, delay: 0, options: [.beginFromCurrentState, .allowUserInteraction], animations: {
863
+ self.updateProgressIndicator()
864
+ })
865
+ sendActions(for: Self.didEndDraggingRange)
866
+
867
+ case .cancelled:
868
+ isDraggingRange = false
869
+ impactFeedbackGenerator = nil
870
+ UIView.animate(withDuration: 0.25, delay: 0, options: [.beginFromCurrentState, .allowUserInteraction], animations: {
871
+ self.updateProgressIndicator()
872
+ })
873
+
874
+ case .possible, .failed:
875
+ break
876
+
877
+ @unknown default:
878
+ break
879
+ }
880
+ }
881
+
783
882
  // MARK: - UIView
784
883
 
785
884
  override var intrinsicContentSize: CGSize {
@@ -131,6 +131,20 @@ class VideoTrimmerViewController: UIViewController {
131
131
  handleTrimmingEnd(false)
132
132
  }
133
133
 
134
+ @objc private func didBeginDraggingRange(_ sender: VideoTrimmer) {
135
+ handleBeforeProgressChange()
136
+ }
137
+
138
+ @objc private func rangeDragChanged(_ sender: VideoTrimmer) {
139
+ handleProgressChanged(time: trimmer.selectedRange.start)
140
+ }
141
+
142
+ @objc private func didEndDraggingRange(_ sender: VideoTrimmer) {
143
+ self.trimmer.progress = trimmer.selectedRange.start
144
+ updateLabels()
145
+ seek(to: trimmer.progress)
146
+ }
147
+
134
148
  @objc private func didBeginScrubbing(_ sender: VideoTrimmer) {
135
149
  handleBeforeProgressChange()
136
150
  }
@@ -332,7 +346,7 @@ class VideoTrimmerViewController: UIViewController {
332
346
  trimmer.zoomOnWaitingDuration = zoomOnWaitingDuration
333
347
 
334
348
  if let maxDuration = maximumDuration {
335
- trimmer.maximumDuration = CMTime(seconds: max(1, Double(maxDuration)), preferredTimescale: 600)
349
+ trimmer.maximumDuration = CMTime(seconds: max(1, Double(maxDuration) / 1000.0), preferredTimescale: 600)
336
350
  if trimmer.maximumDuration > asset!.duration {
337
351
  trimmer.maximumDuration = asset!.duration
338
352
  }
@@ -340,7 +354,7 @@ class VideoTrimmerViewController: UIViewController {
340
354
  }
341
355
 
342
356
  if let minDuration = minimumDuration {
343
- trimmer.minimumDuration = CMTime(seconds: max(1, Double(minDuration)), preferredTimescale: 600)
357
+ trimmer.minimumDuration = CMTime(seconds: max(1, Double(minDuration) / 1000.0), preferredTimescale: 600)
344
358
  }
345
359
 
346
360
  trimmer.addTarget(self, action: #selector(didBeginScrubbing(_:)), for: VideoTrimmer.didBeginScrubbing)
@@ -354,6 +368,10 @@ class VideoTrimmerViewController: UIViewController {
354
368
  trimmer.addTarget(self, action: #selector(didBeginTrimmingFromEnd(_:)), for: VideoTrimmer.didBeginTrimmingFromEnd)
355
369
  trimmer.addTarget(self, action: #selector(trailingGrabberChanged(_:)), for: VideoTrimmer.trailingGrabberChanged)
356
370
  trimmer.addTarget(self, action: #selector(didEndTrimmingFromEnd(_:)), for: VideoTrimmer.didEndTrimmingFromEnd)
371
+
372
+ trimmer.addTarget(self, action: #selector(didBeginDraggingRange(_:)), for: VideoTrimmer.didBeginDraggingRange)
373
+ trimmer.addTarget(self, action: #selector(rangeDragChanged(_:)), for: VideoTrimmer.rangeDragChanged)
374
+ trimmer.addTarget(self, action: #selector(didEndDraggingRange(_:)), for: VideoTrimmer.didEndDraggingRange)
357
375
  trimmer.alpha = 0
358
376
  view.addSubview(trimmer)
359
377
  trimmer.translatesAutoresizingMaskIntoConstraints = false
@@ -1,5 +1,30 @@
1
1
  "use strict";
2
2
 
3
3
  import { TurboModuleRegistry } from 'react-native';
4
+
5
+ /**
6
+ * Base options shared by both the editor and headless trim operations.
7
+ */
8
+
9
+ /**
10
+ * Configuration for the video trimmer editor UI.
11
+ */
12
+
13
+ /**
14
+ * Options for headless (non-UI) trim operations.
15
+ */
16
+
17
+ /**
18
+ * Result returned by {@link Spec.isValidFile}.
19
+ */
20
+
21
+ /**
22
+ * Result returned by a trim operation (both editor and headless).
23
+ */
24
+
25
+ /**
26
+ * TurboModule spec for the native VideoTrim module.
27
+ */
28
+
4
29
  export default TurboModuleRegistry.getEnforcing('VideoTrim');
5
30
  //# sourceMappingURL=NativeVideoTrim.js.map
@@ -1 +1 @@
1
- {"version":3,"names":["TurboModuleRegistry","getEnforcing"],"sourceRoot":"../../src","sources":["NativeVideoTrim.ts"],"mappings":";;AACA,SAASA,mBAAmB,QAAQ,cAAc;AA0IlD,eAAeA,mBAAmB,CAACC,YAAY,CAAO,WAAW,CAAC","ignoreList":[]}
1
+ {"version":3,"names":["TurboModuleRegistry","getEnforcing"],"sourceRoot":"../../src","sources":["NativeVideoTrim.ts"],"mappings":";;AACA,SAASA,mBAAmB,QAAQ,cAAc;;AAGlD;AACA;AACA;;AAkBA;AACA;AACA;;AAgGA;AACA;AACA;;AAQA;AACA;AACA;;AAUA;AACA;AACA;;AAcA;AACA;AACA;;AAmEA,eAAeA,mBAAmB,CAACC,YAAY,CAAO,WAAW,CAAC","ignoreList":[]}
@@ -1,115 +1,202 @@
1
1
  import type { TurboModule } from 'react-native';
2
2
  import type { EventEmitter } from 'react-native/Libraries/Types/CodegenTypes';
3
+ /**
4
+ * Base options shared by both the editor and headless trim operations.
5
+ */
3
6
  export interface BaseOptions {
7
+ /** Whether to save the output file to the device's photo library. */
4
8
  saveToPhoto: boolean;
9
+ /** Media type: `"video"` or `"audio"`. */
5
10
  type: string;
11
+ /** Output file extension (e.g. `"mp4"`, `"wav"`). */
6
12
  outputExt: string;
13
+ /** Whether to remove the output file after it has been saved to the photo library. */
7
14
  removeAfterSavedToPhoto: boolean;
15
+ /** Whether to remove the output file if saving to the photo library fails. */
8
16
  removeAfterFailedToSavePhoto: boolean;
17
+ /** Whether to enable video rotation during trimming. */
9
18
  enableRotation: boolean;
19
+ /** Rotation angle in degrees (e.g. `90`, `180`, `270`). Only used when `enableRotation` is `true`. */
10
20
  rotationAngle: number;
11
21
  }
22
+ /**
23
+ * Configuration for the video trimmer editor UI.
24
+ */
12
25
  export interface EditorConfig extends BaseOptions {
26
+ /** Whether to enable haptic feedback when interacting with the trimmer. */
13
27
  enableHapticFeedback: boolean;
28
+ /** Maximum allowed duration for the trimmed clip in milliseconds. Set to `-1` for no limit. */
14
29
  maxDuration: number;
30
+ /** Minimum allowed duration for the trimmed clip in milliseconds. Set to `-1` for no limit. */
15
31
  minDuration: number;
32
+ /** Whether to open the system documents/files app after trimming finishes. */
16
33
  openDocumentsOnFinish: boolean;
34
+ /** Whether to open the share sheet after trimming finishes. */
17
35
  openShareSheetOnFinish: boolean;
36
+ /** Whether to remove the output file after it has been saved to documents. */
18
37
  removeAfterSavedToDocuments: boolean;
38
+ /** Whether to remove the output file if saving to documents fails. */
19
39
  removeAfterFailedToSaveDocuments: boolean;
40
+ /** Whether to remove the output file after it has been shared. */
20
41
  removeAfterShared: boolean;
42
+ /** Whether to remove the output file if sharing fails. */
21
43
  removeAfterFailedToShare: boolean;
44
+ /** Text for the cancel button. */
22
45
  cancelButtonText: string;
46
+ /** Text for the save button. */
23
47
  saveButtonText: string;
48
+ /** Whether to show a confirmation dialog when the cancel button is pressed. */
24
49
  enableCancelDialog: boolean;
50
+ /** Title of the cancel confirmation dialog. */
25
51
  cancelDialogTitle: string;
52
+ /** Message of the cancel confirmation dialog. */
26
53
  cancelDialogMessage: string;
54
+ /** Text for the dismiss button in the cancel confirmation dialog. */
27
55
  cancelDialogCancelText: string;
56
+ /** Text for the confirm button in the cancel confirmation dialog. */
28
57
  cancelDialogConfirmText: string;
58
+ /** Whether to show a confirmation dialog when the save button is pressed. */
29
59
  enableSaveDialog: boolean;
60
+ /** Title of the save confirmation dialog. */
30
61
  saveDialogTitle: string;
62
+ /** Message of the save confirmation dialog. */
31
63
  saveDialogMessage: string;
64
+ /** Text for the dismiss button in the save confirmation dialog. */
32
65
  saveDialogCancelText: string;
66
+ /** Text for the confirm button in the save confirmation dialog. */
33
67
  saveDialogConfirmText: string;
68
+ /** Text displayed while the video is being trimmed (e.g. `"Trimming video..."`). */
34
69
  trimmingText: string;
70
+ /** iOS only. Whether to present the editor as a full-screen modal. */
35
71
  fullScreenModalIOS: boolean;
72
+ /** Whether to auto-play the video when the editor opens. */
36
73
  autoplay: boolean;
74
+ /** Position in milliseconds to seek to when the editor loads. Set to `-1` to disable. */
37
75
  jumpToPositionOnLoad: number;
76
+ /** Whether to automatically close the editor when trimming finishes. */
38
77
  closeWhenFinish: boolean;
78
+ /** Whether to allow the user to cancel an in-progress trim operation. */
39
79
  enableCancelTrimming: boolean;
80
+ /** Text for the cancel-trimming button. */
40
81
  cancelTrimmingButtonText: string;
82
+ /** Whether to show a confirmation dialog when cancelling an in-progress trim. */
41
83
  enableCancelTrimmingDialog: boolean;
84
+ /** Title of the cancel-trimming confirmation dialog. */
42
85
  cancelTrimmingDialogTitle: string;
86
+ /** Message of the cancel-trimming confirmation dialog. */
43
87
  cancelTrimmingDialogMessage: string;
88
+ /** Text for the dismiss button in the cancel-trimming dialog. */
44
89
  cancelTrimmingDialogCancelText: string;
90
+ /** Text for the confirm button in the cancel-trimming dialog. */
45
91
  cancelTrimmingDialogConfirmText: string;
92
+ /** Custom header text displayed at the top of the editor. */
46
93
  headerText: string;
94
+ /** Font size of the header text in sp/pt. */
47
95
  headerTextSize: number;
96
+ /** Color of the header text as a `processColor` value. */
48
97
  headerTextColor: number;
98
+ /** Whether to show an alert dialog when the media file fails to load. */
49
99
  alertOnFailToLoad: boolean;
100
+ /** Title of the fail-to-load alert. */
50
101
  alertOnFailTitle: string;
102
+ /** Message of the fail-to-load alert. */
51
103
  alertOnFailMessage: string;
104
+ /** Text for the close button of the fail-to-load alert. */
52
105
  alertOnFailCloseText: string;
53
- /**
54
- * Android only
55
- * Update status bar to black background color when editor is opened
56
- */
106
+ /** Android only. Whether to update the status bar to a black background when the editor opens. */
57
107
  changeStatusBarColorOnOpen?: boolean;
58
- /**
59
- * Color of the trimmer bar
60
- */
108
+ /** Color of the trimmer bar as a `processColor` value. */
61
109
  trimmerColor?: number;
62
- /**
63
- * Color of the trimmer left/right handle icons
64
- */
110
+ /** Color of the trimmer left/right handle icons as a `processColor` value. */
65
111
  handleIconColor?: number;
66
112
  /**
67
- * Duration for zoom-on-waiting feature in milliseconds (default: 5000)
68
- * When user pauses while dragging trim handles, the view will zoom to show
69
- * this duration around the current trim position for more precise editing
113
+ * Duration for the zoom-on-waiting feature in milliseconds (default: `5000`).
114
+ * When the user pauses while dragging trim handles, the view zooms to show
115
+ * this duration around the current trim position for more precise editing.
70
116
  */
71
117
  zoomOnWaitingDuration?: number;
72
118
  }
119
+ /**
120
+ * Options for headless (non-UI) trim operations.
121
+ */
73
122
  export interface TrimOptions extends BaseOptions {
123
+ /** Start time of the trim range in milliseconds. */
74
124
  startTime: number;
125
+ /** End time of the trim range in milliseconds. */
75
126
  endTime: number;
76
127
  }
128
+ /**
129
+ * Result returned by {@link Spec.isValidFile}.
130
+ */
77
131
  export interface FileValidationResult {
132
+ /** Whether the file is a valid audio or video file. */
78
133
  isValid: boolean;
134
+ /** Detected file type (e.g. `"video"`, `"audio"`, `"unknown"`). */
79
135
  fileType: string;
136
+ /** Duration of the media file in milliseconds, or `-1` if invalid. */
80
137
  duration: number;
81
138
  }
139
+ /**
140
+ * Result returned by a trim operation (both editor and headless).
141
+ */
82
142
  export interface TrimResult {
143
+ /** Start time of the trimmed range in milliseconds. */
83
144
  startTime: number;
145
+ /** End time of the trimmed range in milliseconds. */
84
146
  endTime: number;
147
+ /** Duration of the trimmed clip in milliseconds. */
85
148
  duration: number;
149
+ /** Absolute path to the trimmed output file. */
86
150
  outputPath: string;
151
+ /** Whether the trim operation completed successfully. */
87
152
  success: boolean;
88
153
  }
154
+ /**
155
+ * TurboModule spec for the native VideoTrim module.
156
+ */
89
157
  export interface Spec extends TurboModule {
158
+ /** Open the video trimmer editor for the given file. */
90
159
  showEditor(filePath: string, config: EditorConfig): void;
160
+ /** List all output files generated by past trim operations. */
91
161
  listFiles(): Promise<string[]>;
162
+ /** Delete all output files generated by past trim operations. Returns the number of files removed. */
92
163
  cleanFiles(): Promise<number>;
164
+ /** Delete a single file at the given path. Resolves `true` on success. */
93
165
  deleteFile(filePath: string): Promise<boolean>;
166
+ /** Programmatically close the editor if it is currently open. */
94
167
  closeEditor(): void;
168
+ /** Check whether the given URL points to a valid audio or video file. */
95
169
  isValidFile(url: string): Promise<FileValidationResult>;
170
+ /** Perform a headless trim (no UI) on the given URL with the specified options. */
96
171
  trim(url: string, options: TrimOptions): Promise<TrimResult>;
172
+ /** Emitted when the trim operation starts. */
97
173
  readonly onStartTrimming: EventEmitter<void>;
174
+ /** Emitted when the user cancels an in-progress trim operation. */
98
175
  readonly onCancelTrimming: EventEmitter<void>;
176
+ /** Emitted when the user dismisses the editor without trimming. */
99
177
  readonly onCancel: EventEmitter<void>;
178
+ /** Emitted when the editor is hidden. */
100
179
  readonly onHide: EventEmitter<void>;
180
+ /** Emitted when the editor is shown. */
101
181
  readonly onShow: EventEmitter<void>;
182
+ /** Emitted when trimming completes successfully. All time values are in milliseconds. */
102
183
  readonly onFinishTrimming: EventEmitter<{
184
+ /** Absolute path to the trimmed output file. */
103
185
  outputPath: string;
186
+ /** Start time of the trimmed range in milliseconds. */
104
187
  startTime: number;
188
+ /** End time of the trimmed range in milliseconds. */
105
189
  endTime: number;
190
+ /** Duration of the trimmed clip in milliseconds. */
106
191
  duration: number;
107
192
  }>;
193
+ /** Emitted with FFmpeg log output during trimming. */
108
194
  readonly onLog: EventEmitter<{
109
195
  level: string;
110
196
  message: string;
111
197
  sessionId: number;
112
198
  }>;
199
+ /** Emitted with FFmpeg encoding statistics during trimming. */
113
200
  readonly onStatistics: EventEmitter<{
114
201
  sessionId: number;
115
202
  videoFrameNumber: number;
@@ -120,11 +207,14 @@ export interface Spec extends TurboModule {
120
207
  bitrate: number;
121
208
  speed: number;
122
209
  }>;
210
+ /** Emitted when an error occurs during trimming or file loading. */
123
211
  readonly onError: EventEmitter<{
124
212
  message: string;
125
213
  errorCode: string;
126
214
  }>;
215
+ /** Emitted when the media file has finished loading in the editor. */
127
216
  readonly onLoad: EventEmitter<{
217
+ /** Duration of the loaded media in milliseconds. */
128
218
  duration: number;
129
219
  }>;
130
220
  }
@@ -1 +1 @@
1
- {"version":3,"file":"NativeVideoTrim.d.ts","sourceRoot":"","sources":["../../../src/NativeVideoTrim.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"NativeVideoTrim.d.ts","sourceRoot":"","sources":["../../../src/NativeVideoTrim.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-video-trim",
3
- "version": "6.0.13",
3
+ "version": "6.2.0",
4
4
  "description": "Video trimmer for your React Native app",
5
5
  "main": "./lib/module/index.js",
6
6
  "types": "./lib/typescript/src/index.d.ts",
@@ -91,7 +91,7 @@
91
91
  "workspaces": [
92
92
  "example"
93
93
  ],
94
- "packageManager": "yarn@1.2.2",
94
+ "packageManager": "yarn@4.13.0",
95
95
  "jest": {
96
96
  "preset": "react-native",
97
97
  "modulePathIgnorePatterns": [
@@ -2,122 +2,209 @@ import type { TurboModule } from 'react-native';
2
2
  import { TurboModuleRegistry } from 'react-native';
3
3
  import type { EventEmitter } from 'react-native/Libraries/Types/CodegenTypes';
4
4
 
5
+ /**
6
+ * Base options shared by both the editor and headless trim operations.
7
+ */
5
8
  export interface BaseOptions {
9
+ /** Whether to save the output file to the device's photo library. */
6
10
  saveToPhoto: boolean;
11
+ /** Media type: `"video"` or `"audio"`. */
7
12
  type: string;
13
+ /** Output file extension (e.g. `"mp4"`, `"wav"`). */
8
14
  outputExt: string;
15
+ /** Whether to remove the output file after it has been saved to the photo library. */
9
16
  removeAfterSavedToPhoto: boolean;
17
+ /** Whether to remove the output file if saving to the photo library fails. */
10
18
  removeAfterFailedToSavePhoto: boolean;
19
+ /** Whether to enable video rotation during trimming. */
11
20
  enableRotation: boolean;
21
+ /** Rotation angle in degrees (e.g. `90`, `180`, `270`). Only used when `enableRotation` is `true`. */
12
22
  rotationAngle: number;
13
23
  }
14
24
 
25
+ /**
26
+ * Configuration for the video trimmer editor UI.
27
+ */
15
28
  export interface EditorConfig extends BaseOptions {
29
+ /** Whether to enable haptic feedback when interacting with the trimmer. */
16
30
  enableHapticFeedback: boolean;
31
+ /** Maximum allowed duration for the trimmed clip in milliseconds. Set to `-1` for no limit. */
17
32
  maxDuration: number;
33
+ /** Minimum allowed duration for the trimmed clip in milliseconds. Set to `-1` for no limit. */
18
34
  minDuration: number;
35
+ /** Whether to open the system documents/files app after trimming finishes. */
19
36
  openDocumentsOnFinish: boolean;
37
+ /** Whether to open the share sheet after trimming finishes. */
20
38
  openShareSheetOnFinish: boolean;
39
+ /** Whether to remove the output file after it has been saved to documents. */
21
40
  removeAfterSavedToDocuments: boolean;
41
+ /** Whether to remove the output file if saving to documents fails. */
22
42
  removeAfterFailedToSaveDocuments: boolean;
43
+ /** Whether to remove the output file after it has been shared. */
23
44
  removeAfterShared: boolean;
45
+ /** Whether to remove the output file if sharing fails. */
24
46
  removeAfterFailedToShare: boolean;
47
+ /** Text for the cancel button. */
25
48
  cancelButtonText: string;
49
+ /** Text for the save button. */
26
50
  saveButtonText: string;
51
+ /** Whether to show a confirmation dialog when the cancel button is pressed. */
27
52
  enableCancelDialog: boolean;
53
+ /** Title of the cancel confirmation dialog. */
28
54
  cancelDialogTitle: string;
55
+ /** Message of the cancel confirmation dialog. */
29
56
  cancelDialogMessage: string;
57
+ /** Text for the dismiss button in the cancel confirmation dialog. */
30
58
  cancelDialogCancelText: string;
59
+ /** Text for the confirm button in the cancel confirmation dialog. */
31
60
  cancelDialogConfirmText: string;
61
+ /** Whether to show a confirmation dialog when the save button is pressed. */
32
62
  enableSaveDialog: boolean;
63
+ /** Title of the save confirmation dialog. */
33
64
  saveDialogTitle: string;
65
+ /** Message of the save confirmation dialog. */
34
66
  saveDialogMessage: string;
67
+ /** Text for the dismiss button in the save confirmation dialog. */
35
68
  saveDialogCancelText: string;
69
+ /** Text for the confirm button in the save confirmation dialog. */
36
70
  saveDialogConfirmText: string;
71
+ /** Text displayed while the video is being trimmed (e.g. `"Trimming video..."`). */
37
72
  trimmingText: string;
73
+ /** iOS only. Whether to present the editor as a full-screen modal. */
38
74
  fullScreenModalIOS: boolean;
75
+ /** Whether to auto-play the video when the editor opens. */
39
76
  autoplay: boolean;
77
+ /** Position in milliseconds to seek to when the editor loads. Set to `-1` to disable. */
40
78
  jumpToPositionOnLoad: number;
79
+ /** Whether to automatically close the editor when trimming finishes. */
41
80
  closeWhenFinish: boolean;
81
+ /** Whether to allow the user to cancel an in-progress trim operation. */
42
82
  enableCancelTrimming: boolean;
83
+ /** Text for the cancel-trimming button. */
43
84
  cancelTrimmingButtonText: string;
85
+ /** Whether to show a confirmation dialog when cancelling an in-progress trim. */
44
86
  enableCancelTrimmingDialog: boolean;
87
+ /** Title of the cancel-trimming confirmation dialog. */
45
88
  cancelTrimmingDialogTitle: string;
89
+ /** Message of the cancel-trimming confirmation dialog. */
46
90
  cancelTrimmingDialogMessage: string;
91
+ /** Text for the dismiss button in the cancel-trimming dialog. */
47
92
  cancelTrimmingDialogCancelText: string;
93
+ /** Text for the confirm button in the cancel-trimming dialog. */
48
94
  cancelTrimmingDialogConfirmText: string;
95
+ /** Custom header text displayed at the top of the editor. */
49
96
  headerText: string;
97
+ /** Font size of the header text in sp/pt. */
50
98
  headerTextSize: number;
99
+ /** Color of the header text as a `processColor` value. */
51
100
  headerTextColor: number;
101
+ /** Whether to show an alert dialog when the media file fails to load. */
52
102
  alertOnFailToLoad: boolean;
103
+ /** Title of the fail-to-load alert. */
53
104
  alertOnFailTitle: string;
105
+ /** Message of the fail-to-load alert. */
54
106
  alertOnFailMessage: string;
107
+ /** Text for the close button of the fail-to-load alert. */
55
108
  alertOnFailCloseText: string;
56
- /**
57
- * Android only
58
- * Update status bar to black background color when editor is opened
59
- */
109
+ /** Android only. Whether to update the status bar to a black background when the editor opens. */
60
110
  changeStatusBarColorOnOpen?: boolean;
61
- /**
62
- * Color of the trimmer bar
63
- */
111
+ /** Color of the trimmer bar as a `processColor` value. */
64
112
  trimmerColor?: number;
65
- /**
66
- * Color of the trimmer left/right handle icons
67
- */
113
+ /** Color of the trimmer left/right handle icons as a `processColor` value. */
68
114
  handleIconColor?: number;
69
115
  /**
70
- * Duration for zoom-on-waiting feature in milliseconds (default: 5000)
71
- * When user pauses while dragging trim handles, the view will zoom to show
72
- * this duration around the current trim position for more precise editing
116
+ * Duration for the zoom-on-waiting feature in milliseconds (default: `5000`).
117
+ * When the user pauses while dragging trim handles, the view zooms to show
118
+ * this duration around the current trim position for more precise editing.
73
119
  */
74
120
  zoomOnWaitingDuration?: number;
75
121
  }
76
122
 
123
+ /**
124
+ * Options for headless (non-UI) trim operations.
125
+ */
77
126
  export interface TrimOptions extends BaseOptions {
127
+ /** Start time of the trim range in milliseconds. */
78
128
  startTime: number;
129
+ /** End time of the trim range in milliseconds. */
79
130
  endTime: number;
80
131
  }
81
132
 
133
+ /**
134
+ * Result returned by {@link Spec.isValidFile}.
135
+ */
82
136
  export interface FileValidationResult {
137
+ /** Whether the file is a valid audio or video file. */
83
138
  isValid: boolean;
139
+ /** Detected file type (e.g. `"video"`, `"audio"`, `"unknown"`). */
84
140
  fileType: string;
141
+ /** Duration of the media file in milliseconds, or `-1` if invalid. */
85
142
  duration: number;
86
143
  }
87
144
 
145
+ /**
146
+ * Result returned by a trim operation (both editor and headless).
147
+ */
88
148
  export interface TrimResult {
149
+ /** Start time of the trimmed range in milliseconds. */
89
150
  startTime: number;
151
+ /** End time of the trimmed range in milliseconds. */
90
152
  endTime: number;
153
+ /** Duration of the trimmed clip in milliseconds. */
91
154
  duration: number;
155
+ /** Absolute path to the trimmed output file. */
92
156
  outputPath: string;
157
+ /** Whether the trim operation completed successfully. */
93
158
  success: boolean;
94
159
  }
95
160
 
161
+ /**
162
+ * TurboModule spec for the native VideoTrim module.
163
+ */
96
164
  export interface Spec extends TurboModule {
165
+ /** Open the video trimmer editor for the given file. */
97
166
  showEditor(filePath: string, config: EditorConfig): void;
167
+ /** List all output files generated by past trim operations. */
98
168
  listFiles(): Promise<string[]>;
169
+ /** Delete all output files generated by past trim operations. Returns the number of files removed. */
99
170
  cleanFiles(): Promise<number>;
171
+ /** Delete a single file at the given path. Resolves `true` on success. */
100
172
  deleteFile(filePath: string): Promise<boolean>;
173
+ /** Programmatically close the editor if it is currently open. */
101
174
  closeEditor(): void;
175
+ /** Check whether the given URL points to a valid audio or video file. */
102
176
  isValidFile(url: string): Promise<FileValidationResult>;
177
+ /** Perform a headless trim (no UI) on the given URL with the specified options. */
103
178
  trim(url: string, options: TrimOptions): Promise<TrimResult>;
104
179
 
180
+ /** Emitted when the trim operation starts. */
105
181
  readonly onStartTrimming: EventEmitter<void>;
182
+ /** Emitted when the user cancels an in-progress trim operation. */
106
183
  readonly onCancelTrimming: EventEmitter<void>;
184
+ /** Emitted when the user dismisses the editor without trimming. */
107
185
  readonly onCancel: EventEmitter<void>;
186
+ /** Emitted when the editor is hidden. */
108
187
  readonly onHide: EventEmitter<void>;
188
+ /** Emitted when the editor is shown. */
109
189
  readonly onShow: EventEmitter<void>;
190
+ /** Emitted when trimming completes successfully. All time values are in milliseconds. */
110
191
  readonly onFinishTrimming: EventEmitter<{
192
+ /** Absolute path to the trimmed output file. */
111
193
  outputPath: string;
194
+ /** Start time of the trimmed range in milliseconds. */
112
195
  startTime: number;
196
+ /** End time of the trimmed range in milliseconds. */
113
197
  endTime: number;
198
+ /** Duration of the trimmed clip in milliseconds. */
114
199
  duration: number;
115
200
  }>;
201
+ /** Emitted with FFmpeg log output during trimming. */
116
202
  readonly onLog: EventEmitter<{
117
203
  level: string;
118
204
  message: string;
119
205
  sessionId: number;
120
206
  }>;
207
+ /** Emitted with FFmpeg encoding statistics during trimming. */
121
208
  readonly onStatistics: EventEmitter<{
122
209
  sessionId: number;
123
210
  videoFrameNumber: number;
@@ -128,11 +215,14 @@ export interface Spec extends TurboModule {
128
215
  bitrate: number;
129
216
  speed: number;
130
217
  }>;
218
+ /** Emitted when an error occurs during trimming or file loading. */
131
219
  readonly onError: EventEmitter<{
132
220
  message: string;
133
221
  errorCode: string;
134
222
  }>;
223
+ /** Emitted when the media file has finished loading in the editor. */
135
224
  readonly onLoad: EventEmitter<{
225
+ /** Duration of the loaded media in milliseconds. */
136
226
  duration: number;
137
227
  }>;
138
228
  }