react-native-video-trim 2.0.0 → 2.1.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.
Files changed (30) hide show
  1. package/README.md +33 -9
  2. package/android/src/main/AndroidManifest.xml +13 -0
  3. package/android/src/main/java/com/videotrim/VideoTrimModule.java +185 -64
  4. package/android/src/main/java/com/videotrim/enums/ErrorCode.java +11 -0
  5. package/android/src/main/java/com/videotrim/interfaces/VideoTrimListener.java +2 -1
  6. package/android/src/main/java/com/videotrim/utils/MediaMetadataUtil.java +75 -0
  7. package/android/src/main/java/com/videotrim/utils/StorageUtil.java +2 -2
  8. package/android/src/main/java/com/videotrim/utils/VideoTrimmerUtil.java +15 -8
  9. package/android/src/main/java/com/videotrim/widgets/VideoTrimmerView.java +239 -70
  10. package/android/src/main/res/drawable/airpodsmax.xml +19 -0
  11. package/android/src/main/res/drawable/exclamationmark_triangle_fill.xml +15 -0
  12. package/android/src/main/res/drawable/thumb_container_bg.xml +8 -0
  13. package/android/src/main/res/layout/video_trimmer_view.xml +51 -4
  14. package/android/src/main/res/xml/file_paths.xml +5 -0
  15. package/ios/AssetLoader.swift +99 -0
  16. package/ios/ErrorCode.swift +16 -0
  17. package/ios/VideoTrim.mm +4 -2
  18. package/ios/VideoTrim.swift +380 -167
  19. package/ios/VideoTrimmer.swift +16 -10
  20. package/ios/VideoTrimmerViewController.swift +78 -12
  21. package/lib/commonjs/index.js +20 -57
  22. package/lib/commonjs/index.js.map +1 -1
  23. package/lib/module/index.js +19 -57
  24. package/lib/module/index.js.map +1 -1
  25. package/lib/typescript/index.d.ts +47 -9
  26. package/lib/typescript/index.d.ts.map +1 -1
  27. package/package.json +1 -1
  28. package/src/index.tsx +56 -66
  29. package/android/src/main/java/iknow/android/utils/BuildConfig.java +0 -18
  30. package/android/src/main/java/iknow/android/utils/DateUtil.java +0 -64
@@ -14,7 +14,28 @@
14
14
  <VideoView
15
15
  android:id="@+id/video_loader"
16
16
  android:layout_width="match_parent"
17
- android:layout_height="match_parent" />
17
+ android:layout_height="match_parent"
18
+ />
19
+
20
+ <FrameLayout
21
+ android:id="@+id/audioBannerView"
22
+ android:layout_width="match_parent"
23
+ android:layout_height="match_parent"
24
+ android:layout_marginStart="50dp"
25
+ android:layout_marginTop="50dp"
26
+ android:layout_marginEnd="50dp"
27
+ android:layout_marginBottom="50dp"
28
+ android:padding="50dp"
29
+ android:visibility="gone">
30
+
31
+ <ImageView
32
+ android:layout_width="match_parent"
33
+ android:layout_height="match_parent"
34
+ android:layout_gravity="center"
35
+ android:contentDescription="Airpods Max"
36
+ android:src="@drawable/airpodsmax"
37
+ />
38
+ </FrameLayout>
18
39
 
19
40
  </RelativeLayout>
20
41
 
@@ -38,7 +59,8 @@
38
59
  android:layout_height="match_parent"
39
60
  android:layout_marginHorizontal="20dp"
40
61
  android:orientation="horizontal"
41
- android:padding="4dp" />
62
+ android:padding="4dp"
63
+ />
42
64
 
43
65
  <RelativeLayout
44
66
  android:id="@+id/trimmerContainerWrapper"
@@ -201,7 +223,30 @@
201
223
  android:layout_gravity="center"
202
224
  android:padding="12dp"
203
225
  android:src="@drawable/play_fill"
