react-native-video-trim 4.1.0 → 5.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (99) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +89 -76
  3. package/VideoTrim.podspec +3 -3
  4. package/android/build.gradle +6 -53
  5. package/android/gradle.properties +1 -1
  6. package/android/src/main/AndroidManifest.xml +1 -1
  7. package/android/src/main/java/com/{margelo/nitro/videotrim/VideoTrim.kt → videotrim/VideoTrimModule.kt} +246 -232
  8. package/android/src/main/java/com/videotrim/VideoTrimPackage.kt +33 -0
  9. package/android/src/main/java/com/{margelo/nitro/videotrim → videotrim}/enums/ErrorCode.java +1 -1
  10. package/android/src/main/java/com/{margelo/nitro/videotrim → videotrim}/interfaces/IVideoTrimmerView.java +1 -1
  11. package/android/src/main/java/com/{margelo/nitro/videotrim → videotrim}/interfaces/VideoTrimListener.java +5 -4
  12. package/android/src/main/java/com/{margelo/nitro/videotrim → videotrim}/utils/MediaMetadataUtil.java +1 -1
  13. package/android/src/main/java/com/{margelo/nitro/videotrim → videotrim}/utils/StorageUtil.java +1 -1
  14. package/android/src/main/java/com/{margelo/nitro/videotrim → videotrim}/utils/VideoTrimmerUtil.java +20 -18
  15. package/android/src/main/java/com/{margelo/nitro/videotrim → videotrim}/widgets/VideoTrimmerView.java +44 -45
  16. package/ios/AssetLoader.h +19 -0
  17. package/ios/AssetLoader.mm +87 -0
  18. package/ios/ErrorCode.h +9 -0
  19. package/ios/ProgressAlertController.h +15 -0
  20. package/ios/ProgressAlertController.mm +78 -0
  21. package/ios/VideoTrim.h +31 -0
  22. package/ios/VideoTrim.mm +663 -0
  23. package/ios/VideoTrimmer.h +67 -0
  24. package/ios/VideoTrimmer.mm +863 -0
  25. package/ios/VideoTrimmerThumb.h +23 -0
  26. package/ios/VideoTrimmerThumb.mm +175 -0
  27. package/ios/VideoTrimmerViewController.h +52 -0
  28. package/ios/VideoTrimmerViewController.mm +533 -0
  29. package/lib/module/NativeVideoTrim.js +5 -0
  30. package/lib/module/NativeVideoTrim.js.map +1 -0
  31. package/lib/module/index.js +24 -24
  32. package/lib/module/index.js.map +1 -1
  33. package/lib/typescript/src/NativeVideoTrim.d.ts +107 -0
  34. package/lib/typescript/src/NativeVideoTrim.d.ts.map +1 -0
  35. package/lib/typescript/src/index.d.ts +16 -10
  36. package/lib/typescript/src/index.d.ts.map +1 -1
  37. package/package.json +15 -18
  38. package/src/NativeVideoTrim.ts +113 -0
  39. package/src/index.tsx +29 -31
  40. package/android/CMakeLists.txt +0 -24
  41. package/android/src/main/cpp/cpp-adapter.cpp +0 -6
  42. package/android/src/main/java/com/margelo/nitro/videotrim/VideoTrimPackage.kt +0 -22
  43. package/ios/AssetLoader.swift +0 -99
  44. package/ios/ErrorCode.swift +0 -17
  45. package/ios/ProgressAlertController.swift +0 -100
  46. package/ios/VideoTrim.swift +0 -67
  47. package/ios/VideoTrimImpl.swift +0 -957
  48. package/ios/VideoTrimmer.swift +0 -872
  49. package/ios/VideoTrimmerThumb.swift +0 -175
  50. package/ios/VideoTrimmerViewController.swift +0 -557
  51. package/lib/module/VideoTrim.nitro.js +0 -4
  52. package/lib/module/VideoTrim.nitro.js.map +0 -1
  53. package/lib/typescript/src/VideoTrim.nitro.d.ts +0 -257
  54. package/lib/typescript/src/VideoTrim.nitro.d.ts.map +0 -1
  55. package/nitrogen/generated/android/c++/JEditorConfig.hpp +0 -237
  56. package/nitrogen/generated/android/c++/JFileValidationResult.hpp +0 -61
  57. package/nitrogen/generated/android/c++/JFunc_void.hpp +0 -74
  58. package/nitrogen/generated/android/c++/JFunc_void_std__string_std__unordered_map_std__string__std__string_.hpp +0 -89
  59. package/nitrogen/generated/android/c++/JHybridVideoTrimSpec.cpp +0 -151
  60. package/nitrogen/generated/android/c++/JHybridVideoTrimSpec.hpp +0 -68
  61. package/nitrogen/generated/android/c++/JTrimOptions.hpp +0 -109
  62. package/nitrogen/generated/android/kotlin/com/margelo/nitro/videotrim/EditorConfig.kt +0 -72
  63. package/nitrogen/generated/android/kotlin/com/margelo/nitro/videotrim/FileValidationResult.kt +0 -28
  64. package/nitrogen/generated/android/kotlin/com/margelo/nitro/videotrim/Func_void.kt +0 -80
  65. package/nitrogen/generated/android/kotlin/com/margelo/nitro/videotrim/Func_void_std__string_std__unordered_map_std__string__std__string_.kt +0 -80
  66. package/nitrogen/generated/android/kotlin/com/margelo/nitro/videotrim/HybridVideoTrimSpec.kt +0 -86
  67. package/nitrogen/generated/android/kotlin/com/margelo/nitro/videotrim/TrimOptions.kt +0 -40
  68. package/nitrogen/generated/android/kotlin/com/margelo/nitro/videotrim/videotrimOnLoad.kt +0 -35
  69. package/nitrogen/generated/android/videotrim+autolinking.cmake +0 -78
  70. package/nitrogen/generated/android/videotrim+autolinking.gradle +0 -27
  71. package/nitrogen/generated/android/videotrimOnLoad.cpp +0 -50
  72. package/nitrogen/generated/android/videotrimOnLoad.hpp +0 -25
  73. package/nitrogen/generated/ios/VideoTrim+autolinking.rb +0 -60
  74. package/nitrogen/generated/ios/VideoTrim-Swift-Cxx-Bridge.cpp +0 -96
  75. package/nitrogen/generated/ios/VideoTrim-Swift-Cxx-Bridge.hpp +0 -374
  76. package/nitrogen/generated/ios/VideoTrim-Swift-Cxx-Umbrella.hpp +0 -56
  77. package/nitrogen/generated/ios/VideoTrimAutolinking.mm +0 -33
  78. package/nitrogen/generated/ios/VideoTrimAutolinking.swift +0 -25
  79. package/nitrogen/generated/ios/c++/HybridVideoTrimSpecSwift.cpp +0 -11
  80. package/nitrogen/generated/ios/c++/HybridVideoTrimSpecSwift.hpp +0 -127
  81. package/nitrogen/generated/ios/swift/EditorConfig.swift +0 -541
  82. package/nitrogen/generated/ios/swift/FileValidationResult.swift +0 -57
  83. package/nitrogen/generated/ios/swift/Func_void.swift +0 -46
  84. package/nitrogen/generated/ios/swift/Func_void_FileValidationResult.swift +0 -46
  85. package/nitrogen/generated/ios/swift/Func_void_bool.swift +0 -46
  86. package/nitrogen/generated/ios/swift/Func_void_double.swift +0 -46
  87. package/nitrogen/generated/ios/swift/Func_void_std__exception_ptr.swift +0 -46
  88. package/nitrogen/generated/ios/swift/Func_void_std__string.swift +0 -46
  89. package/nitrogen/generated/ios/swift/Func_void_std__string_std__unordered_map_std__string__std__string_.swift +0 -54
  90. package/nitrogen/generated/ios/swift/Func_void_std__vector_std__string_.swift +0 -46
  91. package/nitrogen/generated/ios/swift/HybridVideoTrimSpec.swift +0 -54
  92. package/nitrogen/generated/ios/swift/HybridVideoTrimSpec_cxx.swift +0 -241
  93. package/nitrogen/generated/ios/swift/TrimOptions.swift +0 -189
  94. package/nitrogen/generated/shared/c++/EditorConfig.hpp +0 -253
  95. package/nitrogen/generated/shared/c++/FileValidationResult.hpp +0 -77
  96. package/nitrogen/generated/shared/c++/HybridVideoTrimSpec.cpp +0 -27
  97. package/nitrogen/generated/shared/c++/HybridVideoTrimSpec.hpp +0 -80
  98. package/nitrogen/generated/shared/c++/TrimOptions.hpp +0 -125
  99. package/src/VideoTrim.nitro.ts +0 -263
