react-native-video-trim 1.0.5 → 1.0.6
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 +3 -0
- package/android/src/main/java/com/videotrim/VideoTrimModule.java +2 -10
- package/android/src/main/java/com/videotrim/widgets/VideoTrimmerView.java +25 -7
- package/ios/VideoTrim.swift +17 -0
- package/lib/commonjs/index.js +26 -20
- package/lib/commonjs/index.js.map +1 -1
- package/lib/module/index.js +26 -20
- package/lib/module/index.js.map +1 -1
- package/lib/typescript/index.d.ts +3 -0
- package/lib/typescript/index.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/index.tsx +32 -22
package/README.md
CHANGED
|
@@ -147,6 +147,9 @@ Main method to show Video Editor UI.
|
|
|
147
147
|
|
|
148
148
|
- `saveToPhoto` (optional, `default = true`): whether to save video to photo/gallery after editing
|
|
149
149
|
- `maxDuration` (optional): maximum duration for the trimmed video
|
|
150
|
+
- `leftButtonText` (optional): text for left button in Editor dialog
|
|
151
|
+
- `rightButtonText` (optional): text for right button in Editor dialog
|
|
152
|
+
- `title` (optional, iOS only): title Editor dialog
|
|
150
153
|
|
|
151
154
|
If `saveToPhoto = true`, you must ensure that you have request permission to write to photo/gallery
|
|
152
155
|
- For Android: you need to have `<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />` in AndroidManifest.xml
|
|
@@ -45,7 +45,6 @@ public class VideoTrimModule extends ReactContextBaseJavaModule implements Video
|
|
|
45
45
|
private AlertDialog mProgressDialog;
|
|
46
46
|
private ProgressBar mProgressBar;
|
|
47
47
|
private Boolean mSaveToPhoto = true;
|
|
48
|
-
private int mMaxDuration = 0;
|
|
49
48
|
private int listenerCount = 0;
|
|
50
49
|
|
|
51
50
|
private Promise showEditorPromise;
|
|
@@ -71,9 +70,6 @@ public class VideoTrimModule extends ReactContextBaseJavaModule implements Video
|
|
|
71
70
|
if (config.hasKey("saveToPhoto")) {
|
|
72
71
|
this.mSaveToPhoto = config.getBoolean("saveToPhoto");
|
|
73
72
|
}
|
|
74
|
-
if (config.hasKey("maxDuration")) {
|
|
75
|
-
this.mMaxDuration = config.getInt("maxDuration");
|
|
76
|
-
}
|
|
77
73
|
|
|
78
74
|
if (!_isValidVideo(videoPath)) {
|
|
79
75
|
WritableMap map = Arguments.createMap();
|
|
@@ -92,7 +88,7 @@ public class VideoTrimModule extends ReactContextBaseJavaModule implements Video
|
|
|
92
88
|
// here is NOT main thread, we need to create VideoTrimmerView on UI thread, so that later we can update it using same thread
|
|
93
89
|
|
|
94
90
|
runOnUiThread(() -> {
|
|
95
|
-
trimmerView = new VideoTrimmerView(getReactApplicationContext(),
|
|
91
|
+
trimmerView = new VideoTrimmerView(getReactApplicationContext(), config, null);
|
|
96
92
|
trimmerView.setOnTrimVideoListener(this);
|
|
97
93
|
trimmerView.initVideoByURI(Uri.parse(videoPath));
|
|
98
94
|
|
|
@@ -161,11 +157,7 @@ public class VideoTrimModule extends ReactContextBaseJavaModule implements Video
|
|
|
161
157
|
WritableMap map = Arguments.createMap();
|
|
162
158
|
map.putString("outputPath", in);
|
|
163
159
|
sendEvent(getReactApplicationContext(), "onFinishTrimming", map);
|
|
164
|
-
|
|
165
|
-
showEditorPromise.resolve(in);
|
|
166
|
-
} else {
|
|
167
|
-
hideDialog();
|
|
168
|
-
}
|
|
160
|
+
showEditorPromise.resolve(in);
|
|
169
161
|
});
|
|
170
162
|
}
|
|
171
163
|
|
|
@@ -22,6 +22,7 @@ import android.widget.FrameLayout;
|
|
|
22
22
|
import android.widget.ImageView;
|
|
23
23
|
import android.widget.LinearLayout;
|
|
24
24
|
import android.widget.RelativeLayout;
|
|
25
|
+
import android.widget.TextView;
|
|
25
26
|
import android.widget.Toast;
|
|
26
27
|
|
|
27
28
|
import androidx.appcompat.app.AlertDialog;
|
|
@@ -29,6 +30,7 @@ import androidx.recyclerview.widget.LinearLayoutManager;
|
|
|
29
30
|
import androidx.recyclerview.widget.RecyclerView;
|
|
30
31
|
|
|
31
32
|
import com.facebook.react.bridge.ReactApplicationContext;
|
|
33
|
+
import com.facebook.react.bridge.ReadableMap;
|
|
32
34
|
import com.videotrim.R;
|
|
33
35
|
import com.videotrim.adapters.VideoTrimmerAdapter;
|
|
34
36
|
import com.videotrim.interfaces.IVideoTrimmerView;
|
|
@@ -82,19 +84,18 @@ public class VideoTrimmerView extends FrameLayout implements IVideoTrimmerView {
|
|
|
82
84
|
|
|
83
85
|
|
|
84
86
|
public VideoTrimmerView(ReactApplicationContext context, AttributeSet attrs) {
|
|
85
|
-
this(context, attrs, 0);
|
|
87
|
+
this(context, attrs, 0, null);
|
|
86
88
|
}
|
|
87
|
-
public VideoTrimmerView(ReactApplicationContext context,
|
|
88
|
-
this(context, attrs, 0);
|
|
89
|
-
this.mMaxDuration = maxDuration;
|
|
89
|
+
public VideoTrimmerView(ReactApplicationContext context, ReadableMap config, AttributeSet attrs) {
|
|
90
|
+
this(context, attrs, 0, config);
|
|
90
91
|
}
|
|
91
92
|
|
|
92
|
-
public VideoTrimmerView(ReactApplicationContext context, AttributeSet attrs, int defStyleAttr) {
|
|
93
|
+
public VideoTrimmerView(ReactApplicationContext context, AttributeSet attrs, int defStyleAttr, ReadableMap config) {
|
|
93
94
|
super(context, attrs, defStyleAttr);
|
|
94
|
-
init(context);
|
|
95
|
+
init(context, config);
|
|
95
96
|
}
|
|
96
97
|
|
|
97
|
-
private void init(ReactApplicationContext context) {
|
|
98
|
+
private void init(ReactApplicationContext context, ReadableMap config) {
|
|
98
99
|
this.mContext = context;
|
|
99
100
|
|
|
100
101
|
// listen to onConfigurationChanged doesn't work for this, it runs too soon
|
|
@@ -112,6 +113,7 @@ public class VideoTrimmerView extends FrameLayout implements IVideoTrimmerView {
|
|
|
112
113
|
mVideoThumbRecyclerView.setAdapter(mVideoThumbAdapter);
|
|
113
114
|
mVideoThumbRecyclerView.addOnScrollListener(mOnScrollListener);
|
|
114
115
|
|
|
116
|
+
configure(config);
|
|
115
117
|
setUpListeners();
|
|
116
118
|
}
|
|
117
119
|
|
|
@@ -485,4 +487,20 @@ public class VideoTrimmerView extends FrameLayout implements IVideoTrimmerView {
|
|
|
485
487
|
|
|
486
488
|
return screenWidth;
|
|
487
489
|
}
|
|
490
|
+
|
|
491
|
+
private void configure(ReadableMap config) {
|
|
492
|
+
if (config.hasKey("maxDuration")) {
|
|
493
|
+
this.mMaxDuration = config.getInt("maxDuration");
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
if (config.hasKey("leftButtonText")) {
|
|
497
|
+
TextView tv = findViewById(R.id.cancelBtn);
|
|
498
|
+
tv.setText(config.getString("leftButtonText"));
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
if (config.hasKey("rightButtonText")) {
|
|
502
|
+
TextView tv = findViewById(R.id.saveBtn);
|
|
503
|
+
tv.setText(config.getString("rightButtonText"));
|
|
504
|
+
}
|
|
505
|
+
}
|
|
488
506
|
}
|
package/ios/VideoTrim.swift
CHANGED
|
@@ -65,6 +65,23 @@ class VideoTrim: RCTEventEmitter, UIVideoEditorControllerDelegate, UINavigationC
|
|
|
65
65
|
root.present(editController, animated: true, completion: {
|
|
66
66
|
self.emitEventToJS("onShow", eventData: nil)
|
|
67
67
|
self.isShowing = true
|
|
68
|
+
|
|
69
|
+
if let topItem = editController.navigationBar.topItem{
|
|
70
|
+
if let title = config["title"] as? String, !title.isEmpty {
|
|
71
|
+
topItem.title = title
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// when it comes to bar button customization
|
|
75
|
+
// we can't customize text of original buttons here, we can only set attrs like enabled/hidden
|
|
76
|
+
// to customize text we need to create new button
|
|
77
|
+
if let leftBtnText = config["leftButtonText"] as? String, !leftBtnText.isEmpty {
|
|
78
|
+
topItem.leftBarButtonItem = UIBarButtonItem(title: leftBtnText, style: topItem.leftBarButtonItem?.style ?? .plain, target: topItem.leftBarButtonItem?.target, action: topItem.leftBarButtonItem?.action)
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if let rightBtnText = config["rightButtonText"] as? String, !rightBtnText.isEmpty {
|
|
82
|
+
topItem.rightBarButtonItem = UIBarButtonItem(title: rightBtnText, style: topItem.rightBarButtonItem?.style ?? .plain, target: topItem.rightBarButtonItem?.target, action: topItem.rightBarButtonItem?.action)
|
|
83
|
+
}
|
|
84
|
+
}
|
|
68
85
|
})
|
|
69
86
|
}
|
|
70
87
|
}
|
package/lib/commonjs/index.js
CHANGED
|
@@ -18,30 +18,36 @@ const VideoTrim = _reactNative.NativeModules.VideoTrim ? _reactNative.NativeModu
|
|
|
18
18
|
async function showEditor(videoPath) {
|
|
19
19
|
let config = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
20
20
|
const {
|
|
21
|
-
maxDuration,
|
|
22
21
|
saveToPhoto = true
|
|
23
22
|
} = config;
|
|
24
|
-
const outputPath = await VideoTrim.showEditor(videoPath,
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
23
|
+
const outputPath = await VideoTrim.showEditor(videoPath, config);
|
|
24
|
+
if (_reactNative.Platform.OS === 'android') {
|
|
25
|
+
if (saveToPhoto) {
|
|
26
|
+
try {
|
|
27
|
+
if (_reactNative.Platform.Version >= 33) {
|
|
28
|
+
// since android 13 it's not needed to request permission for write storage: https://github.com/facebook/react-native/issues/36714#issuecomment-1491338276
|
|
29
|
+
await VideoTrim.saveVideo(outputPath);
|
|
30
|
+
} else {
|
|
31
|
+
const granted = await _reactNative.PermissionsAndroid.request(_reactNative.PermissionsAndroid.PERMISSIONS.WRITE_EXTERNAL_STORAGE, {
|
|
32
|
+
title: 'Video Trimmer Photos Access Required',
|
|
33
|
+
message: 'Grant access to your Photos to write output Video',
|
|
34
|
+
buttonNeutral: 'Ask Me Later',
|
|
35
|
+
buttonNegative: 'Cancel',
|
|
36
|
+
buttonPositive: 'OK'
|
|
37
|
+
});
|
|
38
|
+
if (granted === _reactNative.PermissionsAndroid.RESULTS.GRANTED) {
|
|
39
|
+
await VideoTrim.saveVideo(outputPath);
|
|
40
|
+
} else {
|
|
41
|
+
throw new Error('Photos Library permission denied');
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
} catch (err) {
|
|
45
|
+
throw err;
|
|
46
|
+
} finally {
|
|
40
47
|
VideoTrim.hideDialog();
|
|
41
|
-
throw new Error('Photos Library permission denied');
|
|
42
48
|
}
|
|
43
|
-
}
|
|
44
|
-
|
|
49
|
+
} else {
|
|
50
|
+
VideoTrim.hideDialog();
|
|
45
51
|
}
|
|
46
52
|
}
|
|
47
53
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["_reactNative","require","LINKING_ERROR","Platform","select","ios","default","VideoTrim","NativeModules","Proxy","get","Error","showEditor","videoPath","config","arguments","length","undefined","
|
|
1
|
+
{"version":3,"names":["_reactNative","require","LINKING_ERROR","Platform","select","ios","default","VideoTrim","NativeModules","Proxy","get","Error","showEditor","videoPath","config","arguments","length","undefined","saveToPhoto","outputPath","OS","Version","saveVideo","granted","PermissionsAndroid","request","PERMISSIONS","WRITE_EXTERNAL_STORAGE","title","message","buttonNeutral","buttonNegative","buttonPositive","RESULTS","GRANTED","err","hideDialog","isValidVideo"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":";;;;;;;AAAA,IAAAA,YAAA,GAAAC,OAAA;AAEA,MAAMC,aAAa,GAChB,kFAAiF,GAClFC,qBAAQ,CAACC,MAAM,CAAC;EAAEC,GAAG,EAAE,gCAAgC;EAAEC,OAAO,EAAE;AAAG,CAAC,CAAC,GACvE,sDAAsD,GACtD,+BAA+B;AAEjC,MAAMC,SAAS,GAAGC,0BAAa,CAACD,SAAS,GACrCC,0BAAa,CAACD,SAAS,GACvB,IAAIE,KAAK,CACP,CAAC,CAAC,EACF;EACEC,GAAGA,CAAA,EAAG;IACJ,MAAM,IAAIC,KAAK,CAACT,aAAa,CAAC;EAChC;AACF,CACF,CAAC;AAUE,eAAeU,UAAUA,CAC9BC,SAAiB,EAEF;EAAA,IADfC,MAAoB,GAAAC,SAAA,CAAAC,MAAA,QAAAD,SAAA,QAAAE,SAAA,GAAAF,SAAA,MAAG,CAAC,CAAC;EAEzB,MAAM;IAAEG,WAAW,GAAG;EAAK,CAAC,GAAGJ,MAAM;EACrC,MAAMK,UAAU,GAAG,MAAMZ,SAAS,CAACK,UAAU,CAACC,SAAS,EAAEC,MAAM,CAAC;EAEhE,IAAIX,qBAAQ,CAACiB,EAAE,KAAK,SAAS,EAAE;IAC7B,IAAIF,WAAW,EAAE;MACf,IAAI;QACF,IAAIf,qBAAQ,CAACkB,OAAO,IAAI,EAAE,EAAE;UAC1B;UACA,MAAMd,SAAS,CAACe,SAAS,CAACH,UAAU,CAAC;QACvC,CAAC,MAAM;UACL,MAAMI,OAAO,GAAG,MAAMC,+BAAkB,CAACC,OAAO,CAC9CD,+BAAkB,CAACE,WAAW,CAACC,sBAAsB,EACrD;YACEC,KAAK,EAAE,sCAAsC;YAC7CC,OAAO,EAAE,mDAAmD;YAC5DC,aAAa,EAAE,cAAc;YAC7BC,cAAc,EAAE,QAAQ;YACxBC,cAAc,EAAE;UAClB,CACF,CAAC;UACD,IAAIT,OAAO,KAAKC,+BAAkB,CAACS,OAAO,CAACC,OAAO,EAAE;YAClD,MAAM3B,SAAS,CAACe,SAAS,CAACH,UAAU,CAAC;UACvC,CAAC,MAAM;YACL,MAAM,IAAIR,KAAK,CAAC,kCAAkC,CAAC;UACrD;QACF;MACF,CAAC,CAAC,OAAOwB,GAAG,EAAE;QACZ,MAAMA,GAAG;MACX,CAAC,SAAS;QACR5B,SAAS,CAAC6B,UAAU,CAAC,CAAC;MACxB;IACF,CAAC,MAAM;MACL7B,SAAS,CAAC6B,UAAU,CAAC,CAAC;IACxB;EACF;AACF;AAEO,SAASC,YAAYA,CAACxB,SAAiB,EAAoB;EAChE,OAAON,SAAS,CAAC8B,YAAY,CAACxB,SAAS,CAAC;AAC1C"}
|
package/lib/module/index.js
CHANGED
|
@@ -11,30 +11,36 @@ const VideoTrim = NativeModules.VideoTrim ? NativeModules.VideoTrim : new Proxy(
|
|
|
11
11
|
export async function showEditor(videoPath) {
|
|
12
12
|
let config = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
13
13
|
const {
|
|
14
|
-
maxDuration,
|
|
15
14
|
saveToPhoto = true
|
|
16
15
|
} = config;
|
|
17
|
-
const outputPath = await VideoTrim.showEditor(videoPath,
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
16
|
+
const outputPath = await VideoTrim.showEditor(videoPath, config);
|
|
17
|
+
if (Platform.OS === 'android') {
|
|
18
|
+
if (saveToPhoto) {
|
|
19
|
+
try {
|
|
20
|
+
if (Platform.Version >= 33) {
|
|
21
|
+
// since android 13 it's not needed to request permission for write storage: https://github.com/facebook/react-native/issues/36714#issuecomment-1491338276
|
|
22
|
+
await VideoTrim.saveVideo(outputPath);
|
|
23
|
+
} else {
|
|
24
|
+
const granted = await PermissionsAndroid.request(PermissionsAndroid.PERMISSIONS.WRITE_EXTERNAL_STORAGE, {
|
|
25
|
+
title: 'Video Trimmer Photos Access Required',
|
|
26
|
+
message: 'Grant access to your Photos to write output Video',
|
|
27
|
+
buttonNeutral: 'Ask Me Later',
|
|
28
|
+
buttonNegative: 'Cancel',
|
|
29
|
+
buttonPositive: 'OK'
|
|
30
|
+
});
|
|
31
|
+
if (granted === PermissionsAndroid.RESULTS.GRANTED) {
|
|
32
|
+
await VideoTrim.saveVideo(outputPath);
|
|
33
|
+
} else {
|
|
34
|
+
throw new Error('Photos Library permission denied');
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
} catch (err) {
|
|
38
|
+
throw err;
|
|
39
|
+
} finally {
|
|
33
40
|
VideoTrim.hideDialog();
|
|
34
|
-
throw new Error('Photos Library permission denied');
|
|
35
41
|
}
|
|
36
|
-
}
|
|
37
|
-
|
|
42
|
+
} else {
|
|
43
|
+
VideoTrim.hideDialog();
|
|
38
44
|
}
|
|
39
45
|
}
|
|
40
46
|
}
|
package/lib/module/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["NativeModules","PermissionsAndroid","Platform","LINKING_ERROR","select","ios","default","VideoTrim","Proxy","get","Error","showEditor","videoPath","config","arguments","length","undefined","
|
|
1
|
+
{"version":3,"names":["NativeModules","PermissionsAndroid","Platform","LINKING_ERROR","select","ios","default","VideoTrim","Proxy","get","Error","showEditor","videoPath","config","arguments","length","undefined","saveToPhoto","outputPath","OS","Version","saveVideo","granted","request","PERMISSIONS","WRITE_EXTERNAL_STORAGE","title","message","buttonNeutral","buttonNegative","buttonPositive","RESULTS","GRANTED","err","hideDialog","isValidVideo"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":"AAAA,SAASA,aAAa,EAAEC,kBAAkB,EAAEC,QAAQ,QAAQ,cAAc;AAE1E,MAAMC,aAAa,GAChB,kFAAiF,GAClFD,QAAQ,CAACE,MAAM,CAAC;EAAEC,GAAG,EAAE,gCAAgC;EAAEC,OAAO,EAAE;AAAG,CAAC,CAAC,GACvE,sDAAsD,GACtD,+BAA+B;AAEjC,MAAMC,SAAS,GAAGP,aAAa,CAACO,SAAS,GACrCP,aAAa,CAACO,SAAS,GACvB,IAAIC,KAAK,CACP,CAAC,CAAC,EACF;EACEC,GAAGA,CAAA,EAAG;IACJ,MAAM,IAAIC,KAAK,CAACP,aAAa,CAAC;EAChC;AACF,CACF,CAAC;AAUL,OAAO,eAAeQ,UAAUA,CAC9BC,SAAiB,EAEF;EAAA,IADfC,MAAoB,GAAAC,SAAA,CAAAC,MAAA,QAAAD,SAAA,QAAAE,SAAA,GAAAF,SAAA,MAAG,CAAC,CAAC;EAEzB,MAAM;IAAEG,WAAW,GAAG;EAAK,CAAC,GAAGJ,MAAM;EACrC,MAAMK,UAAU,GAAG,MAAMX,SAAS,CAACI,UAAU,CAACC,SAAS,EAAEC,MAAM,CAAC;EAEhE,IAAIX,QAAQ,CAACiB,EAAE,KAAK,SAAS,EAAE;IAC7B,IAAIF,WAAW,EAAE;MACf,IAAI;QACF,IAAIf,QAAQ,CAACkB,OAAO,IAAI,EAAE,EAAE;UAC1B;UACA,MAAMb,SAAS,CAACc,SAAS,CAACH,UAAU,CAAC;QACvC,CAAC,MAAM;UACL,MAAMI,OAAO,GAAG,MAAMrB,kBAAkB,CAACsB,OAAO,CAC9CtB,kBAAkB,CAACuB,WAAW,CAACC,sBAAsB,EACrD;YACEC,KAAK,EAAE,sCAAsC;YAC7CC,OAAO,EAAE,mDAAmD;YAC5DC,aAAa,EAAE,cAAc;YAC7BC,cAAc,EAAE,QAAQ;YACxBC,cAAc,EAAE;UAClB,CACF,CAAC;UACD,IAAIR,OAAO,KAAKrB,kBAAkB,CAAC8B,OAAO,CAACC,OAAO,EAAE;YAClD,MAAMzB,SAAS,CAACc,SAAS,CAACH,UAAU,CAAC;UACvC,CAAC,MAAM;YACL,MAAM,IAAIR,KAAK,CAAC,kCAAkC,CAAC;UACrD;QACF;MACF,CAAC,CAAC,OAAOuB,GAAG,EAAE;QACZ,MAAMA,GAAG;MACX,CAAC,SAAS;QACR1B,SAAS,CAAC2B,UAAU,CAAC,CAAC;MACxB;IACF,CAAC,MAAM;MACL3B,SAAS,CAAC2B,UAAU,CAAC,CAAC;IACxB;EACF;AACF;AAEA,OAAO,SAASC,YAAYA,CAACvB,SAAiB,EAAoB;EAChE,OAAOL,SAAS,CAAC4B,YAAY,CAACvB,SAAS,CAAC;AAC1C"}
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
export interface EditorConfig {
|
|
2
2
|
saveToPhoto?: boolean;
|
|
3
3
|
maxDuration?: number;
|
|
4
|
+
title?: string;
|
|
5
|
+
leftButtonText?: string;
|
|
6
|
+
rightButtonText?: string;
|
|
4
7
|
}
|
|
5
8
|
export declare function showEditor(videoPath: string, config?: EditorConfig): Promise<void>;
|
|
6
9
|
export declare function isValidVideo(videoPath: string): Promise<boolean>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.tsx"],"names":[],"mappings":"AAmBA,MAAM,WAAW,YAAY;IAC3B,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.tsx"],"names":[],"mappings":"AAmBA,MAAM,WAAW,YAAY;IAC3B,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,wBAAsB,UAAU,CAC9B,SAAS,EAAE,MAAM,EACjB,MAAM,GAAE,YAAiB,GACxB,OAAO,CAAC,IAAI,CAAC,CAoCf;AAED,wBAAgB,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAEhE"}
|
package/package.json
CHANGED
package/src/index.tsx
CHANGED
|
@@ -20,38 +20,48 @@ const VideoTrim = NativeModules.VideoTrim
|
|
|
20
20
|
export interface EditorConfig {
|
|
21
21
|
saveToPhoto?: boolean;
|
|
22
22
|
maxDuration?: number;
|
|
23
|
+
title?: string;
|
|
24
|
+
leftButtonText?: string;
|
|
25
|
+
rightButtonText?: string;
|
|
23
26
|
}
|
|
24
27
|
|
|
25
28
|
export async function showEditor(
|
|
26
29
|
videoPath: string,
|
|
27
30
|
config: EditorConfig = {}
|
|
28
31
|
): Promise<void> {
|
|
29
|
-
const {
|
|
30
|
-
const outputPath = await VideoTrim.showEditor(videoPath,
|
|
31
|
-
saveToPhoto,
|
|
32
|
-
maxDuration,
|
|
33
|
-
});
|
|
32
|
+
const { saveToPhoto = true } = config;
|
|
33
|
+
const outputPath = await VideoTrim.showEditor(videoPath, config);
|
|
34
34
|
|
|
35
|
-
if (Platform.OS === 'android'
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
35
|
+
if (Platform.OS === 'android') {
|
|
36
|
+
if (saveToPhoto) {
|
|
37
|
+
try {
|
|
38
|
+
if (Platform.Version >= 33) {
|
|
39
|
+
// since android 13 it's not needed to request permission for write storage: https://github.com/facebook/react-native/issues/36714#issuecomment-1491338276
|
|
40
|
+
await VideoTrim.saveVideo(outputPath);
|
|
41
|
+
} else {
|
|
42
|
+
const granted = await PermissionsAndroid.request(
|
|
43
|
+
PermissionsAndroid.PERMISSIONS.WRITE_EXTERNAL_STORAGE!,
|
|
44
|
+
{
|
|
45
|
+
title: 'Video Trimmer Photos Access Required',
|
|
46
|
+
message: 'Grant access to your Photos to write output Video',
|
|
47
|
+
buttonNeutral: 'Ask Me Later',
|
|
48
|
+
buttonNegative: 'Cancel',
|
|
49
|
+
buttonPositive: 'OK',
|
|
50
|
+
}
|
|
51
|
+
);
|
|
52
|
+
if (granted === PermissionsAndroid.RESULTS.GRANTED) {
|
|
53
|
+
await VideoTrim.saveVideo(outputPath);
|
|
54
|
+
} else {
|
|
55
|
+
throw new Error('Photos Library permission denied');
|
|
56
|
+
}
|
|
45
57
|
}
|
|
46
|
-
)
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
} else {
|
|
58
|
+
} catch (err) {
|
|
59
|
+
throw err;
|
|
60
|
+
} finally {
|
|
50
61
|
VideoTrim.hideDialog();
|
|
51
|
-
throw new Error('Photos Library permission denied');
|
|
52
62
|
}
|
|
53
|
-
}
|
|
54
|
-
|
|
63
|
+
} else {
|
|
64
|
+
VideoTrim.hideDialog();
|
|
55
65
|
}
|
|
56
66
|
}
|
|
57
67
|
}
|