shakebug-react-native 2.4.9 → 2.4.10
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 +0 -12
- package/VideoPlayer/PlayVideo.tsx +4 -46
- package/VideoPlayer/index.js +6 -43
- package/android/src/main/java/com/shakebug/BaseUtils.java +7 -19
- package/android/src/main/java/com/shakebug/DeviceUtil.java +34 -21
- package/android/src/main/java/com/shakebug/ShakebugPackage.java +3 -3
- package/android/src/main/java/com/shakebug/UnitConverter.java +8 -8
- package/android/src/main/java/com/shakebug/VideoPlayerModule.java +81 -0
- package/android/src/main/java/com/shakebug/VideoTrimModule.java +387 -0
- package/android/src/main/java/com/shakebug/VideoTrimUtil.java +133 -0
- package/android/src/main/java/com/shakebug/adapters/VideoTrimmerAdapter.java +53 -0
- package/android/src/main/java/com/shakebug/callback/SingleCallback.java +0 -6
- package/android/src/main/java/com/shakebug/thread/BackgroundExecutor.java +1 -93
- package/android/src/main/java/com/shakebug/thread/UiThreadExecutor.java +0 -37
- package/android/src/main/java/com/shakebug/utils/StorageUtil.java +135 -0
- package/android/src/main/java/com/shakebug/utils/VideoTrimmerUtil.java +70 -0
- package/android/src/main/java/com/shakebug/widgets/RangeSeekBarView.java +534 -0
- package/android/src/main/java/com/shakebug/widgets/SpacesItemDecoration2.java +1 -2
- package/android/src/main/java/com/shakebug/widgets/VideoPlayerView.java +317 -0
- package/android/src/main/java/com/shakebug/widgets/VideoTrimmerView.java +520 -0
- package/android/src/main/res/drawable/ic_volume_off.xml +10 -0
- package/android/src/main/res/drawable/ic_volume_on.xml +10 -0
- package/android/src/main/res/layout/{video_player_view.xml → shakebug_video_player_view.xml} +29 -9
- package/ios/TrimVideo/ShakebugSDKVideoTrim.swift +389 -0
- package/ios/TrimVideo/VideoTrim-Bridging-Header.h +10 -0
- package/ios/TrimVideo/VideoTrim.m +23 -0
- package/ios/TrimVideo/VideoTrimmer.swift +810 -0
- package/ios/TrimVideo/VideoTrimmerThumb.swift +119 -0
- package/ios/TrimVideo/VideoTrimmerViewController.swift +322 -0
- package/ios/VideoPlayer/VideoPlayerModule.m +23 -7
- package/package.json +1 -1
- package/src/Componanats/LoadingModal.js +59 -0
- package/src/Componanats/ShakeFunction.js +2 -10
- package/src/Screens/AddDetailsScreen.js +28 -31
- package/src/Screens/FirstScreen.js +15 -18
- package/src/Screens/Shakebug.js +1 -1
- package/src/Screens/TrimVideoScreen.js +37 -22
- package/src/index.tsx +4 -4
- package/trimVideo/src/index.tsx +12 -48
- package/shakebug-react-native-2.4.8.tgz +0 -0
- /package/android/src/main/res/layout/{video_thumb_item_layout.xml → shakebug_video_thumb_item_layout.xml} +0 -0
- /package/android/src/main/res/layout/{video_trimmer_view.xml → shakebug_video_trimmer_view.xml} +0 -0
|
@@ -12,6 +12,7 @@ import { ScrollView } from 'react-native';
|
|
|
12
12
|
import KeyboardAvoidingWrapper from '../Componanats/KeyboardAvoidingWrapper';
|
|
13
13
|
import { useGlobalState } from '../Componanats/GlobalStateContext';
|
|
14
14
|
import CustomeAlert from '../Componanats/CustomAlert';
|
|
15
|
+
import LoadingModal from '../Componanats/LoadingModal';
|
|
15
16
|
import NetInfo from '../../NetInfo/src';
|
|
16
17
|
import DeviceInfo from '../../DeviceInfo';
|
|
17
18
|
|
|
@@ -92,10 +93,11 @@ const AddDetailsScreen = ({ media, updateParent, mediaType, themeColor, SDKScree
|
|
|
92
93
|
try {
|
|
93
94
|
|
|
94
95
|
const { create: createThumbnail } = CreateThumbnail;
|
|
96
|
+
const cleanVideoPath = path ? path.replace('file://', '') : '';
|
|
95
97
|
|
|
96
98
|
const thumbnail = await createThumbnail({
|
|
97
|
-
url: `file://${
|
|
98
|
-
timeStamp:
|
|
99
|
+
url: `file://${cleanVideoPath}`,
|
|
100
|
+
timeStamp: 1000,
|
|
99
101
|
})
|
|
100
102
|
|
|
101
103
|
if (thumbnail) {
|
|
@@ -145,6 +147,7 @@ const AddDetailsScreen = ({ media, updateParent, mediaType, themeColor, SDKScree
|
|
|
145
147
|
// For open Video picker
|
|
146
148
|
const openVideoPicker = () => {
|
|
147
149
|
global.IsBackground = "false"
|
|
150
|
+
setIsLoading(true)
|
|
148
151
|
|
|
149
152
|
const options = {
|
|
150
153
|
mediaType: 'video',
|
|
@@ -153,26 +156,26 @@ const AddDetailsScreen = ({ media, updateParent, mediaType, themeColor, SDKScree
|
|
|
153
156
|
};
|
|
154
157
|
|
|
155
158
|
launchImageLibrary(options, async (response) => {
|
|
156
|
-
setIsLoading(true)
|
|
157
159
|
if (response.didCancel) {
|
|
158
160
|
setIsLoading(false)
|
|
159
|
-
global.IsBackground = "
|
|
161
|
+
global.IsBackground = "false"
|
|
160
162
|
// console.log('User cancelled image picker');
|
|
161
|
-
} else if (response.error) {
|
|
163
|
+
} else if (response.error || response.errorCode) {
|
|
162
164
|
setIsLoading(false)
|
|
163
165
|
global.IsBackground = "true"
|
|
164
166
|
// console.log('Image picker error: ', response.error);
|
|
165
167
|
} else {
|
|
166
|
-
setIsLoading(false)
|
|
167
168
|
global.IsBackground = "true"
|
|
168
169
|
let videoUri = await response.uri || response.assets?.[0]?.uri;
|
|
169
|
-
if (response.assets?.[0]?.type
|
|
170
|
+
if (response.assets?.[0]?.type?.slice(0, 5).trim() == "video") {
|
|
170
171
|
if (mediaType == "img")
|
|
171
172
|
navigate("TrimVideoScreen", { video: `${videoUri}`, Type: "imgReplacedWithVideo", themeColor: ThemeColor, SDKScreenTitle: SDKScreenTitle, UpdateStatusBar: UpdateStatusBar, updateParent: updateParent })
|
|
172
173
|
else
|
|
173
174
|
navigate("TrimVideoScreen", { video: `${videoUri}`, Type: "videoReplacedWithVideo", themeColor: ThemeColor, SDKScreenTitle: SDKScreenTitle, UpdateStatusBar: UpdateStatusBar, updateParent: updateParent })
|
|
175
|
+
setIsLoading(false)
|
|
174
176
|
}
|
|
175
177
|
else {
|
|
178
|
+
setIsLoading(false)
|
|
176
179
|
setAPIMessage("Invalid selection, Please choose a valid video file")
|
|
177
180
|
setErrorInAPI(true)
|
|
178
181
|
}
|
|
@@ -184,25 +187,24 @@ const AddDetailsScreen = ({ media, updateParent, mediaType, themeColor, SDKScree
|
|
|
184
187
|
// For open image picker
|
|
185
188
|
const openImagePicker = () => {
|
|
186
189
|
global.IsBackground = "false"
|
|
190
|
+
setIsLoading(true)
|
|
187
191
|
const options = {
|
|
188
192
|
mediaType: 'photo',
|
|
189
193
|
includeBase64: false,
|
|
190
194
|
selectionLimit: 1
|
|
191
195
|
};
|
|
192
196
|
launchImageLibrary(options, async (response) => {
|
|
193
|
-
setIsLoading(true)
|
|
194
197
|
if (response.didCancel) {
|
|
195
198
|
setIsLoading(false)
|
|
196
199
|
global.IsBackground = "true"
|
|
197
200
|
// console.log('User cancelled image picker');
|
|
198
|
-
} else if (response.error) {
|
|
201
|
+
} else if (response.error || response.errorCode) {
|
|
199
202
|
setIsLoading(false)
|
|
200
203
|
global.IsBackground = "true"
|
|
201
204
|
// console.log('Image picker error: ', response.error);
|
|
202
205
|
} else {
|
|
203
|
-
|
|
204
206
|
global.IsBackground = "true"
|
|
205
|
-
if (response.assets?.[0]?.type
|
|
207
|
+
if (response.assets?.[0]?.type?.slice(0, 5).trim() == "image") {
|
|
206
208
|
let imageuri = await response.uri || response.assets?.[0]?.uri;
|
|
207
209
|
setIsLoading(false)
|
|
208
210
|
if (imageuri != "" || imageuri != undefined) {
|
|
@@ -217,6 +219,7 @@ const AddDetailsScreen = ({ media, updateParent, mediaType, themeColor, SDKScree
|
|
|
217
219
|
}
|
|
218
220
|
}
|
|
219
221
|
else {
|
|
222
|
+
setIsLoading(false)
|
|
220
223
|
setAPIMessage("Invalid selection, Please choose a valid image file")
|
|
221
224
|
setErrorInAPI(true)
|
|
222
225
|
}
|
|
@@ -285,13 +288,18 @@ const AddDetailsScreen = ({ media, updateParent, mediaType, themeColor, SDKScree
|
|
|
285
288
|
}
|
|
286
289
|
|
|
287
290
|
return (
|
|
288
|
-
<
|
|
291
|
+
<View style={{ flex: 1, backgroundColor: '#fff' }}>
|
|
289
292
|
<StatusBar backgroundColor={ThemeColor} hidden={false} barStyle="dark-content" />
|
|
290
|
-
<
|
|
291
|
-
|
|
292
|
-
backgroundColor:
|
|
293
|
-
|
|
294
|
-
}}>
|
|
293
|
+
<SafeAreaView style={{ flex: 0, backgroundColor: ThemeColor }} />
|
|
294
|
+
{Platform.OS === 'android' && StatusBar.currentHeight ? (
|
|
295
|
+
<View style={{ height: StatusBar.currentHeight, backgroundColor: ThemeColor }} />
|
|
296
|
+
) : null}
|
|
297
|
+
<SafeAreaView style={{ flex: 1, backgroundColor: '#fff' }}>
|
|
298
|
+
<View style={{
|
|
299
|
+
flex: 1,
|
|
300
|
+
backgroundColor: "#fff",
|
|
301
|
+
paddingBottom: Platform.OS === 'android' ? 48 : 0 // Standard bottom navigation bar height
|
|
302
|
+
}}>
|
|
295
303
|
<KeyboardAvoidingWrapper>
|
|
296
304
|
<>
|
|
297
305
|
<View style={{ height: '6%', padding: 5, paddingHorizontal: 15, backgroundColor: ThemeColor, flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between' }}>
|
|
@@ -436,7 +444,7 @@ const AddDetailsScreen = ({ media, updateParent, mediaType, themeColor, SDKScree
|
|
|
436
444
|
<CustomeAlert
|
|
437
445
|
isVisible={isErrorInAPI || isBugReported}
|
|
438
446
|
text={apiMessage}
|
|
439
|
-
color={
|
|
447
|
+
color={ThemeColor}
|
|
440
448
|
OnPrees={() => {
|
|
441
449
|
if (isBugReported) {
|
|
442
450
|
global.isScreenShotDetected = false;
|
|
@@ -449,24 +457,13 @@ const AddDetailsScreen = ({ media, updateParent, mediaType, themeColor, SDKScree
|
|
|
449
457
|
setIsLoading(false)
|
|
450
458
|
}}
|
|
451
459
|
/>
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
{isLoading &&
|
|
455
|
-
<View
|
|
456
|
-
style={{
|
|
457
|
-
...StyleSheet.absoluteFillObject,
|
|
458
|
-
backgroundColor: 'rgba(0, 0, 0, 0.4)',
|
|
459
|
-
}}
|
|
460
|
-
/>
|
|
461
|
-
}
|
|
462
|
-
|
|
463
|
-
{isLoading &&
|
|
464
|
-
<ActivityIndicator size={'large'} color={themeColor} collapsable={true} style={{ position: 'absolute', top: 0, bottom: 0, left: 0, right: 0, elevation: 2 }} />}
|
|
465
460
|
</>
|
|
466
461
|
</KeyboardAvoidingWrapper>
|
|
467
462
|
</View>
|
|
468
463
|
|
|
469
464
|
</SafeAreaView>
|
|
465
|
+
<LoadingModal visible={isLoading} color={ThemeColor} />
|
|
466
|
+
</View>
|
|
470
467
|
)
|
|
471
468
|
}
|
|
472
469
|
|
|
@@ -11,6 +11,7 @@ import { ActivityIndicator } from 'react-native';
|
|
|
11
11
|
import DeviceInfo from '../../DeviceInfo';
|
|
12
12
|
import { useGlobalState } from '../Componanats/GlobalStateContext.js';
|
|
13
13
|
import CustomeAlert from '../Componanats/CustomAlert.js';
|
|
14
|
+
import LoadingModal from '../Componanats/LoadingModal.js';
|
|
14
15
|
|
|
15
16
|
console.disableYellowBox = true;
|
|
16
17
|
console.ignoredYellowBox = ["Warning: Each", "Warning: Failed", "Possible"];
|
|
@@ -108,6 +109,7 @@ const FirstScreen = ({ img, themeColor, SDKScreenTitle }) => {
|
|
|
108
109
|
|
|
109
110
|
// open Video picker to choose video
|
|
110
111
|
const openVideoPicker = () => {
|
|
112
|
+
setIsLoading(true)
|
|
111
113
|
const options = {
|
|
112
114
|
mediaType: 'video',
|
|
113
115
|
includeBase64: false,
|
|
@@ -115,19 +117,19 @@ const FirstScreen = ({ img, themeColor, SDKScreenTitle }) => {
|
|
|
115
117
|
};
|
|
116
118
|
|
|
117
119
|
launchImageLibrary(options, async (response) => {
|
|
118
|
-
setIsLoading(true)
|
|
119
120
|
if (response.didCancel) {
|
|
120
121
|
setIsLoading(false)
|
|
121
|
-
} else if (response.error) {
|
|
122
|
+
} else if (response.error || response.errorCode) {
|
|
122
123
|
setIsLoading(false)
|
|
123
124
|
// console.log('Image picker error: ', response.error);
|
|
124
125
|
} else {
|
|
125
126
|
let vedioUri = await response.uri || response.assets?.[0]?.uri;
|
|
126
|
-
if (response.assets?.[0]?.type
|
|
127
|
+
if (response.assets?.[0]?.type?.slice(0, 5).trim() == "video") {
|
|
127
128
|
setIsLoading(false)
|
|
128
129
|
navigate("TrimVideoScreen", { video: `${vedioUri}`, Type: "video", themeColor: `${ThemeColor}`, SDKScreenTitle: `${SDKScreenTitle}`, UpdateStatusBar: UpdateStatusBar, updateParent: updateImage })
|
|
129
130
|
}
|
|
130
131
|
else {
|
|
132
|
+
setIsLoading(false)
|
|
131
133
|
setIsAlertText("Invalid selection, Please choose a valid video file")
|
|
132
134
|
setIsAlert(true)
|
|
133
135
|
}
|
|
@@ -310,9 +312,13 @@ const FirstScreen = ({ img, themeColor, SDKScreenTitle }) => {
|
|
|
310
312
|
// backgroundColor: "#181818"
|
|
311
313
|
|
|
312
314
|
return (
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
315
|
+
<View style={{ flex: 1, backgroundColor: '#fff' }}>
|
|
316
|
+
<StatusBar backgroundColor={ThemeColor} barStyle="dark-content" />
|
|
317
|
+
<SafeAreaView style={{ flex: 0, backgroundColor: ThemeColor }} />
|
|
318
|
+
{Platform.OS === 'android' && StatusBar.currentHeight ? (
|
|
319
|
+
<View style={{ height: StatusBar.currentHeight, backgroundColor: ThemeColor }} />
|
|
320
|
+
) : null}
|
|
321
|
+
<SafeAreaView style={{ flex: 1, backgroundColor: '#fff' }}>
|
|
316
322
|
<View style={{
|
|
317
323
|
flex: 1,
|
|
318
324
|
backgroundColor: "#e4fdfd",
|
|
@@ -547,28 +553,19 @@ const FirstScreen = ({ img, themeColor, SDKScreenTitle }) => {
|
|
|
547
553
|
</KeyboardAvoidingView>
|
|
548
554
|
</View>) : null}
|
|
549
555
|
|
|
550
|
-
{isLoading &&
|
|
551
|
-
<View
|
|
552
|
-
style={{
|
|
553
|
-
...StyleSheet.absoluteFillObject,
|
|
554
|
-
backgroundColor: 'rgba(0, 0, 0, 0.4)',
|
|
555
|
-
}}
|
|
556
|
-
/>
|
|
557
|
-
}
|
|
558
|
-
|
|
559
556
|
<CustomeAlert
|
|
560
557
|
isVisible={isAlert}
|
|
561
558
|
text={isAlertText}
|
|
562
|
-
color={
|
|
559
|
+
color={ThemeColor}
|
|
563
560
|
OnPrees={() => {
|
|
564
561
|
setIsAlert(false)
|
|
565
562
|
setIsAlertText("")
|
|
566
563
|
}}
|
|
567
564
|
/>
|
|
568
565
|
|
|
569
|
-
{isLoading && <ActivityIndicator size={'large'} color={themeColor} collapsable={true} style={{ position: 'absolute', top: 0, bottom: 0, left: 0, right: 0, elevation: 2 }} />}
|
|
570
|
-
|
|
571
566
|
</SafeAreaView>
|
|
567
|
+
<LoadingModal visible={isLoading} color={ThemeColor} />
|
|
568
|
+
</View>
|
|
572
569
|
)
|
|
573
570
|
}
|
|
574
571
|
|
package/src/Screens/Shakebug.js
CHANGED
|
@@ -63,7 +63,7 @@ global.isScreeenShotTaken = false;
|
|
|
63
63
|
global.restrictedViews = [];
|
|
64
64
|
global.currentScreen = ""
|
|
65
65
|
global.isShakebugSDKOpen = false;
|
|
66
|
-
global.sdk_version = "2.4.
|
|
66
|
+
global.sdk_version = "2.4.10";
|
|
67
67
|
global.app_lunch_count = 0;
|
|
68
68
|
global.POPUP_LAUNCH_THRESHOLD = 3;
|
|
69
69
|
global.POPUP_COOLDOWN_DAYS = 2;
|
|
@@ -1,26 +1,27 @@
|
|
|
1
|
-
import { NativeEventEmitter, NativeModules, Platform, SafeAreaView, StatusBar } from 'react-native'
|
|
1
|
+
import { DeviceEventEmitter, NativeEventEmitter, NativeModules, Platform, SafeAreaView, StatusBar, View } from 'react-native'
|
|
2
2
|
import React, { useEffect, useState } from 'react'
|
|
3
|
-
import { showEditor } from '
|
|
3
|
+
import { showEditor } from '../../trimVideo/src/index';
|
|
4
4
|
import { useNavigation } from '../Componanats/NavigationContext';
|
|
5
5
|
import { Localization } from '../Componanats/localization';
|
|
6
|
+
import LoadingModal from '../Componanats/LoadingModal';
|
|
6
7
|
|
|
7
8
|
console.ignoredYellowBox = ["Warning: Each", "Warning: Failed"];
|
|
8
9
|
|
|
9
|
-
|
|
10
|
-
|
|
11
10
|
const TrimVideoScreen = ({ video, themeColor, SDKScreenTitle, Type, UpdateStatusBar, updateParent }) => {
|
|
12
11
|
|
|
13
12
|
const { goToScreenAtIndex, navigate, goBack } = useNavigation();
|
|
13
|
+
const [loading, setLoading] = useState(true);
|
|
14
14
|
|
|
15
|
+
const ThemeColor = themeColor ? themeColor : "#1dd3e3";
|
|
15
16
|
|
|
16
17
|
// For display video trimmer
|
|
17
18
|
useEffect(() => {
|
|
18
19
|
StatusBar.setHidden(true)
|
|
19
20
|
|
|
20
21
|
const uri = video; // your path
|
|
21
|
-
const
|
|
22
|
+
const cleanUri = uri.replace('file://', '');
|
|
22
23
|
|
|
23
|
-
showEditor(
|
|
24
|
+
showEditor(cleanUri, {
|
|
24
25
|
saveButtonText: Localization[global.ShakebugLanguage].Choose,
|
|
25
26
|
cancelButtonText: Localization[global.ShakebugLanguage].Cancel,
|
|
26
27
|
trimmingText: Localization[global.ShakebugLanguage].TrimmingText,
|
|
@@ -38,50 +39,64 @@ const TrimVideoScreen = ({ video, themeColor, SDKScreenTitle, Type, UpdateStatus
|
|
|
38
39
|
saveDialogConfirmText: Localization[global.ShakebugLanguage].Yes
|
|
39
40
|
});
|
|
40
41
|
|
|
41
|
-
const
|
|
42
|
-
const subscription = eventEmitter.addListener('VideoTrim', (event) => {
|
|
42
|
+
const handleVideoTrimEvent = (event) => {
|
|
43
43
|
switch (event.name) {
|
|
44
44
|
case 'onShow': {
|
|
45
|
+
setLoading(false);
|
|
45
46
|
break;
|
|
46
47
|
}
|
|
47
48
|
case 'onHide': {
|
|
48
49
|
break;
|
|
49
50
|
}
|
|
50
51
|
case 'onStartTrimming': {
|
|
52
|
+
// The native side displays "Trimming video..." dialog, so we don't need a React Native loader here
|
|
51
53
|
break;
|
|
52
54
|
}
|
|
53
55
|
case 'onFinishTrimming': {
|
|
54
|
-
global.IsBackground = 'true'
|
|
55
|
-
UpdateStatusBar()
|
|
56
|
+
global.IsBackground = 'true';
|
|
57
|
+
UpdateStatusBar();
|
|
56
58
|
navigate("AddDetailsScreen", { media: `${event.outputPath}`, mediaType: 'video', themeColor: themeColor, SDKScreenTitle: SDKScreenTitle, updateParent: updateParent });
|
|
57
59
|
return;
|
|
58
60
|
}
|
|
59
61
|
case 'onCancel': {
|
|
60
|
-
UpdateStatusBar()
|
|
62
|
+
UpdateStatusBar();
|
|
61
63
|
if (Type == "video") {
|
|
62
|
-
goToScreenAtIndex(1)
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
else if (Type == "videoReplacedWithVideo") {
|
|
68
|
-
goToScreenAtIndex(3)
|
|
64
|
+
goToScreenAtIndex(1);
|
|
65
|
+
} else if (Type == "imgReplacedWithVideo") {
|
|
66
|
+
goBack();
|
|
67
|
+
} else if (Type == "videoReplacedWithVideo") {
|
|
68
|
+
goToScreenAtIndex(3);
|
|
69
69
|
}
|
|
70
70
|
return;
|
|
71
|
-
break;
|
|
72
71
|
}
|
|
73
72
|
case 'onError': {
|
|
73
|
+
setLoading(false);
|
|
74
74
|
break;
|
|
75
75
|
}
|
|
76
76
|
}
|
|
77
|
-
}
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
let subscription;
|
|
80
|
+
if (Platform.OS === 'android') {
|
|
81
|
+
subscription = DeviceEventEmitter.addListener('VideoTrim', handleVideoTrimEvent);
|
|
82
|
+
} else {
|
|
83
|
+
const videoTrimModule = NativeModules.ShakebugSDKVideoTrim || NativeModules.VideoTrim;
|
|
84
|
+
const eventEmitter = new NativeEventEmitter(videoTrimModule);
|
|
85
|
+
subscription = eventEmitter.addListener('VideoTrim', handleVideoTrimEvent);
|
|
86
|
+
}
|
|
78
87
|
|
|
79
88
|
return () => {
|
|
80
|
-
subscription.remove
|
|
89
|
+
if (subscription && subscription.remove) {
|
|
90
|
+
subscription.remove();
|
|
91
|
+
}
|
|
81
92
|
};
|
|
82
93
|
}, [])
|
|
83
94
|
|
|
84
|
-
return
|
|
95
|
+
return (
|
|
96
|
+
<View style={{ flex: 1, backgroundColor: '#000', justifyContent: 'center', alignItems: 'center' }}>
|
|
97
|
+
<LoadingModal visible={loading} color={ThemeColor} />
|
|
98
|
+
</View>
|
|
99
|
+
);
|
|
85
100
|
}
|
|
86
101
|
|
|
87
102
|
export default TrimVideoScreen;
|
package/src/index.tsx
CHANGED
|
@@ -22,10 +22,10 @@ export interface ShakebugViewProps {
|
|
|
22
22
|
changeSDKScreenTitle?: string[];
|
|
23
23
|
allowToReportBugByShakingMobile?: boolean;
|
|
24
24
|
allowToReportBugByScreenCapture?: boolean;
|
|
25
|
-
allowCrashReport
|
|
26
|
-
makeLogEnabled
|
|
27
|
-
ShakebugLanguage
|
|
28
|
-
setShakebugSDKEndPointURL
|
|
25
|
+
allowCrashReport?: boolean;
|
|
26
|
+
makeLogEnabled?: boolean;
|
|
27
|
+
ShakebugLanguage?: 'ENGLISH' | 'HINDI' | 'GUJARATI' | 'ARABIC' | 'CHINESE' | 'DUTCH' | 'FRENCH' | 'GERMAN' | 'GREEK' | 'INDONESIAN' | 'ITALIAN' | 'JAPANESE' | 'KOREAN' | 'RUSSIAN' | 'SPANISH' | 'TURKISH' | 'UKRAINIAN' | 'MARATHI' | 'TAMIL' | 'TELUGU';
|
|
28
|
+
setShakebugSDKEndPointURL?: string[];
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
|
package/trimVideo/src/index.tsx
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { NativeModules, PermissionsAndroid, Platform } from 'react-native';
|
|
2
2
|
|
|
3
3
|
const LINKING_ERROR =
|
|
4
|
-
`The
|
|
4
|
+
`The native module 'ShakebugSDKVideoTrim' is not linked. Make sure: \n\n` +
|
|
5
5
|
Platform.select({ ios: "- You have run 'pod install'\n", default: '' }) +
|
|
6
6
|
'- You rebuilt the app after installing the package\n' +
|
|
7
7
|
'- You are not using Expo Go\n';
|
|
8
8
|
|
|
9
|
-
const VideoTrim = NativeModules.ShakebugSDKVideoTrim
|
|
10
|
-
? NativeModules.ShakebugSDKVideoTrim
|
|
9
|
+
const VideoTrim = NativeModules.ShakebugSDKVideoTrim || NativeModules.VideoTrim
|
|
10
|
+
? (NativeModules.ShakebugSDKVideoTrim || NativeModules.VideoTrim)
|
|
11
11
|
: new Proxy(
|
|
12
12
|
{},
|
|
13
13
|
{
|
|
@@ -21,6 +21,7 @@ export interface EditorConfig {
|
|
|
21
21
|
saveToPhoto?: boolean;
|
|
22
22
|
removeAfterSavedToPhoto?: boolean;
|
|
23
23
|
maxDuration?: number;
|
|
24
|
+
minDuration?: number;
|
|
24
25
|
cancelButtonText?: string;
|
|
25
26
|
saveButtonText?: string;
|
|
26
27
|
enableCancelDialog?: boolean;
|
|
@@ -34,15 +35,9 @@ export interface EditorConfig {
|
|
|
34
35
|
saveDialogCancelText?: string;
|
|
35
36
|
saveDialogConfirmText?: string;
|
|
36
37
|
trimmingText?: string;
|
|
38
|
+
fullScreenModalIOS?: boolean;
|
|
37
39
|
}
|
|
38
40
|
|
|
39
|
-
/**
|
|
40
|
-
* Delete a file
|
|
41
|
-
*
|
|
42
|
-
* @param {string} videoPath: absolute non-empty file path to edit
|
|
43
|
-
* @param {EditorConfig} config: editor configuration
|
|
44
|
-
* @returns {void} A **Promise** which resolves `void`
|
|
45
|
-
*/
|
|
46
41
|
export async function showEditor(
|
|
47
42
|
filePath: string,
|
|
48
43
|
config: EditorConfig = {}
|
|
@@ -54,19 +49,17 @@ export async function showEditor(
|
|
|
54
49
|
const { saveToPhoto = true } = config;
|
|
55
50
|
const outputPath = await VideoTrim.showEditor(filePath, config);
|
|
56
51
|
|
|
57
|
-
if (Platform.OS === 'android') {
|
|
52
|
+
if (Platform.OS === 'android' && outputPath) {
|
|
58
53
|
if (saveToPhoto) {
|
|
59
54
|
try {
|
|
60
55
|
if (Platform.Version >= 33) {
|
|
61
|
-
// since android 13 it's not needed to request permission for write storage: https://github.com/facebook/react-native/issues/36714#issuecomment-1491338276
|
|
62
56
|
await VideoTrim.saveVideo(outputPath);
|
|
63
|
-
|
|
64
57
|
if (config.removeAfterSavedToPhoto) {
|
|
65
58
|
deleteFile(outputPath);
|
|
66
59
|
}
|
|
67
60
|
} else {
|
|
68
61
|
const granted = await PermissionsAndroid.request(
|
|
69
|
-
PermissionsAndroid.PERMISSIONS.WRITE_EXTERNAL_STORAGE
|
|
62
|
+
PermissionsAndroid.PERMISSIONS.WRITE_EXTERNAL_STORAGE,
|
|
70
63
|
{
|
|
71
64
|
title: 'Video Trimmer Photos Access Required',
|
|
72
65
|
message: 'Grant access to your Photos to write output Video',
|
|
@@ -77,65 +70,36 @@ export async function showEditor(
|
|
|
77
70
|
);
|
|
78
71
|
if (granted === PermissionsAndroid.RESULTS.GRANTED) {
|
|
79
72
|
await VideoTrim.saveVideo(outputPath);
|
|
80
|
-
|
|
81
73
|
if (config.removeAfterSavedToPhoto) {
|
|
82
74
|
deleteFile(outputPath);
|
|
83
75
|
}
|
|
84
|
-
} else {
|
|
85
|
-
throw new Error('Photos Library permission denied');
|
|
86
76
|
}
|
|
87
77
|
}
|
|
88
78
|
} catch (err) {
|
|
89
|
-
|
|
79
|
+
console.warn(err);
|
|
90
80
|
} finally {
|
|
91
81
|
VideoTrim.hideDialog();
|
|
92
82
|
}
|
|
93
|
-
} else {
|
|
94
|
-
VideoTrim.hideDialog();
|
|
95
83
|
}
|
|
96
84
|
}
|
|
97
85
|
}
|
|
98
86
|
|
|
99
|
-
/**
|
|
100
|
-
* Delete a file
|
|
101
|
-
*
|
|
102
|
-
* @param {string} filePath: absolute non-empty file path to check if editable
|
|
103
|
-
* @returns {Promise} A **Promise** which resolves `true` if editable
|
|
104
|
-
*/
|
|
105
87
|
export function isValidVideo(filePath: string): Promise<boolean> {
|
|
106
|
-
if (!filePath?.trim().length) {
|
|
107
|
-
throw new Error('File path cannot be empty!');
|
|
108
|
-
}
|
|
109
88
|
return VideoTrim.isValidVideo(filePath);
|
|
110
89
|
}
|
|
111
90
|
|
|
112
|
-
/**
|
|
113
|
-
* Clean output files generated at all time
|
|
114
|
-
*
|
|
115
|
-
* @returns {Promise<string[]>} A **Promise** which resolves to array of files
|
|
116
|
-
*/
|
|
117
91
|
export function listFiles(): Promise<string[]> {
|
|
118
92
|
return VideoTrim.listFiles();
|
|
119
93
|
}
|
|
120
94
|
|
|
121
|
-
/**
|
|
122
|
-
* Clean output files generated at all time
|
|
123
|
-
*
|
|
124
|
-
* @returns {Promise} A **Promise** which resolves to number of deleted files
|
|
125
|
-
*/
|
|
126
95
|
export function cleanFiles(): Promise<number> {
|
|
127
96
|
return VideoTrim.cleanFiles();
|
|
128
97
|
}
|
|
129
98
|
|
|
130
|
-
/**
|
|
131
|
-
* Delete a file
|
|
132
|
-
*
|
|
133
|
-
* @param {string} filePath: absolute non-empty file path to delete
|
|
134
|
-
* @returns {Promise} A **Promise** which resolves `true` if successful
|
|
135
|
-
*/
|
|
136
99
|
export function deleteFile(filePath: string): Promise<boolean> {
|
|
137
|
-
if (!filePath?.trim().length) {
|
|
138
|
-
throw new Error('File path cannot be empty!');
|
|
139
|
-
}
|
|
140
100
|
return VideoTrim.deleteFile(filePath);
|
|
141
101
|
}
|
|
102
|
+
|
|
103
|
+
export function closeEditor(): void {
|
|
104
|
+
return VideoTrim.hideDialog();
|
|
105
|
+
}
|
|
Binary file
|
|
File without changes
|
/package/android/src/main/res/layout/{video_trimmer_view.xml → shakebug_video_trimmer_view.xml}
RENAMED
|
File without changes
|