@@ -0,0 +1,33 @@
1
+ package com.videotrim
2
+
3
+ import com.facebook.react.BaseReactPackage
4
+ import com.facebook.react.bridge.NativeModule
5
+ import com.facebook.react.bridge.ReactApplicationContext
6
+ import com.facebook.react.module.model.ReactModuleInfo
7
+ import com.facebook.react.module.model.ReactModuleInfoProvider
8
+ import java.util.HashMap
9
+
10
+ class VideoTrimPackage : BaseReactPackage() {
11
+ override fun getModule(name: String, reactContext: ReactApplicationContext): NativeModule? {
12
+ return if (name == VideoTrimModule.NAME) {
13
+ VideoTrimModule(reactContext)
14
+ } else {
15
+ null
16
+ }
17
+ }
18
+
19
+ override fun getReactModuleInfoProvider(): ReactModuleInfoProvider {
20
+ return ReactModuleInfoProvider {
21
+ val moduleInfos: MutableMap<String, ReactModuleInfo> = HashMap()
22
+ moduleInfos[VideoTrimModule.NAME] = ReactModuleInfo(
23
+ VideoTrimModule.NAME,
24
+ VideoTrimModule.NAME,
25
+ false, // canOverrideExistingModule
26
+ false, // needsEagerInit
27
+ false, // isCxxModule
28
+ true // isTurboModule
29
+ )
30
+ moduleInfos
31
+ }
32
+ }
33
+ }
@@ -1,4 +1,4 @@
1
- package com.margelo.nitro.videotrim.enums;
1
+ package com.videotrim.enums;
2
2
 
