shakebug-react-native 2.4.8 → 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/DrawingView.java +8 -3
- package/android/src/main/java/com/shakebug/RecordScreenModule.java +1 -2
- 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/ViewShot.java +5 -2
- 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/APIs/AddIssue.js +11 -1
- package/src/Componanats/CustomAlert.js +2 -6
- package/src/Componanats/ErrorHandler.js +10 -1
- package/src/Componanats/LoadingModal.js +59 -0
- package/src/Componanats/ShakeFunction.js +2 -10
- package/src/Screens/AddDetailsScreen.js +29 -33
- package/src/Screens/FirstScreen.js +15 -19
- package/src/Screens/Shakebug.js +18 -26
- package/src/Screens/TrimVideoScreen.js +37 -22
- package/src/index.tsx +4 -4
- package/trimVideo/src/index.tsx +12 -48
- /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,14 +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
|
-
|
|
295
|
-
|
|
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
|
+
}}>
|
|
296
303
|
<KeyboardAvoidingWrapper>
|
|
297
304
|
<>
|
|
298
305
|
<View style={{ height: '6%', padding: 5, paddingHorizontal: 15, backgroundColor: ThemeColor, flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between' }}>
|
|
@@ -427,7 +434,7 @@ const AddDetailsScreen = ({ media, updateParent, mediaType, themeColor, SDKScree
|
|
|
427
434
|
</TouchableOpacity>
|
|
428
435
|
</View>
|
|
429
436
|
|
|
430
|
-
<View style={{ alignItems: 'flex-end', marginHorizontal: 15, marginTop: '
|
|
437
|
+
<View style={{ alignItems: 'flex-end', marginHorizontal: 15, marginTop: '0.5%' }}>
|
|
431
438
|
<Text style={{ fontSize: 12, color: "gray", fontWeight: '300' }}>© <Text>ShakeBug v{global.sdk_version}</Text></Text>
|
|
432
439
|
</View>
|
|
433
440
|
|
|
@@ -437,7 +444,7 @@ const AddDetailsScreen = ({ media, updateParent, mediaType, themeColor, SDKScree
|
|
|
437
444
|
<CustomeAlert
|
|
438
445
|
isVisible={isErrorInAPI || isBugReported}
|
|
439
446
|
text={apiMessage}
|
|
440
|
-
color={
|
|
447
|
+
color={ThemeColor}
|
|
441
448
|
OnPrees={() => {
|
|
442
449
|
if (isBugReported) {
|
|
443
450
|
global.isScreenShotDetected = false;
|
|
@@ -450,24 +457,13 @@ const AddDetailsScreen = ({ media, updateParent, mediaType, themeColor, SDKScree
|
|
|
450
457
|
setIsLoading(false)
|
|
451
458
|
}}
|
|
452
459
|
/>
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
{isLoading &&
|
|
456
|
-
<View
|
|
457
|
-
style={{
|
|
458
|
-
...StyleSheet.absoluteFillObject,
|
|
459
|
-
backgroundColor: 'rgba(0, 0, 0, 0.4)',
|
|
460
|
-
}}
|
|
461
|
-
/>
|
|
462
|
-
}
|
|
463
|
-
|
|
464
|
-
{isLoading &&
|
|
465
|
-
<ActivityIndicator size={'large'} color={themeColor} collapsable={true} style={{ position: 'absolute', top: 0, bottom: 0, left: 0, right: 0, elevation: 2 }} />}
|
|
466
460
|
</>
|
|
467
461
|
</KeyboardAvoidingWrapper>
|
|
468
462
|
</View>
|
|
469
463
|
|
|
470
464
|
</SafeAreaView>
|
|
465
|
+
<LoadingModal visible={isLoading} color={ThemeColor} />
|
|
466
|
+
</View>
|
|
471
467
|
)
|
|
472
468
|
}
|
|
473
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,13 +312,16 @@ 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",
|
|
319
|
-
paddingTop: Platform.OS === 'android' ? StatusBar.currentHeight : 0,
|
|
320
325
|
paddingBottom: Platform.OS === 'android' ? 48 : 0 // Standard bottom navigation bar height
|
|
321
326
|
}}>
|
|
322
327
|
|
|
@@ -548,28 +553,19 @@ const FirstScreen = ({ img, themeColor, SDKScreenTitle }) => {
|
|
|
548
553
|
</KeyboardAvoidingView>
|
|
549
554
|
</View>) : null}
|
|
550
555
|
|
|
551
|
-
{isLoading &&
|
|
552
|
-
<View
|
|
553
|
-
style={{
|
|
554
|
-
...StyleSheet.absoluteFillObject,
|
|
555
|
-
backgroundColor: 'rgba(0, 0, 0, 0.4)',
|
|
556
|
-
}}
|
|
557
|
-
/>
|
|
558
|
-
}
|
|
559
|
-
|
|
560
556
|
<CustomeAlert
|
|
561
557
|
isVisible={isAlert}
|
|
562
558
|
text={isAlertText}
|
|
563
|
-
color={
|
|
559
|
+
color={ThemeColor}
|
|
564
560
|
OnPrees={() => {
|
|
565
561
|
setIsAlert(false)
|
|
566
562
|
setIsAlertText("")
|
|
567
563
|
}}
|
|
568
564
|
/>
|
|
569
565
|
|
|
570
|
-
{isLoading && <ActivityIndicator size={'large'} color={themeColor} collapsable={true} style={{ position: 'absolute', top: 0, bottom: 0, left: 0, right: 0, elevation: 2 }} />}
|
|
571
|
-
|
|
572
566
|
</SafeAreaView>
|
|
567
|
+
<LoadingModal visible={isLoading} color={ThemeColor} />
|
|
568
|
+
</View>
|
|
573
569
|
)
|
|
574
570
|
}
|
|
575
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;
|
|
@@ -101,33 +101,25 @@ const NavigationContainer = ({ screens, setFocusedScreen }) => {
|
|
|
101
101
|
);
|
|
102
102
|
}
|
|
103
103
|
|
|
104
|
-
const currentScreen =
|
|
105
|
-
navigationState[navigationState.length - 1];
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
const ScreenComponent = screens[currentScreen.name];
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
if (!ScreenComponent) {
|
|
112
|
-
return (
|
|
113
|
-
<View
|
|
114
|
-
style={{
|
|
115
|
-
flex: 1,
|
|
116
|
-
justifyContent: 'center',
|
|
117
|
-
alignItems: 'center',
|
|
118
|
-
backgroundColor: 'red',
|
|
119
|
-
}}
|
|
120
|
-
>
|
|
121
|
-
<Text style={{ color: 'white', fontSize: 20 }}>
|
|
122
|
-
Screen Not Found: {currentScreen.name}
|
|
123
|
-
</Text>
|
|
124
|
-
</View>
|
|
125
|
-
);
|
|
126
|
-
}
|
|
127
|
-
|
|
128
104
|
return (
|
|
129
105
|
<View style={{ flex: 1, backgroundColor: 'white' }}>
|
|
130
|
-
|
|
106
|
+
{navigationState.map((screen, index) => {
|
|
107
|
+
const ScreenComponent = screens[screen.name];
|
|
108
|
+
if (!ScreenComponent) return null;
|
|
109
|
+
|
|
110
|
+
const isFocused = index === navigationState.length - 1;
|
|
111
|
+
return (
|
|
112
|
+
<View
|
|
113
|
+
key={index}
|
|
114
|
+
style={[
|
|
115
|
+
StyleSheet.absoluteFillObject,
|
|
116
|
+
{ display: isFocused ? 'flex' : 'none', width: '100%', height: '100%' }
|
|
117
|
+
]}
|
|
118
|
+
>
|
|
119
|
+
<ScreenComponent {...(screen.params || {})} />
|
|
120
|
+
</View>
|
|
121
|
+
);
|
|
122
|
+
})}
|
|
131
123
|
</View>
|
|
132
124
|
);
|
|
133
125
|
};
|
|
@@ -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
|
+
}
|
|
File without changes
|
/package/android/src/main/res/layout/{video_trimmer_view.xml → shakebug_video_trimmer_view.xml}
RENAMED
|
File without changes
|