react-native-video-trim 5.1.1 → 6.0.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/README.md CHANGED
@@ -1,6 +1,7 @@
1
1
  # Table of contents
2
2
  - [Installation](#installation)
3
3
  * [For iOS (React Native CLI project)](#for-ios-react-native-cli-project)
4
+ * [For Android New Arch (React Native CLI project)](#for-android-new-arch-react-native-cli-project)
4
5
  * [For Expo project](#for-expo-project)
5
6
  * [Usage](#usage)
6
7
  - [Methods](#methods)
@@ -11,10 +12,7 @@
11
12
  * [listFiles()](#listfiles)
12
13
  * [cleanFiles()](#cleanfiles)
13
14
  * [deleteFile()](#deletefile)
14
- - [Callbacks (New arch)](#callbacks-new-arch)
15
- * [showEditor](#showeditor)
16
- * [closeEditor](#closeeditor-1)
17
- - [Audio support](#audio-support)
15
+ - [Audio only support](#audio-only-support)
18
16
  - [Cancel trimming](#cancel-trimming)
19
17
  - [Fail to load media](#fail-to-load-media)
20
18
  - [Rotation](#rotation)
@@ -45,27 +43,26 @@
45
43
 
46
44
  # Installation
47
45
 
46
+ Both new + old arch are supported in a single distribution
47
+
48
48
  ```sh
49
- # new arch
50
49
  npm install react-native-video-trim
51
50
 
52
- # old arch
53
- npm install react-native-video-trim@^3.0.0
54
-
55
51
  # or with yarn
56
-
57
- # new arch
58
52
  yarn add react-native-video-trim
59
53
 
60
- # old arch
61
- yarn add react-native-video-trim@^3.0.0
62
54
  ```
63
55
 
64
- ## For iOS (React Native CLI project)
56
+ ## iOS (RN CLI project)
65
57
  Run the following command to setup for iOS:
66
58
  ```
67
59
  npx pod-install ios
68
60
  ```
61
+ ## Android New Arch (RN CLI project)
62
+ If you are using New Arch, in `android` folder run:
63
+ ```
64
+ ./gradlew generateCodegenArtifactsFromSchema
65
+ ```
69
66
  ## For Expo project
70
67
  You need to run `prebuild` in order for native code takes effect:
71
68
  ```
@@ -75,7 +72,7 @@ Then you should to restart to make the changes take effect
75
72
 
76
73
  Note that on iOS, Expo Go may not work because of library linking, you may see this error:
77
74
 
78
- <img src="images/expo_error.PNG" width="300" />
75
+ <img src="images/expo_error.PNG" width="150" />
79
76
 
80
77
  To avoid the error, you should open `ios/yourproject.xcworkspace` then manually build and run your app
81
78
 
@@ -94,7 +91,10 @@ showEditor(videoUrl, {
94
91
  maxDuration: 20,
95
92
  });
96
93
  ```
97
- Usually this library will be used along with other library to select video file, Eg. [react-native-image-picker](https://github.com/react-native-image-picker/react-native-image-picker). Below is real world example:
94
+ Usually this library will be used along with other library to select video file, Eg. [react-native-image-picker](https://github.com/react-native-image-picker/react-native-image-picker). Below are real world examples:
95
+
96
+ <details>
97
+ <summary>New Arch usage</summary>
98
98
 
99
99
  ```jsx
100
100
  import * as React from 'react';
@@ -104,51 +104,49 @@ import {
104
104
  View,
105
105
  Text,
106
106
  TouchableOpacity,
107
- NativeEventEmitter,
108
- NativeModules,
109
107
  type EventSubscription,
110
108
  } from 'react-native';
111
- import { isValidFile, showEditor } from 'react-native-video-trim';
109
+ import { isValidFile, showEditor, type Spec } from 'react-native-video-trim';
112
110
  import { launchImageLibrary } from 'react-native-image-picker';
113
111
 
114
112
  export default function App() {
115
113
  const listenerSubscription = useRef<Record<string, EventSubscription>>({});
116
114
 
117
115
  useEffect(() => {
118
- listenerSubscription.current.onLoad = NativeVideoTrim.onLoad(
116
+ listenerSubscription.current.onLoad = (NativeVideoTrim as Spec).onLoad(
119
117
  ({ duration }) => console.log('onLoad', duration)
120
118
  );
121
119
 
122
120
  listenerSubscription.current.onStartTrimming =
123
- NativeVideoTrim.onStartTrimming(() => console.log('onStartTrimming'));
121
+ (NativeVideoTrim as Spec).onStartTrimming(() => console.log('onStartTrimming'));
124
122
 
125
123
  listenerSubscription.current.onCancelTrimming =
126
- NativeVideoTrim.onCancelTrimming(() => console.log('onCancelTrimming'));
127
- listenerSubscription.current.onCancel = NativeVideoTrim.onCancel(() =>
124
+ (NativeVideoTrim as Spec).onCancelTrimming(() => console.log('onCancelTrimming'));
125
+ listenerSubscription.current.onCancel = (NativeVideoTrim as Spec).onCancel(() =>
128
126
  console.log('onCancel')
129
127
  );
130
- listenerSubscription.current.onHide = NativeVideoTrim.onHide(() =>
128
+ listenerSubscription.current.onHide = (NativeVideoTrim as Spec).onHide(() =>
131
129
  console.log('onHide')
132
130
  );
133
- listenerSubscription.current.onShow = NativeVideoTrim.onShow(() =>
131
+ listenerSubscription.current.onShow = (NativeVideoTrim as Spec).onShow(() =>
134
132
  console.log('onShow')
135
133
  );
136
134
  listenerSubscription.current.onFinishTrimming =
137
- NativeVideoTrim.onFinishTrimming(
135
+ (NativeVideoTrim as Spec).onFinishTrimming(
138
136
  ({ outputPath, startTime, endTime, duration }) =>
139
137
  console.log(
140
138
  'onFinishTrimming',
141
139
  `outputPath: ${outputPath}, startTime: ${startTime}, endTime: ${endTime}, duration: ${duration}`
142
140
  )
143
141
  );
144
- listenerSubscription.current.onLog = NativeVideoTrim.onLog(
142
+ listenerSubscription.current.onLog = (NativeVideoTrim as Spec).onLog(
145
143
  ({ level, message, sessionId }) =>
146
144
  console.log(
147
145
  'onLog',
148
146
  `level: ${level}, message: ${message}, sessionId: ${sessionId}`
149
147
  )
150
148
  );
151
- listenerSubscription.current.onStatistics = NativeVideoTrim.onStatistics(
149
+ listenerSubscription.current.onStatistics = (NativeVideoTrim as Spec).onStatistics(
152
150
  ({
153
151
  sessionId,
154
152
  videoFrameNumber,
@@ -164,7 +162,7 @@ export default function App() {
164
162
  `sessionId: ${sessionId}, videoFrameNumber: ${videoFrameNumber}, videoFps: ${videoFps}, videoQuality: ${videoQuality}, size: ${size}, time: ${time}, bitrate: ${bitrate}, speed: ${speed}`
165
163
  )
166
164
  );
167
- listenerSubscription.current.onError = NativeVideoTrim.onError(
165
+ listenerSubscription.current.onError = (NativeVideoTrim as Spec).onError(
168
166
  ({ message, errorCode }) =>
169
167
  console.log('onError', `message: ${message}, errorCode: ${errorCode}`)
170
168
  );
@@ -229,6 +227,130 @@ const styles = StyleSheet.create({
229
227
  },
230
228
  });
231
229
  ```
230
+ </details>
231
+
232
+ <br />
233
+
234
+ <details>
235
+ <summary>Old Arch usage</summary>
236
+
237
+ ```jsx
238
+ import * as React from 'react';
239
+
240
+ import {
241
+ StyleSheet,
242
+ View,
243
+ Text,
244
+ TouchableOpacity,
245
+ NativeEventEmitter,
246
+ NativeModules,
247
+ } from 'react-native';
248
+ import { isValidFile, showEditor } from 'react-native-video-trim';
249
+ import { launchImageLibrary } from 'react-native-image-picker';
250
+
251
+ export default function App() {
252
+ useEffect(() => {
253
+ const eventEmitter = new NativeEventEmitter(NativeModules.VideoTrim);
254
+ const subscription = eventEmitter.addListener('VideoTrim', (event) => {
255
+ switch (event.name) {
256
+ case 'onLoad': {
257
+ console.log('onLoadListener', event);
258
+ break;
259
+ }
260
+ case 'onShow': {
261
+ console.log('onShowListener', event);
262
+ break;
263
+ }
264
+ case 'onHide': {
265
+ console.log('onHide', event);
266
+ break;
267
+ }
268
+ case 'onStartTrimming': {
269
+ console.log('onStartTrimming', event);
270
+ break;
271
+ }
272
+ case 'onFinishTrimming': {
273
+ console.log('onFinishTrimming', event);
274
+ break;
275
+ }
276
+ case 'onCancelTrimming': {
277
+ console.log('onCancelTrimming', event);
278
+ break;
279
+ }
280
+ case 'onCancel': {
281
+ console.log('onCancel', event);
282
+ break;
283
+ }
284
+ case 'onError': {
285
+ console.log('onError', event);
286
+ break;
287
+ }
288
+ case 'onLog': {
289
+ console.log('onLog', event);
290
+ break;
291
+ }
292
+ case 'onStatistics': {
293
+ console.log('onStatistics', event);
294
+ break;
295
+ }
296
+ }
297
+ });
298
+
299
+ return () => {
300
+ subscription.remove();
301
+ };
302
+ }, []);
303
+
304
+ return (
305
+ <View style={styles.container}>
306
+ <TouchableOpacity
307
+ onPress={async () => {
308
+ const result = await launchImageLibrary({
309
+ mediaType: 'video',
310
+ assetRepresentationMode: 'current',
311
+ });
312
+
313
+ isValidFile(result.assets![0]?.uri || '').then((res) =>
314
+ console.log(res)
315
+ );
316
+
317
+ showEditor(result.assets![0]?.uri || '', {
318
+ maxDuration: 20,
319
+ });
320
+ }}
321
+ style={{ padding: 10, backgroundColor: 'red' }}
322
+ >
323
+ <Text>Launch Library</Text>
324
+ </TouchableOpacity>
325
+ <TouchableOpacity
326
+ onPress={() => {
327
+ isValidFile('invalid file path').then((res) => console.log(res));
328
+ }}
329
+ style={{
330
+ padding: 10,
331
+ backgroundColor: 'blue',
332
+ marginTop: 20,
333
+ }}
334
+ >
335
+ <Text>Check Video Valid</Text>
336
+ </TouchableOpacity>
337
+ </View>
338
+ );
339
+ }
340
+
341
+ const styles = StyleSheet.create({
342
+ container: {
343
+ flex: 1,
344
+ alignItems: 'center',
345
+ justifyContent: 'center',
346
+ },
347
+ });
348
+ ```
349
+ </details>
350
+
351
+ <br />
352
+
353
+ Checkout [Example folder](./example/src/) for more details
232
354
 
233
355
  # Methods
234
356
 
@@ -286,7 +408,7 @@ Main method to show Video Editor UI.
286
408
  - `alertOnFailCloseText` (`default = "Close"`)
287
409
  - `enableRotation` (`default = false`)
288
410
  - `rotationAngle` (`default = 0`)
289
- - `changeStatusBarColorOnOpen` (`default = false`): Update status bar color to black background color when editor is opened (useful in somecases where your theme has titlebar in different color than black)
411
+ - `changeStatusBarColorOnOpen` (`default = false`): (Android only) Update status bar color to black background color when editor is opened (useful in somecases where your theme has titlebar in different color than black)
290
412
 
291
413
  If `saveToPhoto = true`, you must ensure that you have request permission to write to photo/gallery
292
414
  - For Android: you need to have `<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />` in AndroidManifest.xml
@@ -338,21 +460,7 @@ Clean all generated output files in app storage. Return number of successfully d
338
460
  ## deleteFile()
339
461
  Delete a file in app storage. Return `true` if success
340
462
 
341
- # Callbacks (New arch)
342
-
343
- ## showEditor
344
-
345
- ```ts
346
- showEditor('file', config)
347
- ```
348
-
349
- ## closeEditor
350
-
351
- ```ts
352
- closeEditor()
353
- ```
354
-
355
- # Audio support
463
+ # Audio only support
356
464
  <div align="left">
357
465
  <img src="images/audio_android.jpg" width="200" />
358
466
  <img src="images/audio_ios.jpg" width="200" />
@@ -19,7 +19,9 @@ buildscript {
19
19
  apply plugin: "com.android.library"
20
20
  apply plugin: "kotlin-android"
21
21
 
22
- apply plugin: "com.facebook.react"
22
+ if (isNewArchitectureEnabled()) {
23
+ apply plugin: "com.facebook.react"
24
+ }
23
25
 
24
26
  def getExtOrIntegerDefault(name) {
25
27
  return rootProject.ext.has(name) ? rootProject.ext.get(name) : (project.properties["VideoTrim_" + name]).toInteger()
@@ -33,6 +35,10 @@ def getPackageVersionOrDefault() {
33
35
  return rootProject.ext.has("VideoTrim_ffmpeg_version") ? rootProject.ext.get("VideoTrim_ffmpeg_version") : project.properties["VideoTrim_ffmpeg_version"]
34
36
  }
35
37
 
38
+ def isNewArchitectureEnabled() {
39
+ return rootProject.hasProperty("newArchEnabled") && rootProject.getProperty("newArchEnabled") == "true"
40
+ }
41
+
36
42
  android {
37
43
  namespace "com.videotrim"
38
44
 
@@ -41,6 +47,7 @@ android {
41
47
  defaultConfig {
42
48
  minSdkVersion getExtOrIntegerDefault("minSdkVersion")
43
49
  targetSdkVersion getExtOrIntegerDefault("targetSdkVersion")
50
+ buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString()
44
51
  }
45
52
 
46
53
  buildFeatures {
@@ -64,10 +71,16 @@ android {
64
71
 
65
72
  sourceSets {
66
73
  main {
67
- java.srcDirs += [
68
- "generated/java",
69
- "generated/jni"
70
- ]
74
+ if (isNewArchitectureEnabled()) {
75
+ java.srcDirs += [
76
+ "src/newarch",
77
+ // Codegen specs
78
+ "generated/java",
79
+ "generated/jni"
80
+ ]
81
+ } else {
82
+ java.srcDirs += "src/oldarch"
83
+ }
71
84
  }
72
85
  }
73
86
  }
@@ -85,8 +98,10 @@ dependencies {
85
98
  implementation 'io.github.maitrungduc1410:ffmpeg-kit-' + getPackageNameOrDefault() +':' + getPackageVersionOrDefault()
86
99
  }
87
100
 
88
- react {
89
- jsRootDir = file("../src/")
90
- libraryName = "VideoTrim"
91
- codegenJavaPackageName = "com.videotrim"
101
+ if (isNewArchitectureEnabled()) {
102
+ react {
103
+ jsRootDir = file("../src/")
104
+ libraryName = "VideoTrim"
105
+ codegenJavaPackageName = "com.videotrim"
106
+ }
92
107
  }
@@ -17,7 +17,6 @@ import android.util.TypedValue
17
17
  import android.view.Gravity
18
18
  import android.view.View
19
19
  import android.view.ViewGroup
20
- import android.view.Window
21
20
  import android.view.WindowManager
22
21
  import android.widget.Button
23
22
  import android.widget.LinearLayout
@@ -32,8 +31,14 @@ import androidx.core.view.ViewCompat
32
31
  import androidx.core.view.WindowInsetsCompat
33
32
  import com.arthenica.ffmpegkit.FFmpegKit
34
33
  import com.arthenica.ffmpegkit.ReturnCode
35
- import com.facebook.react.bridge.*
36
- import com.facebook.react.module.annotations.ReactModule
34
+ import com.facebook.react.bridge.Arguments
35
+ import com.facebook.react.bridge.BaseActivityEventListener
36
+ import com.facebook.react.bridge.LifecycleEventListener
37
+ import com.facebook.react.bridge.Promise
38
+ import com.facebook.react.bridge.ReactApplicationContext
39
+ import com.facebook.react.bridge.ReadableMap
40
+ import com.facebook.react.bridge.UiThreadUtil
41
+ import com.facebook.react.bridge.WritableMap
37
42
  import com.videotrim.enums.ErrorCode
38
43
  import com.videotrim.interfaces.VideoTrimListener
39
44
  import com.videotrim.utils.MediaMetadataUtil
@@ -47,9 +52,14 @@ import java.text.SimpleDateFormat
47
52
  import java.util.Date
48
53
  import java.util.TimeZone
49
54
 
50
- @ReactModule(name = VideoTrimModule.NAME)
51
- class VideoTrimModule(reactContext: ReactApplicationContext) :
52
- NativeVideoTrimSpec(reactContext), VideoTrimListener, LifecycleEventListener {
55
+ /**
56
+ * Contains all shared business logic between old + new arch.
57
+ * Does NOT know how to emit events.
58
+ */
59
+ open class BaseVideoTrimModule internal constructor(
60
+ private val reactApplicationContext: ReactApplicationContext,
61
+ private val sendEvent: (eventName: String, params: WritableMap?) -> Unit
62
+ ) : VideoTrimListener, LifecycleEventListener {
53
63
 
54
64
  private var isInit: Boolean = false
55
65
  private var trimmerView: VideoTrimmerView? = null
@@ -62,6 +72,8 @@ class VideoTrimModule(reactContext: ReactApplicationContext) :
62
72
  private var editorConfig: ReadableMap? = null
63
73
  private var trimOptions: ReadableMap? = null
64
74
  private var originalStatusBarColor: Int = Color.TRANSPARENT
75
+ private val shouldChangeStatusBarColorOnOpen: Boolean
76
+ get() = editorConfig?.hasKey("changeStatusBarColorOnOpen") == true && editorConfig?.getBoolean("changeStatusBarColorOnOpen") == true
65
77
 
66
78
  init {
67
79
  val mActivityEventListener = object : BaseActivityEventListener() {
@@ -114,7 +126,8 @@ class VideoTrimModule(reactContext: ReactApplicationContext) :
114
126
  reactApplicationContext.addActivityEventListener(mActivityEventListener)
115
127
  }
116
128
 
117
- override fun showEditor(
129
+
130
+ fun showEditor(
118
131
  filePath: String,
119
132
  config: ReadableMap,
120
133
  ) {
@@ -149,7 +162,7 @@ class VideoTrimModule(reactContext: ReactApplicationContext) :
149
162
  alertDialog?.setOnShowListener {
150
163
  applySafeAreaToDialog(alertDialog!!, trimmerView!!)
151
164
 
152
- emitOnShow()
165
+ sendEvent("onShow", null)
153
166
  }
154
167
 
155
168
  // this is to ensure to release resource if dialog is dismissed in unexpected way (Eg. open control/notification center by dragging from top of screen)
@@ -160,7 +173,7 @@ class VideoTrimModule(reactContext: ReactApplicationContext) :
160
173
  trimmerView = null
161
174
  }
162
175
  hideDialog(true)
163
- emitOnHide()
176
+ sendEvent("onHide", null)
164
177
  }
165
178
 
166
179
  alertDialog?.show()
@@ -196,8 +209,8 @@ class VideoTrimModule(reactContext: ReactApplicationContext) :
196
209
 
197
210
  // 2. restore flags to their previous state
198
211
  // For most cases, just setting the color is enough.
199
- it.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
200
- it.clearFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS)
212
+ it.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
213
+ it.clearFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS)
201
214
  }
202
215
  }
203
216
 
@@ -249,15 +262,15 @@ class VideoTrimModule(reactContext: ReactApplicationContext) :
249
262
  hideDialog(true)
250
263
  }
251
264
 
252
- override fun invalidate() {
253
- super.invalidate()
254
- hideDialog(true)
255
- }
265
+ // override fun invalidate() {
266
+ // super.invalidate()
267
+ // hideDialog(true)
268
+ // }
256
269
 
257
270
  override fun onLoad(duration: Int) {
258
271
  val map = Arguments.createMap()
259
272
  map.putInt("duration", duration)
260
- emitOnLoad(map)
273
+ sendEvent("onLoad", map)
261
274
  }
262
275
 
263
276
  override fun onTrimmingProgress(percentage: Int) {
@@ -279,7 +292,7 @@ class VideoTrimModule(reactContext: ReactApplicationContext) :
279
292
  map.putInt("duration", duration)
280
293
  map.putDouble("startTime", startTime.toDouble())
281
294
  map.putDouble("endTime", endTime.toDouble())
282
- emitOnFinishTrimming(map)
295
+ sendEvent("onFinishTrimming", map)
283
296
 
284
297
  if (editorConfig?.getBoolean("saveToPhoto") == true && isVideoType) {
285
298
  try {
@@ -311,19 +324,19 @@ class VideoTrimModule(reactContext: ReactApplicationContext) :
311
324
  }
312
325
 
313
326
  override fun onCancelTrim() {
314
- emitOnCancelTrimming()
327
+ sendEvent("onCancelTrimming", null)
315
328
  }
316
329
 
317
330
  override fun onError(errorMessage: String?, errorCode: ErrorCode) {
318
331
  val map = Arguments.createMap()
319
332
  map.putString("message", errorMessage)
320
333
  map.putString("errorCode", errorCode.name)
321
- emitOnError(map)
334
+ sendEvent("onError", map)
322
335
  }
323
336
 
324
337
  override fun onCancel() {
325
338
  if (!editorConfig?.getBoolean("enableCancelDialog")!!) {
326
- emitOnCancel()
339
+ sendEvent("onCancel", null)
327
340
  hideDialog(true)
328
341
  return
329
342
  }
@@ -334,7 +347,7 @@ class VideoTrimModule(reactContext: ReactApplicationContext) :
334
347
  builder.setCancelable(false)
335
348
  builder.setPositiveButton(editorConfig?.getString("cancelDialogConfirmText")) { dialog: DialogInterface, _: Int ->
336
349
  dialog.cancel()
337
- emitOnCancel()
350
+ sendEvent("onCancel", null)
338
351
  hideDialog(true)
339
352
  }
340
353
  builder.setNegativeButton(
@@ -369,12 +382,12 @@ class VideoTrimModule(reactContext: ReactApplicationContext) :
369
382
  alertDialog.show()
370
383
  }
371
384
 
372
- override fun onLog(log: ReadableMap) {
373
- emitOnLog( log)
385
+ override fun onLog(log: WritableMap) {
386
+ sendEvent("onLog", log)
374
387
  }
375
388
 
376
- override fun onStatistics(statistics: ReadableMap) {
377
- emitOnStatistics(statistics)
389
+ override fun onStatistics(statistics: WritableMap) {
390
+ sendEvent("onStatistics", statistics)
378
391
  }
379
392
 
380
393
  private fun startTrim() {
@@ -478,7 +491,7 @@ class VideoTrimModule(reactContext: ReactApplicationContext) :
478
491
  mProgressDialog = builder.create()
479
492
 
480
493
  mProgressDialog!!.setOnShowListener {
481
- emitOnStartTrimming()
494
+ sendEvent("onStartTrimming", null)
482
495
  if (trimmerView != null) {
483
496
  trimmerView!!.onSaveClicked()
484
497
  }
@@ -516,45 +529,33 @@ class VideoTrimModule(reactContext: ReactApplicationContext) :
516
529
  }
517
530
  }
518
531
 
519
- // private fun sendEvent(
520
- // eventName: String,
521
- // params: Map<String, String>
522
- // ) {
523
- // onEvent?.let { it(eventName, params) }
524
- //
525
- // if (eventName == "onHide" && onComplete != null) {
526
- // onComplete?.let { it() }
527
- // onComplete = null // Clear the callback after invoking it
528
- // }
529
- // }
530
-
531
- override fun listFiles(promise: Promise) {
532
- promise.resolve(StorageUtil.listFiles(reactApplicationContext))
532
+ fun listFiles(promise: Promise) {
533
+ promise.resolve(Arguments.fromArray(StorageUtil.listFiles(reactApplicationContext)))
533
534
  }
534
535
 
535
- override fun cleanFiles(promise: Promise) {
536
- val files = StorageUtil.listFiles(reactApplicationContext)
537
- var successCount = 0
538
- for (file in files) {
539
- val state = StorageUtil.deleteFile(file)
540
- if (state) {
541
- successCount++
542
- }
536
+ fun cleanFiles(promise: Promise) {
537
+ val files = StorageUtil.listFiles(reactApplicationContext)
538
+ var successCount = 0
539
+ for (file in files) {
540
+ val state = StorageUtil.deleteFile(file)
541
+ if (state) {
542
+ successCount++
543
543
  }
544
+ }
544
545
 
545
- promise.resolve(successCount.toDouble())
546
+ promise.resolve(successCount.toDouble())
546
547
  }
547
548
 
548
- override fun deleteFile(filePath: String?, promise: Promise) {
549
- promise.resolve(StorageUtil.deleteFile(filePath))
549
+ fun deleteFile(filePath: String, promise: Promise) {
550
+ promise.resolve(StorageUtil.deleteFile(filePath))
550
551
  }
551
552
 
552
- override fun closeEditor() {
553
+ fun closeEditor() {
553
554
  hideDialog(true)
554
- emitOnHide()
555
+ sendEvent("onHide", null)
555
556
  }
556
557
 
557
- override fun isValidFile(url: String, promise: Promise) {
558
+ fun isValidFile(url: String, promise: Promise) {
558
559
  MediaMetadataUtil.checkFileValidity(url) { isValid: Boolean, fileType: String, duration: Long ->
559
560
  if (isValid) {
560
561
  Log.d(TAG, "Valid $fileType file with duration: $duration milliseconds")
@@ -572,7 +573,7 @@ class VideoTrimModule(reactContext: ReactApplicationContext) :
572
573
  }
573
574
  }
574
575
 
575
- override fun trim(url: String, options: ReadableMap?, promise: Promise) {
576
+ fun trim(url: String, options: ReadableMap?, promise: Promise) {
576
577
  trimOptions = options
577
578
 
578
579
  val currentDate = Date()
@@ -694,9 +695,6 @@ class VideoTrimModule(reactContext: ReactApplicationContext) :
694
695
  reactApplicationContext.currentActivity?.startActivity(Intent.createChooser(shareIntent, "Share file"))
695
696
  }
696
697
 
697
- val shouldChangeStatusBarColorOnOpen: Boolean
698
- get() = editorConfig?.hasKey("changeStatusBarColorOnOpen") == true && editorConfig?.getBoolean("changeStatusBarColorOnOpen") == true
699
-
700
698
  companion object {
701
699
  const val NAME = "VideoTrim"
702
700
  const val TAG = "VideoTrimModule"
@@ -1,6 +1,7 @@
1
1
  package com.videotrim.interfaces;
2
2
 
3
3
  import com.facebook.react.bridge.ReadableMap;
4
+ import com.facebook.react.bridge.WritableMap;
4
5
  import com.videotrim.enums.ErrorCode;
5
6
 
6
7
  import java.util.Map;
@@ -13,6 +14,6 @@ public interface VideoTrimListener {
13
14
  void onError(String errorMessage, ErrorCode errorCode);
14
15
  void onCancel();
15
16
  void onSave();
16
- void onLog(ReadableMap log);
17
- void onStatistics(ReadableMap statistics);
17
+ void onLog(WritableMap log);
18
+ void onStatistics(WritableMap statistics);
18
19
  }
@@ -17,9 +17,7 @@ import com.videotrim.interfaces.VideoTrimListener;
17
17
  import java.text.SimpleDateFormat;
18
18
  import java.util.ArrayList;
19
19
  import java.util.Date;
20
- import java.util.HashMap;
21
20
  import java.util.List;
22
- import java.util.Map;
23
21
  import java.util.TimeZone;
24
22
 
25
23
  import iknow.android.utils.DeviceUtil;
@@ -81,8 +79,14 @@ public class VideoTrimmerUtil {
81
79
  cmds.add(outputFile);
82
80
 
83
81
  String[] command = cmds.toArray(new String[0]);
82
+ String cmdStr = "Command: " + String.join(" ", command);
84
83
 
85
- Log.d(TAG,"Command: " + String.join(",", command));
84
+ Log.d(TAG, cmdStr);
85
+
86
+ WritableMap m = Arguments.createMap();
87
+ m.putString("message", cmdStr);
88
+
89
+ callback.onLog(m);
86
90
 
87
91
  return FFmpegKit.executeWithArgumentsAsync(command, session -> {
88
92
  SessionState state = session.getState();
@@ -0,0 +1,76 @@
1
+ package com.videotrim
2
+
3
+ import android.util.Log
4
+ import com.facebook.react.bridge.Promise
5
+ import com.facebook.react.bridge.ReactApplicationContext
6
+ import com.facebook.react.bridge.ReadableMap
7
+ import com.facebook.react.bridge.WritableMap
8
+
9
+ class VideoTrimModule(
10
+ context: ReactApplicationContext
11
+ ) : VideoTrimSpec(context) {
12
+ // making BaseVideoTrimModule as abstract class then inherit from here doesn't work
13
+ // hence using composition instead of inheritance
14
+ private val base = BaseVideoTrimModule(
15
+ context
16
+ ) { eventName, params -> sendEvent(eventName, params) }
17
+
18
+ private fun sendEvent(eventName: String, params: WritableMap?) {
19
+ when (eventName) {
20
+ "onHide" -> emitOnHide()
21
+ "onShow" -> emitOnShow()
22
+ "onCancel" -> emitOnCancel()
23
+ "onStartTrimming" -> emitOnStartTrimming()
24
+ "onFinishTrimming" -> emitOnFinishTrimming(params)
25
+ "onCancelTrimming" -> emitOnCancelTrimming()
26
+ "onLog" -> emitOnLog(params)
27
+ "onStatistics" -> emitOnStatistics(params)
28
+ "onError" -> emitOnError(params)
29
+ "onLoad" -> emitOnLoad(params)
30
+ // default case to handle unexpected event names
31
+ else -> {
32
+ Log.d(NAME, "Unknown event: $eventName")
33
+ }
34
+ }
35
+ }
36
+
37
+ override fun showEditor(
38
+ filePath: String,
39
+ config: ReadableMap
40
+ ) {
41
+ base.showEditor(filePath, config)
42
+ }
43
+
44
+ override fun listFiles(promise: Promise) {
45
+ base.listFiles(promise)
46
+ }
47
+
48
+ override fun cleanFiles(promise: Promise) {
49
+ base.cleanFiles(promise)
50
+ }
51
+
52
+ override fun deleteFile(filePath: String, promise: Promise) {
53
+ base.deleteFile(filePath, promise)
54
+ }
55
+
56
+ override fun closeEditor() {
57
+ base.closeEditor()
58
+ }
59
+
60
+ override fun isValidFile(url: String, promise: Promise) {
61
+ base.isValidFile(url, promise)
62
+ }
63
+
64
+ override fun trim(
65
+ url: String,
66
+ options: ReadableMap,
67
+ promise: Promise
68
+ ) {
69
+ base.trim(url, options, promise)
70
+ }
71
+
72
+ companion object {
73
+ const val NAME = "VideoTrim"
74
+ }
75
+
76
+ }
@@ -0,0 +1,7 @@
1
+ package com.videotrim
2
+
3
+ import com.facebook.react.bridge.ReactApplicationContext
4
+
5
+ abstract class VideoTrimSpec internal constructor(context: ReactApplicationContext) :
6
+ NativeVideoTrimSpec(context) {
7
+ }
@@ -0,0 +1,75 @@
1
+ package com.videotrim
2
+
3
+ import com.facebook.react.bridge.ReactApplicationContext
4
+ import com.facebook.react.bridge.Arguments
5
+ import com.facebook.react.bridge.WritableMap
6
+
7
+ import com.facebook.react.bridge.*
8
+ import com.facebook.react.module.annotations.ReactModule
9
+ import com.facebook.react.modules.core.DeviceEventManagerModule
10
+
11
+
12
+ @ReactModule(name = VideoTrimModule.NAME)
13
+ class VideoTrimModule internal constructor(context: ReactApplicationContext) : VideoTrimSpec(context) {
14
+ // making BaseVideoTrimModule as abstract class then inherit from here doesn't work
15
+ // hence using composition instead of inheritance
16
+ private val base = BaseVideoTrimModule(
17
+ context
18
+ ) { eventName, params -> sendEvent(eventName, params) }
19
+
20
+
21
+ private fun sendEvent(eventName: String, params: WritableMap?) {
22
+ val map = params ?: Arguments.createMap()
23
+ map.putString("name", eventName)
24
+ reactApplicationContext
25
+ .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
26
+ .emit(NAME, map)
27
+ }
28
+
29
+ override fun getName(): String {
30
+ return NAME
31
+ }
32
+
33
+ @ReactMethod
34
+ override fun showEditor(filePath: String, config: ReadableMap) {
35
+ base.showEditor(filePath, config)
36
+ }
37
+
38
+ @ReactMethod
39
+ override fun listFiles(promise: Promise) {
40
+ base.listFiles(promise)
41
+ }
42
+
43
+ @ReactMethod
44
+ override fun cleanFiles(promise: Promise) {
45
+ base.cleanFiles(promise)
46
+ }
47
+
48
+ @ReactMethod
49
+ override fun deleteFile(filePath: String, promise: Promise) {
50
+ base.deleteFile(filePath, promise)
51
+ }
52
+
53
+ @ReactMethod
54
+ override fun closeEditor() {
55
+ base.closeEditor()
56
+ }
57
+
58
+ @ReactMethod
59
+ override fun isValidFile(url: String, promise: Promise) {
60
+ base.isValidFile(url, promise)
61
+ }
62
+
63
+ @ReactMethod
64
+ override fun trim(
65
+ url: String,
66
+ options: ReadableMap?,
67
+ promise: Promise
68
+ ) {
69
+ base.trim(url, options, promise)
70
+ }
71
+
72
+ companion object {
73
+ const val NAME = "VideoTrim"
74
+ }
75
+ }
@@ -0,0 +1,24 @@
1
+ package com.videotrim
2
+
3
+ import com.facebook.react.bridge.Promise
4
+ import com.facebook.react.bridge.ReactApplicationContext
5
+ import com.facebook.react.bridge.ReactContextBaseJavaModule
6
+ import com.facebook.react.bridge.ReadableMap
7
+
8
+ abstract class VideoTrimSpec internal constructor(context: ReactApplicationContext) :
9
+ ReactContextBaseJavaModule(context) {
10
+
11
+ abstract fun showEditor(filePath: String, config: ReadableMap)
12
+
13
+ abstract fun listFiles(promise: Promise)
14
+
15
+ abstract fun cleanFiles(promise: Promise)
16
+
17
+ abstract fun deleteFile(filePath: String, promise: Promise)
18
+
19
+ abstract fun closeEditor()
20
+
21
+ abstract fun isValidFile(url: String, promise: Promise)
22
+
23
+ abstract fun trim(url: String, options: ReadableMap?, promise: Promise)
24
+ }
@@ -1 +1 @@
1
-
1
+ #import <React/RCTBridgeModule.h>
package/ios/VideoTrim.mm CHANGED
@@ -1,5 +1,12 @@
1
- #import "VideoTrim.h"
1
+ // because Swift class inherits from RCTEventEmitter, hence we need to import it here for both new and old arch
2
+ #import <React/RCTEventEmitter.h>
3
+
4
+ #ifdef RCT_NEW_ARCH_ENABLED
5
+
6
+ #import <VideoTrimSpec/VideoTrimSpec.h>
2
7
  #import <VideoTrim-Swift.h>
8
+ @interface VideoTrim : NativeVideoTrimSpecBase <NativeVideoTrimSpec, VideoTrimProtocol>
9
+ @end
3
10
 
4
11
  @implementation VideoTrim {
5
12
  VideoTrimSwift * _Nullable videoTrim;
@@ -45,9 +52,9 @@ RCT_EXPORT_MODULE()
45
52
  options:(JS::NativeVideoTrim::TrimOptions &)options
46
53
  resolve:(nonnull RCTPromiseResolveBlock)resolve
47
54
  reject:(nonnull RCTPromiseRejectBlock)reject {
48
- // TODO: implement
49
55
  if (!self->videoTrim) {
50
56
  self->videoTrim = [[VideoTrimSwift alloc] init];
57
+ self->videoTrim.isNewArch = true;
51
58
  }
52
59
 
53
60
  NSMutableDictionary *dict = [NSMutableDictionary dictionary];
@@ -83,6 +90,7 @@ RCT_EXPORT_MODULE()
83
90
  if (!self->videoTrim) {
84
91
  self->videoTrim = [[VideoTrimSwift alloc] init];
85
92
  self->videoTrim.delegate = self;
93
+ self->videoTrim.isNewArch = true;
86
94
  }
87
95
 
88
96
  NSMutableDictionary *dict = [NSMutableDictionary dictionary];
@@ -178,3 +186,27 @@ RCT_EXPORT_MODULE()
178
186
  }
179
187
 
180
188
  @end
189
+
190
+ #else
191
+
192
+ #import <React/RCTBridgeModule.h>
193
+
194
+ @interface RCT_EXTERN_REMAP_MODULE(VideoTrim, VideoTrimSwift, RCTEventEmitter)
195
+
196
+ RCT_EXTERN_METHOD(showEditor:(NSString*)uri withConfig:(NSDictionary *)config)
197
+ RCT_EXTERN_METHOD(listFiles:(RCTPromiseResolveBlock)resolve
198
+ withRejecter:(RCTPromiseRejectBlock)reject)
199
+ RCT_EXTERN_METHOD(cleanFiles:(RCTPromiseResolveBlock)resolve
200
+ withRejecter:(RCTPromiseRejectBlock)reject)
201
+ RCT_EXTERN_METHOD(deleteFile:(NSString*)uri withResolver:(RCTPromiseResolveBlock)resolve
202
+ withRejecter:(RCTPromiseRejectBlock)reject)
203
+ RCT_EXTERN_METHOD(closeEditor)
204
+ RCT_EXTERN_METHOD(isValidFile:(NSString*)uri withResolver:(RCTPromiseResolveBlock)resolve
205
+ withRejecter:(RCTPromiseRejectBlock)reject)
206
+ RCT_EXTERN_METHOD(trim:(NSString*)uri withConfig:(NSDictionary *)config
207
+ withResolver:(RCTPromiseResolveBlock)resolve
208
+ withRejecter:(RCTPromiseRejectBlock)reject)
209
+ @end
210
+
211
+ #endif
212
+
@@ -6,7 +6,7 @@ let FILE_PREFIX = "trimmedVideo"
6
6
  let BEFORE_TRIM_PREFIX = "beforeTrim"
7
7
 
8
8
  @objc(VideoTrimSwift)
9
- public class VideoTrim: NSObject, AssetLoaderDelegate, UIDocumentPickerDelegate {
9
+ public class VideoTrim: RCTEventEmitter, AssetLoaderDelegate, UIDocumentPickerDelegate {
10
10
  // MARK: instance private props
11
11
  private var isShowing = false
12
12
  private var vc: VideoTrimmerViewController?
@@ -210,10 +210,41 @@ public class VideoTrim: NSObject, AssetLoaderDelegate, UIDocumentPickerDelegate
210
210
  }
211
211
 
212
212
  @objc public weak var delegate: VideoTrimProtocol?
213
+ @objc public var isNewArch = false
214
+
215
+
216
+
217
+ // MARK: for old arch
218
+ private var hasListeners = false
219
+
220
+ @objc
221
+ static public override func requiresMainQueueSetup() -> Bool {
222
+ return false
223
+ }
224
+
225
+ public override func supportedEvents() -> [String]! {
226
+ return ["VideoTrim"]
227
+ }
228
+
229
+ public override func startObserving() {
230
+ hasListeners = true
231
+ }
232
+
233
+ public override func stopObserving() {
234
+ hasListeners = false
235
+ }
213
236
 
214
237
 
215
238
  private func emitEventToJS(_ eventName: String, eventData: [String: Any]?) {
216
- delegate?.emitEventToJS(eventName: eventName, body: eventData)
239
+ if isNewArch {
240
+ delegate?.emitEventToJS(eventName: eventName, body: eventData)
241
+ } else {
242
+ if hasListeners {
243
+ var modifiedEventData = eventData ?? [:] // If eventData is nil, create an empty dictionary
244
+ modifiedEventData["name"] = eventName
245
+ sendEvent(withName: "VideoTrim", body: modifiedEventData)
246
+ }
247
+ }
217
248
  }
218
249
 
219
250
  private static func deleteFile(url: URL) -> Int {
@@ -433,6 +464,7 @@ public class VideoTrim: NSObject, AssetLoaderDelegate, UIDocumentPickerDelegate
433
464
  })
434
465
  }
435
466
 
467
+ // New Arch
436
468
  @objc(trim:url:config:)
437
469
  public func _trim(inputFile: String, config: NSDictionary, completion: @escaping ([String: Any]?) -> Void) {
438
470
  var destPath: URL?
@@ -502,7 +534,13 @@ public class VideoTrim: NSObject, AssetLoaderDelegate, UIDocumentPickerDelegate
502
534
  }, withLogCallback: nil, withStatisticsCallback: nil)
503
535
  }
504
536
 
505
-
537
+ // Old Arch
538
+ @objc(trim:withConfig:withResolver:withRejecter:)
539
+ func _trim(inputFile: String, config: NSDictionary, resolve: @escaping RCTPromiseResolveBlock,reject: @escaping RCTPromiseRejectBlock) -> Void {
540
+ _trim(inputFile: inputFile, config: config, completion: { payload in
541
+ resolve(payload)
542
+ })
543
+ }
506
544
 
507
545
  private func saveFileToFilesApp(fileURL: URL) {
508
546
  DispatchQueue.main.async {
@@ -602,6 +640,7 @@ public class VideoTrim: NSObject, AssetLoaderDelegate, UIDocumentPickerDelegate
602
640
 
603
641
  // MARK: @objc instance methods
604
642
  extension VideoTrim {
643
+ // Old + New arch
605
644
  @objc(showEditor:withConfig:)
606
645
  public func showEditor(uri: String, config: NSDictionary) {
607
646
  if isShowing {
@@ -755,6 +794,7 @@ extension VideoTrim {
755
794
  }
756
795
  }
757
796
 
797
+ // New Arch
758
798
  @objc(closeEditor:)
759
799
  public func closeEditor(delay: Int = 0) {
760
800
  guard let vc = vc else { return }
@@ -768,15 +808,29 @@ extension VideoTrim {
768
808
  })
769
809
  }
770
810
  }
811
+
812
+ // Old Arch
813
+ @objc(closeEditor)
814
+ func closeEditor() -> Void {
815
+ closeEditor()
816
+ }
771
817
  }
772
818
 
773
819
  // MARK: @objc static methods
774
820
  extension VideoTrim {
821
+ // New Arch
775
822
  @objc(listFiles)
776
823
  public static func _listFiles() -> [String] {
777
824
  return listFiles().map{ $0.absoluteString }
778
825
  }
779
826
 
827
+ // Old Arch
828
+ @objc(listFiles:withRejecter:)
829
+ func listFiles(resolve: @escaping RCTPromiseResolveBlock,reject: @escaping RCTPromiseRejectBlock) -> Void {
830
+ resolve(VideoTrim._listFiles())
831
+ }
832
+
833
+ // New Arch
780
834
  @objc(cleanFiles)
781
835
  public static func cleanFiles() -> Int {
782
836
  let files = listFiles()
@@ -792,12 +846,25 @@ extension VideoTrim {
792
846
  return successCount
793
847
  }
794
848
 
849
+ // Old Arch
850
+ @objc(cleanFiles:withRejecter:)
851
+ func cleanFiles(resolve: @escaping RCTPromiseResolveBlock,reject: @escaping RCTPromiseRejectBlock) -> Void {
852
+ resolve(VideoTrim.cleanFiles())
853
+ }
854
+
855
+ // New Arch
795
856
  @objc(deleteFile:)
796
857
  public static func deleteFile(uri: String) -> Bool {
797
858
  let state = deleteFile(url: URL(string: uri)!)
798
859
  return state == 0
799
860
  }
800
861
 
862
+ // Old Arch
863
+ @objc(deleteFile:withResolver:withRejecter:)
864
+ func deleteFile(uri: String, resolve: @escaping RCTPromiseResolveBlock,reject: @escaping RCTPromiseRejectBlock) -> Void {
865
+ resolve(VideoTrim.deleteFile(uri: uri))
866
+ }
867
+
801
868
  private static func listFiles() -> [URL] {
802
869
  var files: [URL] = []
803
870
 
@@ -818,6 +885,7 @@ extension VideoTrim {
818
885
  return files
819
886
  }
820
887
 
888
+ // New Arch
821
889
  @objc(isValidFile:url:)
822
890
  public static func isValidFile(url: String, completion: @escaping ([String: Any]) -> Void) -> Void {
823
891
  let fileURL = URL(string: url)!
@@ -838,6 +906,15 @@ extension VideoTrim {
838
906
  }
839
907
  }
840
908
 
909
+ // Old Arch
910
+ @objc(isValidFile:withResolver:withRejecter:)
911
+ func isValidFile(uri: String, resolve: @escaping RCTPromiseResolveBlock,reject: @escaping RCTPromiseRejectBlock) -> Void {
912
+ VideoTrim.isValidFile(url: uri, completion: { payload in
913
+ resolve(payload)
914
+ }
915
+ )
916
+ }
917
+
841
918
  private static func checkFileValidity(url: URL, completion: @escaping (Bool, String, Double) -> Void) {
842
919
  let asset = AVAsset(url: url)
843
920
 
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+
3
+ import { NativeModules, Platform } from 'react-native';
4
+ export * from "./NativeVideoTrim.js";
5
+ const LINKING_ERROR = `The package 'react-native-video-trim' doesn't seem to be linked. Make sure: \n\n` + Platform.select({
6
+ ios: "- You have run 'pod install'\n",
7
+ default: ''
8
+ }) + '- You rebuilt the app after installing the package\n' + '- You are not using Expo Go\n';
9
+ const VideoTrim = NativeModules.VideoTrim ? NativeModules.VideoTrim : new Proxy({}, {
10
+ get() {
11
+ throw new Error(LINKING_ERROR);
12
+ }
13
+ });
14
+ export default VideoTrim;
15
+ //# sourceMappingURL=OldArch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["NativeModules","Platform","LINKING_ERROR","select","ios","default","VideoTrim","Proxy","get","Error"],"sourceRoot":"../../src","sources":["OldArch.ts"],"mappings":";;AAAA,SAASA,aAAa,EAAEC,QAAQ,QAAQ,cAAc;AACtD,cAAc,sBAAmB;AAEjC,MAAMC,aAAa,GACjB,kFAAkF,GAClFD,QAAQ,CAACE,MAAM,CAAC;EAAEC,GAAG,EAAE,gCAAgC;EAAEC,OAAO,EAAE;AAAG,CAAC,CAAC,GACvE,sDAAsD,GACtD,+BAA+B;AAEjC,MAAMC,SAAS,GAAGN,aAAa,CAACM,SAAS,GACrCN,aAAa,CAACM,SAAS,GACvB,IAAIC,KAAK,CACP,CAAC,CAAC,EACF;EACEC,GAAGA,CAAA,EAAG;IACJ,MAAM,IAAIC,KAAK,CAACP,aAAa,CAAC;EAChC;AACF,CACF,CAAC;AAEL,eAAeI,SAAS","ignoreList":[]}
@@ -1,8 +1,12 @@
1
1
  "use strict";
2
2
 
3
- import VideoTrim from "./NativeVideoTrim.js";
3
+ import VideoTrimNewArch from "./NativeVideoTrim.js";
4
+ import VideoTrimOldArch from "./OldArch.js";
4
5
  import { processColor } from 'react-native';
5
- export * from "./NativeVideoTrim.js";
6
+
7
+ // React Native runtime flags like nativeFabricUIManager are not in TypeScript types. Using `any` here is intentional and safe.
8
+ const isFabric = !!global.nativeFabricUIManager;
9
+ const VideoTrim = isFabric ? VideoTrimNewArch : VideoTrimOldArch;
6
10
  function createBaseOptions(overrides = {}) {
7
11
  return {
8
12
  saveToPhoto: false,
@@ -1 +1 @@
1
- {"version":3,"names":["VideoTrim","processColor","createBaseOptions","overrides","saveToPhoto","type","outputExt","openDocumentsOnFinish","openShareSheetOnFinish","removeAfterSavedToPhoto","removeAfterFailedToSavePhoto","removeAfterSavedToDocuments","removeAfterFailedToSaveDocuments","removeAfterShared","removeAfterFailedToShare","enableRotation","rotationAngle","createEditorConfig","enableHapticFeedback","maxDuration","minDuration","cancelButtonText","saveButtonText","enableCancelDialog","cancelDialogTitle","cancelDialogMessage","cancelDialogCancelText","cancelDialogConfirmText","enableSaveDialog","saveDialogTitle","saveDialogMessage","saveDialogCancelText","saveDialogConfirmText","trimmingText","fullScreenModalIOS","autoplay","jumpToPositionOnLoad","closeWhenFinish","enableCancelTrimming","cancelTrimmingButtonText","enableCancelTrimmingDialog","cancelTrimmingDialogTitle","cancelTrimmingDialogMessage","cancelTrimmingDialogCancelText","cancelTrimmingDialogConfirmText","headerText","headerTextSize","headerTextColor","alertOnFailToLoad","alertOnFailTitle","alertOnFailMessage","alertOnFailCloseText","createTrimOptions","startTime","endTime","showEditor","filePath","config","color","listFiles","cleanFiles","deleteFile","trim","length","Error","closeEditor","isValidFile","url","options"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"names":["VideoTrimNewArch","VideoTrimOldArch","processColor","isFabric","global","nativeFabricUIManager","VideoTrim","createBaseOptions","overrides","saveToPhoto","type","outputExt","openDocumentsOnFinish","openShareSheetOnFinish","removeAfterSavedToPhoto","removeAfterFailedToSavePhoto","removeAfterSavedToDocuments","removeAfterFailedToSaveDocuments","removeAfterShared","removeAfterFailedToShare","enableRotation","rotationAngle","createEditorConfig","enableHapticFeedback","maxDuration","minDuration","cancelButtonText","saveButtonText","enableCancelDialog","cancelDialogTitle","cancelDialogMessage","cancelDialogCancelText","cancelDialogConfirmText","enableSaveDialog","saveDialogTitle","saveDialogMessage","saveDialogCancelText","saveDialogConfirmText","trimmingText","fullScreenModalIOS","autoplay","jumpToPositionOnLoad","closeWhenFinish","enableCancelTrimming","cancelTrimmingButtonText","enableCancelTrimmingDialog","cancelTrimmingDialogTitle","cancelTrimmingDialogMessage","cancelTrimmingDialogCancelText","cancelTrimmingDialogConfirmText","headerText","headerTextSize","headerTextColor","alertOnFailToLoad","alertOnFailTitle","alertOnFailMessage","alertOnFailCloseText","createTrimOptions","startTime","endTime","showEditor","filePath","config","color","listFiles","cleanFiles","deleteFile","trim","length","Error","closeEditor","isValidFile","url","options"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":"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","ignoreList":[]}
@@ -0,0 +1,4 @@
1
+ export * from './NativeVideoTrim';
2
+ declare const VideoTrim: any;
3
+ export default VideoTrim;
4
+ //# sourceMappingURL=OldArch.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"OldArch.d.ts","sourceRoot":"","sources":["../../../src/OldArch.ts"],"names":[],"mappings":"AACA,cAAc,mBAAmB,CAAC;AAQlC,QAAA,MAAM,SAAS,KASV,CAAC;AAEN,eAAe,SAAS,CAAC"}
@@ -1,6 +1,5 @@
1
- import VideoTrim from './NativeVideoTrim';
2
1
  import type { EditorConfig, FileValidationResult, TrimOptions } from './NativeVideoTrim';
3
- export * from './NativeVideoTrim';
2
+ declare const VideoTrim: any;
4
3
  /**
5
4
  * Show video editor
6
5
  *
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.tsx"],"names":[],"mappings":"AAAA,OAAO,SAAS,MAAM,mBAAmB,CAAC;AAC1C,OAAO,KAAK,EAEV,YAAY,EACZ,oBAAoB,EACpB,WAAW,EACZ,MAAM,mBAAmB,CAAC;AAE3B,cAAc,mBAAmB,CAAC;AA0ElC;;;;;;;GAOG;AACH,wBAAgB,UAAU,CACxB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,OAAO,CAAC,IAAI,CAAC,YAAY,EAAE,iBAAiB,CAAC,CAAC,GAAG;IACvD,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B,GACA,IAAI,CAWN;AAED;;;;GAIG;AACH,wBAAgB,SAAS,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC,CAE7C;AAED;;;;GAIG;AACH,wBAAgB,UAAU,IAAI,OAAO,CAAC,MAAM,CAAC,CAE5C;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAK7D;AAED;;GAEG;AACH,wBAAgB,WAAW,IAAI,IAAI,CAElC;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAEtE;AAED;;;;;;GAMG;AACH,wBAAgB,IAAI,CAClB,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,OAAO,CAAC,WAAW,CAAC,GAC5B,OAAO,CAAC,MAAM,CAAC,CAEjB;AAED,cAAc,mBAAmB,CAAC;AAClC,eAAe,SAAS,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAEV,YAAY,EACZ,oBAAoB,EACpB,WAAW,EACZ,MAAM,mBAAmB,CAAC;AAK3B,QAAA,MAAM,SAAS,KAAiD,CAAC;AA0EjE;;;;;;;GAOG;AACH,wBAAgB,UAAU,CACxB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,OAAO,CAAC,IAAI,CAAC,YAAY,EAAE,iBAAiB,CAAC,CAAC,GAAG;IACvD,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B,GACA,IAAI,CAWN;AAED;;;;GAIG;AACH,wBAAgB,SAAS,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC,CAE7C;AAED;;;;GAIG;AACH,wBAAgB,UAAU,IAAI,OAAO,CAAC,MAAM,CAAC,CAE5C;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAK7D;AAED;;GAEG;AACH,wBAAgB,WAAW,IAAI,IAAI,CAElC;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAEtE;AAED;;;;;;GAMG;AACH,wBAAgB,IAAI,CAClB,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,OAAO,CAAC,WAAW,CAAC,GAC5B,OAAO,CAAC,MAAM,CAAC,CAEjB;AAED,cAAc,mBAAmB,CAAC;AAClC,eAAe,SAAS,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-video-trim",
3
- "version": "5.1.1",
3
+ "version": "6.0.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",
package/src/OldArch.ts ADDED
@@ -0,0 +1,21 @@
1
+ import { NativeModules, Platform } from 'react-native';
2
+ export * from './NativeVideoTrim';
3
+
4
+ const LINKING_ERROR =
5
+ `The package 'react-native-video-trim' doesn't seem to be linked. Make sure: \n\n` +
6
+ Platform.select({ ios: "- You have run 'pod install'\n", default: '' }) +
7
+ '- You rebuilt the app after installing the package\n' +
8
+ '- You are not using Expo Go\n';
9
+
10
+ const VideoTrim = NativeModules.VideoTrim
11
+ ? NativeModules.VideoTrim
12
+ : new Proxy(
13
+ {},
14
+ {
15
+ get() {
16
+ throw new Error(LINKING_ERROR);
17
+ },
18
+ }
19
+ );
20
+
21
+ export default VideoTrim;
package/src/index.tsx CHANGED
@@ -1,4 +1,5 @@
1
- import VideoTrim from './NativeVideoTrim';
1
+ import VideoTrimNewArch from './NativeVideoTrim';
2
+ import VideoTrimOldArch from './OldArch';
2
3
  import type {
3
4
  BaseOptions,
4
5
  EditorConfig,
@@ -6,7 +7,10 @@ import type {
6
7
  TrimOptions,
7
8
  } from './NativeVideoTrim';
8
9
  import { processColor } from 'react-native';
9
- export * from './NativeVideoTrim';
10
+
11
+ // React Native runtime flags like nativeFabricUIManager are not in TypeScript types. Using `any` here is intentional and safe.
12
+ const isFabric = !!(global as any).nativeFabricUIManager;
13
+ const VideoTrim = isFabric ? VideoTrimNewArch : VideoTrimOldArch;
10
14
 
11
15
  function createBaseOptions(overrides: Partial<BaseOptions> = {}): BaseOptions {
12
16
  return {
package/ios/VideoTrim.h DELETED
@@ -1,5 +0,0 @@
1
- #import <VideoTrimSpec/VideoTrimSpec.h>
2
- #import <VideoTrim-Swift.h>
3
-
4
- @interface VideoTrim : NativeVideoTrimSpecBase <NativeVideoTrimSpec, VideoTrimProtocol>
5
- @end