3
3
  public enum ErrorCode {
4
4
  TRIMMING_FAILED,
@@ -1,4 +1,4 @@
1
- package com.margelo.nitro.videotrim.interfaces;
1
+ package com.videotrim.interfaces;
2
2
 
3
3
  public interface IVideoTrimmerView {
4
4
  void onDestroy();
@@ -1,6 +1,7 @@
1
- package com.margelo.nitro.videotrim.interfaces;
1
+ package com.videotrim.interfaces;
2
2
 
3
- import com.margelo.nitro.videotrim.enums.ErrorCode;
3
+ import com.facebook.react.bridge.ReadableMap;
4
+ import com.videotrim.enums.ErrorCode;
4
5
 
5
6
  import java.util.Map;
6
7
 
@@ -12,6 +13,6 @@ public interface VideoTrimListener {
12
13
  void onError(String errorMessage, ErrorCode errorCode);
13
14
  void onCancel();
14
15
  void onSave();
15
- void onLog(Map<String, String> log);
16
- void onStatistics(Map<String, String> statistics);
16
+ void onLog(ReadableMap log);
17
+ void onStatistics(ReadableMap statistics);
17
18
  }
@@ -1,4 +1,4 @@
1
- package com.margelo.nitro.videotrim.utils;
1
+ package com.videotrim.utils;
2
2
 
3
3
  import android.media.MediaMetadataRetriever;
4
4
  import android.util.Log;
@@ -1,4 +1,4 @@
1
- package com.margelo.nitro.videotrim.utils;
1
+ package com.videotrim.utils;
2
2
 
3
3
  import android.content.ContentValues;
4
4
  import android.content.Context;
@@ -1,4 +1,4 @@
1
- package com.margelo.nitro.videotrim.utils;
1
+ package com.videotrim.utils;
2
2
 
3
3
  import android.annotation.SuppressLint;
4
4
  import android.graphics.Bitmap;
@@ -9,8 +9,10 @@ import com.arthenica.ffmpegkit.FFmpegKit;
9
9
  import com.arthenica.ffmpegkit.FFmpegSession;
10
10
  import com.arthenica.ffmpegkit.ReturnCode;
11
11
  import com.arthenica.ffmpegkit.SessionState;
12
- import com.margelo.nitro.videotrim.enums.ErrorCode;
13
- import com.margelo.nitro.videotrim.interfaces.VideoTrimListener;
12
+ import com.facebook.react.bridge.Arguments;
13
+ import com.facebook.react.bridge.WritableMap;
14
+ import com.videotrim.enums.ErrorCode;
15
+ import com.videotrim.interfaces.VideoTrimListener;
14
16
 
15
17
  import java.text.SimpleDateFormat;
16
18
  import java.util.ArrayList;
@@ -99,11 +101,11 @@ public class VideoTrimmerUtil {
99
101
  }, log -> {
100
102
  Log.d(TAG, "FFmpeg process started with log " + log.getMessage());
101
103
 
102
- Map<String, String> map = new HashMap<>();
103
- map.put("level", String.valueOf(log.getLevel().getValue()));
104
- map.put("message", log.getMessage());
105
- map.put("sessionId", String.valueOf(log.getSessionId()));
106
- map.put("logStr", log.toString());
104
+ WritableMap map = Arguments.createMap();
105
+ map.putInt("level", log.getLevel().getValue());
106
+ map.putString("message", log.getMessage());
107
+ map.putDouble("sessionId", log.getSessionId());
108
+ map.putString("logStr", log.toString());
107
109
 
108
110
  callback.onLog(map);
109
111
  }, statistics -> {
@@ -114,16 +116,16 @@ public class VideoTrimmerUtil {
114
116
  callback.onTrimmingProgress(Math.min(Math.max(completePercentage, 0), 100));
115
117
  }
116
118
 
117
- Map<String, String> map = new HashMap<>();
118
- map.put("sessionId", String.valueOf(statistics.getSessionId()));
119
- map.put("videoFrameNumber", String.valueOf(statistics.getVideoFrameNumber()));
120
- map.put("videoFps", String.valueOf(statistics.getVideoFps()));
121
- map.put("videoQuality", String.valueOf(statistics.getVideoQuality()));
122
- map.put("size", String.valueOf(statistics.getSize()));
123
- map.put("time", String.valueOf(statistics.getTime()));
124
- map.put("bitrate", String.valueOf(statistics.getBitrate()));
125
- map.put("speed", String.valueOf(statistics.getSpeed()));
126
- map.put("statisticsStr", statistics.toString());
119
+ WritableMap map = Arguments.createMap();
120
+ map.putDouble("sessionId", statistics.getSessionId());
121
+ map.putInt("videoFrameNumber", statistics.getVideoFrameNumber());
122
+ map.putDouble("videoFps", statistics.getVideoFps());
123
+ map.putDouble("videoQuality", statistics.getVideoQuality());
124
+ map.putDouble("size", statistics.getSize());
125
+ map.putDouble("time", statistics.getTime());
126
+ map.putDouble("bitrate", statistics.getBitrate());
127
+ map.putDouble("speed", statistics.getSpeed());
128
+ map.putString("statisticsStr", statistics.toString());
127
129
  callback.onStatistics(map);
128
130
  });
129
131
  }
