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 +152 -44
- package/android/build.gradle +24 -9
- package/android/src/main/java/com/videotrim/{VideoTrimModule.kt → BaseVideoTrimModule.kt} +56 -58
- package/android/src/main/java/com/videotrim/interfaces/VideoTrimListener.java +3 -2
- package/android/src/main/java/com/videotrim/utils/VideoTrimmerUtil.java +7 -3
- package/android/src/newarch/VideoTrimModule.kt +76 -0
- package/android/src/newarch/VideoTrimSpec.kt +7 -0
- package/android/src/oldarch/VideoTrimModule.kt +75 -0
- package/android/src/oldarch/VideoTrimSpec.kt +24 -0
- package/ios/VideoTrim-Bridging-Header.h +1 -1
- package/ios/VideoTrim.mm +34 -2
- package/ios/VideoTrim.swift +80 -3
- package/lib/module/OldArch.js +15 -0
- package/lib/module/OldArch.js.map +1 -0
- package/lib/module/index.js +6 -2
- package/lib/module/index.js.map +1 -1
- package/lib/typescript/src/OldArch.d.ts +4 -0
- package/lib/typescript/src/OldArch.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +1 -2
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/OldArch.ts +21 -0
- package/src/index.tsx +6 -2
- package/ios/VideoTrim.h +0 -5
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
|
-
- [
|
|
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
|
-
##
|
|
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="
|
|
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
|
|
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
|
-
#
|
|
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" />
|
package/android/build.gradle
CHANGED
|
@@ -19,7 +19,9 @@ buildscript {
|
|
|
19
19
|
apply plugin: "com.android.library"
|
|
20
20
|
apply plugin: "kotlin-android"
|
|
21
21
|
|
|
22
|
-
|
|
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
|
-
|
|
68
|
-
|
|
69
|
-
|
|
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
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
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.
|
|
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
|
-
|
|
51
|
-
|
|
52
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
200
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
334
|
+
sendEvent("onError", map)
|
|
322
335
|
}
|
|
323
336
|
|
|
324
337
|
override fun onCancel() {
|
|
325
338
|
if (!editorConfig?.getBoolean("enableCancelDialog")!!) {
|
|
326
|
-
|
|
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
|
-
|
|
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:
|
|
373
|
-
|
|
385
|
+
override fun onLog(log: WritableMap) {
|
|
386
|
+
sendEvent("onLog", log)
|
|
374
387
|
}
|
|
375
388
|
|
|
376
|
-
override fun onStatistics(statistics:
|
|
377
|
-
|
|
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
|
-
|
|
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
|
-
|
|
520
|
-
|
|
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
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
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
|
-
|
|
546
|
+
promise.resolve(successCount.toDouble())
|
|
546
547
|
}
|
|
547
548
|
|
|
548
|
-
|
|
549
|
-
|
|
549
|
+
fun deleteFile(filePath: String, promise: Promise) {
|
|
550
|
+
promise.resolve(StorageUtil.deleteFile(filePath))
|
|
550
551
|
}
|
|
551
552
|
|
|
552
|
-
|
|
553
|
+
fun closeEditor() {
|
|
553
554
|
hideDialog(true)
|
|
554
|
-
|
|
555
|
+
sendEvent("onHide", null)
|
|
555
556
|
}
|
|
556
557
|
|
|
557
|
-
|
|
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
|
-
|
|
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(
|
|
17
|
-
void onStatistics(
|
|
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,
|
|
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,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
|
-
|
|
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
|
+
|
package/ios/VideoTrim.swift
CHANGED
|
@@ -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:
|
|
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
|
-
|
|
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":[]}
|
package/lib/module/index.js
CHANGED
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
-
import
|
|
3
|
+
import VideoTrimNewArch from "./NativeVideoTrim.js";
|
|
4
|
+
import VideoTrimOldArch from "./OldArch.js";
|
|
4
5
|
import { processColor } from 'react-native';
|
|
5
|
-
|
|
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,
|
package/lib/module/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["
|
|
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 @@
|
|
|
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 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.tsx"],"names":[],"mappings":"
|
|
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
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
|
|
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
|
-
|
|
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 {
|