204
- android:tint="@color/white"/>
226
+ android:tint="@color/white"
227
+ android:visibility="gone"
228
+ />
229
+
230
+ <ImageView
231
+ android:id="@+id/failToLoadBtn"
232
+ android:layout_width="wrap_content"
233
+ android:layout_height="match_parent"
234
+ android:layout_gravity="center"
235
+ android:padding="12dp"
236
+ android:src="@drawable/exclamationmark_triangle_fill"
237
+ android:tint="@color/trim_color"
238
+ android:visibility="gone"
239
+ />
240
+
241
+ <ProgressBar
242
+ android:id="@+id/loadingIndicator"
243
+ style="?android:attr/progressBarStyle"
244
+ android:layout_width="wrap_content"
245
+ android:layout_height="wrap_content"
246
+ android:layout_gravity="center"
247
+ android:padding="10dp"
248
+ android:indeterminateTint="@color/white"
249
+ />
205
250
 
206
251
  <TextView
207
252
  android:id="@+id/saveBtn"
@@ -212,7 +257,9 @@
212
257
  android:padding="10dp"
213
258
  android:text="@string/save"
214
259
  android:textColor="#2196F3"
215
- android:textSize="16dp" />
260
+ android:textSize="16dp"
261
+ android:visibility="gone"
262
+ />
216
263
 
217
264
  </FrameLayout>
218
265
 
@@ -0,0 +1,5 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <paths xmlns:android="http://schemas.android.com/apk/res/android">
3
+ <files-path name="internal_files" path="." />
4
+ <external-path name="external_files" path="." />
5
+ </paths>
@@ -0,0 +1,99 @@
1
+ //
2
+ // AssetLoader.swift
3
+ // react-native-video-trim
4
+ //
5
+ // Created by ByteDance on 7/27/24.
6
+ //
7
+
8
+ import AVFoundation
9
+
10
+ protocol AssetLoaderDelegate: AnyObject {
11
+ func assetLoader(_ loader: AssetLoader, didFailWithError error: Error, forKey key: String)
12
+ func assetLoaderDidSucceed(_ loader: AssetLoader)
13
+ }
14
+
15
+ class AssetLoader: NSObject {
16
+ var asset: AVURLAsset?
17
+ weak var delegate: AssetLoaderDelegate?
18
+
19
+ func loadAsset(url: URL, isVideoType: Bool) {
20
+ // Creating AVURLAsset (not blocking the main thread)
21
+ asset = AVURLAsset(url: url, options: [AVURLAssetPreferPreciseDurationAndTimingKey: true])
22
+ let keys = ["duration", "tracks"]
23
+
24
+ // Asynchronous property loading
25
+ asset?.loadValuesAsynchronously(forKeys: keys) {
26
+ DispatchQueue.main.async {
27
+ self.assetLoaded(isVideoType: isVideoType)
28
+ }
29
+ }
30
+ }
31
+
32
+ private func assetLoaded(isVideoType: Bool) {
33
+ guard let asset = asset else { return }
34
+
35
+ let keys = ["duration", "tracks"]
36
+ for key in keys {
37
+ var error: NSError?
38
+ let status = asset.statusOfValue(forKey: key, error: &error)
39
+
40
+ if status == .failed {
41
+ if let error = error {
42
+ delegate?.assetLoader(self, didFailWithError: error, forKey: key)
43
+ }
44
+ return
45
+ } else if status == .cancelled {
46
+ delegate?.assetLoader(self, didFailWithError: NSError(domain: "AssetLoader", code: -1, userInfo: [NSLocalizedDescriptionKey: "\(key) loading was cancelled"]), forKey: key)
47
+ return
48
+ } else if status != .loaded {
49
+ delegate?.assetLoader(self, didFailWithError: NSError(domain: "AssetLoader", code: -1, userInfo: [NSLocalizedDescriptionKey: "\(key) is in an unknown state"]), forKey: key)
50
+ return
51
+ }
52
+ }
53
+
54
+ if isVideoType {
55
+ // Process the tracks to load the remaining properties
56
+ self.processAssetTracks()
57
+ } else {
58
+ delegate?.assetLoaderDidSucceed(self)
59
+ }
60
+ }
61
+
62
+ private func processAssetTracks() {
63
+ guard let asset = asset else { return }
64
+
65
+ let videoTracks = asset.tracks(withMediaType: .video)
66
+ guard let videoTrack = videoTracks.first else {
67
+ delegate?.assetLoader(self, didFailWithError: NSError(domain: "AssetLoader", code: -1, userInfo: [NSLocalizedDescriptionKey: "No video tracks found"]), forKey: "tracks")
68
+ return
69
+ }
70
+
71
+ let trackKeys = ["naturalSize", "preferredTransform"]
72
+ videoTrack.loadValuesAsynchronously(forKeys: trackKeys) {
73
+ DispatchQueue.main.async {
74
+ self.trackPropertiesLoaded(track: videoTrack)
75
+ }
76
+ }
77
+ }
78
+
79
+ private func trackPropertiesLoaded(track: AVAssetTrack) {
80
+ var error: NSError?
81
+
82
+ let naturalSizeStatus = track.statusOfValue(forKey: "naturalSize", error: &error)
83
+ let preferredTransformStatus = track.statusOfValue(forKey: "preferredTransform", error: &error)
84
+
85
+ if naturalSizeStatus == .loaded, preferredTransformStatus == .loaded {
86
+ let naturalSize = track.naturalSize
87
+ let preferredTransform = track.preferredTransform
88
+
89
+ print("Natural size: \(naturalSize)")
90
+ print("Preferred transform: \(preferredTransform)")
91
+ delegate?.assetLoaderDidSucceed(self)
92
+ } else {
93
+ if let error = error {
94
+ let failedKey = naturalSizeStatus != .loaded ? "naturalSize" : "preferredTransform"
95
+ delegate?.assetLoader(self, didFailWithError: error, forKey: failedKey)
96
+ }
97
+ }
98
+ }
99
+ }
@@ -0,0 +1,16 @@
1
+ //
2
+ // ErrorCode.swift
3
+ // react-native-video-trim
4
+ //
5
+ // Created by ByteDance on 7/27/24.
6
+ //
7
+
8
+ import Foundation
9
+
10
+ enum ErrorCode: String {
11
+ case trimmingFailed = "TRIMMING_FAILED"
12
+ case failToLoadVideo = "FAIL_TO_LOAD_VIDEO"
13
+ case failToSaveToPhoto = "FAIL_TO_SAVE_TO_PHOTO"
14
+ case failToShare = "FAIL_TO_SHARE"
15
+ case noPhotoPermission = "NO_PHOTO_PERMISSION"
16
+ }
package/ios/VideoTrim.mm CHANGED
@@ -4,12 +4,14 @@
4
4
  @interface RCT_EXTERN_MODULE(VideoTrim, RCTEventEmitter)