@@ -1,13 +1,14 @@
1
- package com.margelo.nitro.videotrim.widgets;
1
+ package com.videotrim.widgets;
2
2
 
3
3
  import static com.facebook.react.bridge.UiThreadUtil.runOnUiThread;
4
- import static com.margelo.nitro.videotrim.utils.VideoTrimmerUtil.RECYCLER_VIEW_PADDING;
5
- import static com.margelo.nitro.videotrim.utils.VideoTrimmerUtil.VIDEO_FRAMES_WIDTH;
4
+ import static com.videotrim.utils.VideoTrimmerUtil.RECYCLER_VIEW_PADDING;
5
+ import static com.videotrim.utils.VideoTrimmerUtil.VIDEO_FRAMES_WIDTH;
6
6
 
7
7
  import android.content.Context;
8
8
  import android.content.pm.ActivityInfo;
9
9
  import android.content.res.Configuration;
10
10
  import android.graphics.Bitmap;
11
+ import android.graphics.Color;
11
12
  import android.graphics.drawable.GradientDrawable;
12
13
  import android.media.MediaMetadataRetriever;
13
14
  import android.media.MediaPlayer;
@@ -34,17 +35,18 @@ import androidx.appcompat.app.AlertDialog;
34
35
 
35
36
  import com.arthenica.ffmpegkit.FFmpegSession;
36
37
  import com.facebook.react.bridge.ReactApplicationContext;
37
- import com.margelo.nitro.videotrim.EditorConfig;
38
- import com.margelo.nitro.videotrim.R;
39
- import com.margelo.nitro.videotrim.enums.ErrorCode;
40
- import com.margelo.nitro.videotrim.interfaces.IVideoTrimmerView;
41
- import com.margelo.nitro.videotrim.interfaces.VideoTrimListener;
42
- import com.margelo.nitro.videotrim.utils.MediaMetadataUtil;
43
- import com.margelo.nitro.videotrim.utils.StorageUtil;
44
- import com.margelo.nitro.videotrim.utils.VideoTrimmerUtil;
38
+ import com.facebook.react.bridge.ReadableMap;
39
+ import com.videotrim.R;
40
+ import com.videotrim.enums.ErrorCode;
41
+ import com.videotrim.interfaces.IVideoTrimmerView;
42
+ import com.videotrim.interfaces.VideoTrimListener;
43
+ import com.videotrim.utils.MediaMetadataUtil;
44
+ import com.videotrim.utils.StorageUtil;
45
+ import com.videotrim.utils.VideoTrimmerUtil;
45
46
 
46
47
  import java.io.IOException;
47
48
  import java.util.Locale;
49
+ import java.util.Objects;
48
50
 
49
51
  import iknow.android.utils.DeviceUtil;
50
52
  import iknow.android.utils.thread.BackgroundExecutor;
@@ -119,16 +121,16 @@ public class VideoTrimmerView extends FrameLayout implements IVideoTrimmerView {
119
121
  private String alertOnFailCloseText = "Close";
120
122
  private View currentSelectedhandle;
121
123
 
122
- public VideoTrimmerView(ReactApplicationContext context, EditorConfig config, AttributeSet attrs) {
124
+ public VideoTrimmerView(ReactApplicationContext context, ReadableMap config, AttributeSet attrs) {
123
125
  this(context, attrs, 0, config);
124
126
  }
125
127
 
126
- public VideoTrimmerView(ReactApplicationContext context, AttributeSet attrs, int defStyleAttr, EditorConfig config) {
128
+ public VideoTrimmerView(ReactApplicationContext context, AttributeSet attrs, int defStyleAttr, ReadableMap config) {
127
129
  super(context, attrs, defStyleAttr);
128
130
  init(context, config);
129
131
  }
130
132
 
131
- private void init(ReactApplicationContext context, EditorConfig config) {
133
+ private void init(ReactApplicationContext context, ReadableMap config) {
132
134
  this.mContext = context;
133
135
 
134
136
  context.getCurrentActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
@@ -450,50 +452,47 @@ public class VideoTrimmerView extends FrameLayout implements IVideoTrimmerView {
450
452
  return screenWidth;
451
453
  }
452
454
 
453
- private void configure(EditorConfig config) {
454
- if (config.getMaxDuration() > 0) {
455
- mMaxDuration = (long) Math.max(0, config.getMaxDuration() * 1000L);
455
+ private void configure(ReadableMap config) {
456
+ if (config.hasKey("maxDuration") && config.getDouble("maxDuration") > 0) {
457
+ mMaxDuration = (long) Math.max(0, config.getDouble("maxDuration") * 1000L);
456
458
  }
457
459
 
458
- if (config.getMinDuration() > 0) {
459
- mMinDuration = (long) Math.max(1000L, config.getMinDuration() * 1000L);
460
+ if (config.hasKey("minDuration") && config.getDouble("minDuration") > 0) {
461
+ mMinDuration = (long) Math.max(1000L, config.getDouble("minDuration") * 1000L);
460
462
  }
461
463
 
462
- cancelBtn.setText(config.getCancelButtonText());
464
+ cancelBtn.setText(config.getString("cancelButtonText"));
465
+ saveBtn.setText(config.getString("saveButtonText"));
466
+ isVideoType = config.hasKey("type") && Objects.equals(config.getString("type"), "video");
467
+ System.out.println("1111 isVideoType: " + isVideoType);
463
468
 
464
- saveBtn.setText(config.getSaveButtonText());
465
-
466
- isVideoType = config.getType().equals("video");
467
-
468
- mOutputExt = config.getOutputExt();
469
+ mOutputExt = config.hasKey("outputExt") ? config.getString("outputExt") : "mp4";
469
470
  if (!isVideoType) {
470
471
  mOutputExt = "wav";
471
472
  }
473
+ enableHapticFeedback = config.hasKey("enableHapticFeedback") && config.getBoolean("enableHapticFeedback");
474
+ autoplay = config.hasKey("autoplay") && config.getBoolean("autoplay");
472
475
 
473
- enableHapticFeedback = config.getEnableHapticFeedback();
474
- autoplay = config.getAutoplay();
475
-
476
- if (config.getJumpToPositionOnLoad() > 0) {
477
- jumpToPositionOnLoad = (long) config.getJumpToPositionOnLoad();
476
+ if (config.hasKey("jumpToPositionOnLoad") && config.getDouble("jumpToPositionOnLoad") > 0) {
477
+ jumpToPositionOnLoad = (long) Math.max(0, config.getDouble("jumpToPositionOnLoad") * 1000L);
478
478
  }
479
+ headerText.setText(config.hasKey("headerText") ? config.getString("headerText") : "");
479
480
 
480
- headerText.setText(config.getHeaderText());
481
-
482
- int textSize = (int) config.getHeaderTextSize();
483
- if (textSize < 0) {
484
- textSize = 16;
485
- }
486
- headerText.setTextSize(TypedValue.COMPLEX_UNIT_DIP, textSize);
487
- headerText.setTextColor((int) config.getHeaderTextColor());
481
+ int textSize = config.hasKey("headerTextSize") ? config.getInt("headerTextSize") : 16;
482
+ if (textSize < 0) {
483
+ textSize = 16;
484
+ }
488
485
 
489
- headerView.setVisibility(View.VISIBLE);
486
+ headerText.setTextSize(TypedValue.COMPLEX_UNIT_DIP, textSize);
487
+ headerText.setTextColor(config.hasKey("headerTextColor") ? config.getInt("headerTextColor") : Color.BLACK);
490
488
 
491
- alertOnFailToLoad = config.getAlertOnFailToLoad();
492
- alertOnFailTitle = config.getAlertOnFailTitle();
493
- alertOnFailMessage = config.getAlertOnFailMessage();
494
- alertOnFailCloseText = config.getAlertOnFailCloseText();
495
- enableRotation = config.getEnableRotation();
496
- rotationAngle = config.getRotationAngle();
489
+ headerView.setVisibility(View.VISIBLE);
490
+ alertOnFailToLoad = config.hasKey("alertOnFailToLoad") && config.getBoolean("alertOnFailToLoad");
491
+ alertOnFailTitle = config.hasKey("alertOnFailTitle") ? config.getString("alertOnFailTitle") : "Error";
492
+ alertOnFailMessage = config.hasKey("alertOnFailMessage") ? config.getString("alertOnFailMessage") : "Fail to load media. Possibly invalid file or no network connection";
493
+ alertOnFailCloseText = config.hasKey("alertOnFailCloseText") ? config.getString("alertOnFailCloseText") : "Close";
494
+ enableRotation = config.hasKey("enableRotation") && config.getBoolean("enableRotation");
495
+ rotationAngle = config.hasKey("rotationAngle") ? config.getDouble("rotationAngle") : 0.0;
497
496
  }
498
497
 
499
498
  private void startTimingRunnable() {
@@ -0,0 +1,19 @@
1
+ #import <Foundation/Foundation.h>
2
+ #import <AVFoundation/AVFoundation.h>
3
+
4
+ @class AssetLoader;
5
+
6
+ @protocol AssetLoaderDelegate <NSObject>
7
+ @optional
8
+ - (void)assetLoaderDidSucceed:(AssetLoader *)assetLoader;
9
+ - (void)assetLoader:(AssetLoader *)assetLoader didFailWithError:(NSError *)error forKey:(NSString *)key;
10
+ @end
11
+
12
+ @interface AssetLoader : NSObject
13
+
14
+ @property (nonatomic, weak) id<AssetLoaderDelegate> delegate;
15
+ @property (nonatomic, strong, readonly) AVURLAsset *asset;
16
+
17
+ - (void)loadAssetWithURL:(NSURL *)url isVideoType:(BOOL)isVideoType;
18
+
19
+ @end
@@ -0,0 +1,87 @@
1
+ #import "AssetLoader.h"
2
+
3
+ @interface AssetLoader ()
4
+ @property (nonatomic, strong) AVURLAsset *asset;
5
+ @end
6
+
7
+ @implementation AssetLoader
8
+
9
+ - (void)loadAssetWithURL:(NSURL *)url isVideoType:(BOOL)isVideoType {
10
+ NSDictionary *options = @{ AVURLAssetPreferPreciseDurationAndTimingKey: @YES };
11
+ self.asset = [AVURLAsset URLAssetWithURL:url options:options];
12
+ NSArray *keys = @[ @"duration", @"tracks" ];
13
+ [self.asset loadValuesAsynchronouslyForKeys:keys completionHandler:^{
14
+ [self assetLoaded:isVideoType];
15
+ }];
16
+ }
17
+
18
+ - (void)assetLoaded:(BOOL)isVideoType {
19
+ NSArray *keys = @[ @"duration", @"tracks" ];
20
+ for (NSString *key in keys) {
21
+ NSError *error = nil;
22
+ AVKeyValueStatus status = [self.asset statusOfValueForKey:key error:&error];
23
+ if (status == AVKeyValueStatusFailed) {
24
+ if ([self.delegate respondsToSelector:@selector(assetLoader:didFailWithError:forKey:)]) {
25
+ [self.delegate assetLoader:self didFailWithError:error forKey:key];
26
+ }
27
+ return;
28
+ } else if (status == AVKeyValueStatusCancelled) {
29
+ NSError *cancelError = [NSError errorWithDomain:@"AssetLoader" code:-1 userInfo:@{ NSLocalizedDescriptionKey: [NSString stringWithFormat:@"%@ loading was cancelled", key] }];
30
+ if ([self.delegate respondsToSelector:@selector(assetLoader:didFailWithError:forKey:)]) {
31
+ [self.delegate assetLoader:self didFailWithError:cancelError forKey:key];
32
+ }
33
+ return;
34
+ } else if (status != AVKeyValueStatusLoaded) {
35
+ NSError *unknownError = [NSError errorWithDomain:@"AssetLoader" code:-1 userInfo:@{ NSLocalizedDescriptionKey: [NSString stringWithFormat:@"%@ is in an unknown state", key] }];
36
+ if ([self.delegate respondsToSelector:@selector(assetLoader:didFailWithError:forKey:)]) {
37
+ [self.delegate assetLoader:self didFailWithError:unknownError forKey:key];
38
+ }
39
+ return;
40
+ }
41
+ }
42
+ if (isVideoType) {
43
+ [self processAssetTracks];
44
+ } else {
45
+ if ([self.delegate respondsToSelector:@selector(assetLoaderDidSucceed:)]) {
46
+ [self.delegate assetLoaderDidSucceed:self];
47
+ }
48
+ }
49
+ }
50
+
51
+ - (void)processAssetTracks {
52
+ NSArray *videoTracks = [self.asset tracksWithMediaType:AVMediaTypeVideo];
53
+ AVAssetTrack *videoTrack = videoTracks.firstObject;
54
+ if (!videoTrack) {
55
+ NSError *error = [NSError errorWithDomain:@"AssetLoader" code:-1 userInfo:@{ NSLocalizedDescriptionKey: @"No video tracks found" }];
56
+ if ([self.delegate respondsToSelector:@selector(assetLoader:didFailWithError:forKey:)]) {
57
+ [self.delegate assetLoader:self didFailWithError:error forKey:@"tracks"];
58
+ }
59
+ return;
60
+ }
61
+ NSArray *trackKeys = @[ @"naturalSize", @"preferredTransform" ];
62
+ [videoTrack loadValuesAsynchronouslyForKeys:trackKeys completionHandler:^{
63
+ [self trackPropertiesLoaded:videoTrack];
64
+ }];
65
+ }
66
+
67
+ - (void)trackPropertiesLoaded:(AVAssetTrack *)track {
68
+ NSError *error = nil;
69
+ AVKeyValueStatus naturalSizeStatus = [track statusOfValueForKey:@"naturalSize" error:&error];
70
+ AVKeyValueStatus preferredTransformStatus = [track statusOfValueForKey:@"preferredTransform" error:&error];
71
+ if (naturalSizeStatus == AVKeyValueStatusLoaded && preferredTransformStatus == AVKeyValueStatusLoaded) {
72
+ CGSize naturalSize = track.naturalSize;
73
+ CGAffineTransform preferredTransform = track.preferredTransform;
74
+ NSLog(@"Natural size: %@", NSStringFromCGSize(naturalSize));
75
+ NSLog(@"Preferred transform: %@", NSStringFromCGAffineTransform(preferredTransform));
76
+ if ([self.delegate respondsToSelector:@selector(assetLoaderDidSucceed:)]) {
77
+ [self.delegate assetLoaderDidSucceed:self];
78
+ }
79
+ } else {
80
+ if ([self.delegate respondsToSelector:@selector(assetLoader:didFailWithError:forKey:)]) {
81
+ NSString *failedKey = (naturalSizeStatus != AVKeyValueStatusLoaded) ? @"naturalSize" : @"preferredTransform";
82
+ [self.delegate assetLoader:self didFailWithError:error forKey:failedKey];
83
+ }
84
+ }
85
+ }
86
+
87
+ @end
@@ -0,0 +1,9 @@
1
+ // ErrorCode.h
2
+ typedef NS_ENUM(NSInteger, ErrorCode) {
3
+ ErrorCodeTrimmingFailed,
4
+ ErrorCodeFailToLoadMedia,
5
+ ErrorCodeFailToSaveToPhoto,
6
+ ErrorCodeFailToShare,
7
+ ErrorCodeNoPhotoPermission,
8
+ ErrorCodeInvalidFilePath
9
+ };
@@ -0,0 +1,15 @@
1
+ #import <UIKit/UIKit.h>
2
+
3
+ @interface ProgressAlertController : UIViewController
4
+
5
+ @property (nonatomic, copy) void (^onDismiss)(void);
6
+ @property (nonatomic, strong) UILabel *titleLabel;
7
+ @property (nonatomic, strong) UIProgressView *progressBar;
8
+ @property (nonatomic, strong) UIButton *actionButton;
9
+
10
+ - (void)setTitle:(NSString *)title;
11
+ - (void)setCancelTitle:(NSString *)title;
12
+ - (void)setProgress:(float)progress;
13
+ - (void)showCancelBtn;
14
+
15
+ @end
@@ -0,0 +1,78 @@
1
+ #import "ProgressAlertController.h"
2
+
3
+ @implementation ProgressAlertController
4
+
5
+ - (void)viewDidLoad {
6
+ [super viewDidLoad];
7
+ [self setupBackground];
8
+ [self setupAlertView];
9
+ }
10
+
11
+ - (void)setupBackground {
12
+ self.view.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.4];
13
+ }
14
+
15
+ - (void)setupAlertView {
16
+ UIView *alertView = [[UIView alloc] init];
17
+ alertView.backgroundColor = [UIColor colorWithRed:28/255.0 green:28/255.0 blue:30/255.0 alpha:1.0];
18
+ alertView.layer.cornerRadius = 12;
19
+ alertView.translatesAutoresizingMaskIntoConstraints = NO;
20
+ [self.view addSubview:alertView];
21
+ [NSLayoutConstraint activateConstraints:@[
22
+ [alertView.centerXAnchor constraintEqualToAnchor:self.view.centerXAnchor],
23
+ [alertView.centerYAnchor constraintEqualToAnchor:self.view.centerYAnchor],
24
+ [alertView.widthAnchor constraintEqualToConstant:270]
25
+ ]];
26
+ self.titleLabel = [[UILabel alloc] init];
27
+ self.titleLabel.translatesAutoresizingMaskIntoConstraints = NO;
28
+ self.titleLabel.textAlignment = NSTextAlignmentCenter;
29
+ self.titleLabel.font = [UIFont systemFontOfSize:18];
30
+ self.titleLabel.numberOfLines = 0;
31
+ self.titleLabel.textColor = [UIColor whiteColor];
32
+ [alertView addSubview:self.titleLabel];
33
+ self.progressBar = [[UIProgressView alloc] initWithProgressViewStyle:UIProgressViewStyleDefault];
34
+ self.progressBar.translatesAutoresizingMaskIntoConstraints = NO;
35
+ [alertView addSubview:self.progressBar];
36
+ self.actionButton = [UIButton buttonWithType:UIButtonTypeSystem];
37
+ [self.actionButton setTitle:@"Cancel" forState:UIControlStateNormal];
38
+ [self.actionButton setTitleColor:[UIColor systemPinkColor] forState:UIControlStateNormal];
39
+ self.actionButton.titleLabel.font = [UIFont systemFontOfSize:16];
40
+ [self.actionButton addTarget:self action:@selector(dismissAlert) forControlEvents:UIControlEventTouchUpInside];
41
+ self.actionButton.translatesAutoresizingMaskIntoConstraints = NO;
42
+ self.actionButton.hidden = YES;
43
+ [alertView addSubview:self.actionButton];
44
+ [NSLayoutConstraint activateConstraints:@[
45
+ [self.titleLabel.topAnchor constraintEqualToAnchor:alertView.topAnchor constant:16],
46
+ [self.titleLabel.leadingAnchor constraintEqualToAnchor:alertView.leadingAnchor constant:16],
47
+ [self.titleLabel.trailingAnchor constraintEqualToAnchor:alertView.trailingAnchor constant:-16],
48
+ [self.progressBar.topAnchor constraintEqualToAnchor:self.titleLabel.bottomAnchor constant:16],
49
+ [self.progressBar.leadingAnchor constraintEqualToAnchor:alertView.leadingAnchor constant:16],
50
+ [self.progressBar.trailingAnchor constraintEqualToAnchor:alertView.trailingAnchor constant:-16],
51
+ [self.actionButton.topAnchor constraintEqualToAnchor:self.progressBar.bottomAnchor constant:16],
52
+ [self.actionButton.bottomAnchor constraintEqualToAnchor:alertView.bottomAnchor constant:-16],
53
+ [self.actionButton.centerXAnchor constraintEqualToAnchor:alertView.centerXAnchor]
54
+ ]];
55
+ }
56
+
57
+ - (void)dismissAlert {
58
+ if (self.onDismiss) self.onDismiss();
59
+ }
60
+
61
+ - (void)setTitle:(NSString *)text {
62
+ self.titleLabel.text = text;
63
+ }
64
+
65
+ - (void)setCancelTitle:(NSString *)text {
66
+ [self.actionButton setTitle:text forState:UIControlStateNormal];
67
+ }
68
+
69
+ - (void)setProgress:(float)progress {
70
+ [self.progressBar setProgress:progress animated:YES];
71
+ }
72
+
73
+ - (void)showCancelBtn {
74
+ [self.view layoutIfNeeded];
75
+ self.actionButton.hidden = NO;
76
+ }
77
+
78
+ @end
@@ -0,0 +1,31 @@
1
+ #import <VideoTrimSpec/VideoTrimSpec.h>
2
+ #import <AVFoundation/AVFoundation.h>
3
+ #import <UIKit/UIKit.h>
4
+ #import "AssetLoader.h"
5
+
6
+ @class VideoTrimmerViewController;
7
+ @class ProgressAlertController;
8
+
9
+ @interface VideoTrim : NativeVideoTrimSpecBase <NativeVideoTrimSpec, AssetLoaderDelegate, UIDocumentPickerDelegate>
10
+
11
+ @property (nonatomic, strong) NSString *FILE_PREFIX;
12
+ @property (nonatomic, strong) NSString *BEFORE_TRIM_PREFIX;
13
+ @property (nonatomic, assign) BOOL isShowing;
14
+ @property (nonatomic, strong) VideoTrimmerViewController *vc;
15
+ @property (nonatomic, strong) NSURL *outputFile;
16
+ @property (nonatomic, assign) BOOL isVideoType;
17
+ //@property (nonatomic, assign) JS::NativeVideoTrim::EditorConfig editorConfig;
18
+
19
+ // Helper methods
20
+ - (NSURL *)renameFileAtURL:(NSURL *)url newName:(NSString *)newName;
21
+ - (void)trimWithViewController:(VideoTrimmerViewController *)viewController
22
+ inputFile:(NSURL *)inputFile
23
+ videoDuration:(double)videoDuration
24
+ startTime:(double)startTime
25
+ endTime:(double)endTime;
26
+ - (void)saveFileToFilesApp:(NSURL *)fileURL;
27
+ - (void)shareFile:(NSURL *)fileURL;
28
+ - (int)deleteFileAtURL:(NSURL *)url;
29
+ - (void)onError:(NSString *)message code:(NSString *)code;
30
+
31
+ @end