5
5
 
6
6
  RCT_EXTERN_METHOD(showEditor:(NSString*)uri withConfig:(NSDictionary *)config)
7
- RCT_EXTERN_METHOD(isValidVideo:(NSString*)uri withResolver:(RCTPromiseResolveBlock)resolve
8
- withRejecter:(RCTPromiseRejectBlock)reject)
9
7
  RCT_EXTERN_METHOD(listFiles:(RCTPromiseResolveBlock)resolve
10
8
  withRejecter:(RCTPromiseRejectBlock)reject)
11
9
  RCT_EXTERN_METHOD(cleanFiles:(RCTPromiseResolveBlock)resolve
12
10
  withRejecter:(RCTPromiseRejectBlock)reject)
13
11
  RCT_EXTERN_METHOD(deleteFile:(NSString*)uri withResolver:(RCTPromiseResolveBlock)resolve
14
12
  withRejecter:(RCTPromiseRejectBlock)reject)
13
+ RCT_EXTERN_METHOD(closeEditor:(RCTPromiseResolveBlock)resolve
14
+ withRejecter:(RCTPromiseRejectBlock)reject)
15
+ RCT_EXTERN_METHOD(isValidFile:(NSString*)uri withResolver:(RCTPromiseResolveBlock)resolve
16
+ withRejecter:(RCTPromiseRejectBlock)reject)
15
17
  @end