shakebug-react-native 2.1.0 → 2.2.1

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.
Files changed (44) hide show
  1. package/README.md +17 -1
  2. package/VideoPlayer/index.js +37 -23
  3. package/android/build.gradle +0 -1
  4. package/android/src/main/java/com/shakebug/CreateThumbnailModule.java +217 -0
  5. package/android/src/main/java/com/shakebug/NetInfoModule.java +1 -2
  6. package/android/src/main/java/com/shakebug/RNDeviceModule.java +1 -3
  7. package/android/src/main/java/com/shakebug/ShakebugPackage.java +10 -10
  8. package/android/src/main/java/com/shakebug/{Shakebug.java → ShakebugSensors.java} +16 -22
  9. package/ios/GetLocals/ShakebugSDKRNLocalize.h +1 -0
  10. package/ios/Thumbnaill/{VideoThumbnailManager.h → CreateThumbnail.h} +2 -1
  11. package/ios/Thumbnaill/CreateThumbnail.m +82 -0
  12. package/package.json +2 -5
  13. package/shakebug-react-native.podspec +0 -1
  14. package/src/APIs/AddIssue.js +13 -4
  15. package/src/APIs/AddReview.js +46 -0
  16. package/src/APIs/CustomUserId.js +47 -0
  17. package/src/APIs/Event.js +8 -3
  18. package/src/APIs/StartSession.js +6 -2
  19. package/src/Assets/images/solar_star-bold.png +0 -0
  20. package/src/Assets/images/solar_star-line-duotone.png +0 -0
  21. package/src/Componanats/ReviewModal.js +171 -0
  22. package/src/Componanats/ShakeFunction.js +6 -3
  23. package/src/Screens/AddDetailsScreen.js +14 -10
  24. package/src/Screens/FirstScreen.js +2 -2
  25. package/src/Screens/Shakebug.js +63 -6
  26. package/src/Screens/TrimVideoScreen.js +13 -7
  27. package/src/index.tsx +6 -2
  28. package/android/src/main/java/com/shakebug/ShakebugSDKScreenShotModule.java +0 -196
  29. package/android/src/main/java/com/shakebug/VideoPlayerModule.java +0 -199
  30. package/android/src/main/java/com/shakebug/VideoThumbnailModule.java +0 -215
  31. package/android/src/main/java/com/shakebug/VideoTrimModule.java +0 -372
  32. package/android/src/main/java/com/shakebug/adapters/VideoTrimmerAdapter.java +0 -54
  33. package/android/src/main/java/com/shakebug/utils/StorageUtil.java +0 -139
  34. package/android/src/main/java/com/shakebug/utils/VideoTrimmerUtil.java +0 -89
  35. package/android/src/main/java/com/shakebug/widgets/RangeSeekBarView.java +0 -534
  36. package/android/src/main/java/com/shakebug/widgets/VideoPlayerView.java +0 -429
  37. package/android/src/main/java/com/shakebug/widgets/VideoTrimmerView.java +0 -477
  38. package/ios/Thumbnaill/VideoThumbnailManager.m +0 -73
  39. package/ios/TrimVideo/ShakebugSDKVideoTrim.swift +0 -372
  40. package/ios/TrimVideo/VideoTrim-Bridging-Header.h +0 -10
  41. package/ios/TrimVideo/VideoTrim.m +0 -23
  42. package/ios/TrimVideo/VideoTrimmer.swift +0 -810
  43. package/ios/TrimVideo/VideoTrimmerThumb.swift +0 -119
  44. package/ios/TrimVideo/VideoTrimmerViewController.swift +0 -301
@@ -1,215 +0,0 @@
1
- package com.shakebug;
2
-
3
- import android.content.Context;
4
- import android.graphics.Bitmap;
5
- import android.graphics.BitmapFactory;
6
- import android.media.MediaMetadataRetriever;
7
- import android.net.Uri;
8
- import android.os.Build.VERSION;
9
- import android.text.TextUtils;
10
- import android.webkit.URLUtil;
11
-
12
- import com.facebook.react.bridge.Arguments;
13
- import com.facebook.react.bridge.GuardedResultAsyncTask;
14
- import com.facebook.react.bridge.Promise;
15
- import com.facebook.react.bridge.ReactApplicationContext;
16
- import com.facebook.react.bridge.ReactContext;
17
- import com.facebook.react.bridge.ReactContextBaseJavaModule;
18
- import com.facebook.react.bridge.ReactMethod;
19
- import com.facebook.react.bridge.ReadableMap;
20
- import com.facebook.react.bridge.WritableMap;
21
-
22
- import org.apache.commons.io.comparator.LastModifiedFileComparator;
23
-
24
- import java.io.File;
25
- import java.io.FileOutputStream;
26
- import java.io.IOException;
27
- import java.io.OutputStream;
28
- import java.io.UnsupportedEncodingException;
29
- import java.net.URLDecoder;
30
- import java.lang.ref.WeakReference;
31
- import java.util.Arrays;
32
- import java.util.HashMap;
33
- import java.util.Map;
34
- import java.util.UUID;
35
-
36
- public class VideoThumbnailModule extends ReactContextBaseJavaModule {
37
-
38
- private final ReactApplicationContext reactContext;
39
-
40
- public VideoThumbnailModule(ReactApplicationContext reactContext) {
41
- super(reactContext);
42
- this.reactContext = reactContext;
43
- }
44
-
45
- @Override
46
- public String getName() {
47
- return "ShakebugSDKCreateThumbnail";
48
- }
49
-
50
- @ReactMethod
51
- public void create(ReadableMap options, Promise promise) {
52
- new ProcessDataTask(reactContext, promise, options).execute();
53
- }
54
-
55
- private static class ProcessDataTask extends GuardedResultAsyncTask<ReadableMap> {
56
- private final WeakReference<Context> weakContext;
57
- private final Promise promise;
58
- private final ReadableMap options;
59
-
60
- protected ProcessDataTask(ReactContext reactContext, Promise promise, ReadableMap options) {
61
- super(reactContext.getExceptionHandler());
62
- this.weakContext = new WeakReference<>(reactContext.getApplicationContext());
63
- this.promise = promise;
64
- this.options = options;
65
- }
66
-
67
- @Override
68
- protected ReadableMap doInBackgroundGuarded() {
69
- String format = options.hasKey("format") ? options.getString("format") : "jpeg";
70
- String cacheName = options.hasKey("cacheName") ? options.getString("cacheName") : "";
71
-
72
- String thumbnailDir = weakContext.get().getApplicationContext().getCacheDir().getAbsolutePath() + "/thumbnails";
73
- File cacheDir = createDirIfNotExists(thumbnailDir);
74
- if (!TextUtils.isEmpty(cacheName)) {
75
- File file = new File(thumbnailDir, cacheName + "." + format);
76
- if (file.exists()) {
77
- WritableMap map = Arguments.createMap();
78
- map.putString("path", "file://" + file.getAbsolutePath());
79
- Bitmap image = BitmapFactory.decodeFile(file.getAbsolutePath());
80
- map.putDouble("size", image.getByteCount());
81
- map.putString("mime", "image/" + format);
82
- map.putDouble("width", image.getWidth());
83
- map.putDouble("height", image.getHeight());
84
- return map;
85
- }
86
- }
87
-
88
- String filePath = options.hasKey("url") ? options.getString("url") : "";
89
- int dirSize = options.hasKey("dirSize") ? options.getInt("dirSize") : 100;
90
- int timeStamp = options.hasKey("timeStamp") ? options.getInt("timeStamp") : 0;
91
- HashMap headers = options.hasKey("headers") ? options.getMap("headers").toHashMap() : new HashMap<String, String>();
92
- String fileName = TextUtils.isEmpty(cacheName) ? ("thumb-" + UUID.randomUUID().toString()) : cacheName + "." + format;
93
- OutputStream fOut = null;
94
- try {
95
- File file = new File(cacheDir, fileName);
96
- Context context = weakContext.get();
97
- Bitmap image = getBitmapAtTime(context, filePath, timeStamp, headers);
98
- file.createNewFile();
99
- fOut = new FileOutputStream(file);
100
-
101
- // 100 means no compression, the lower you go, the stronger the compression
102
- if (format.equals("png")) {
103
- image.compress(Bitmap.CompressFormat.PNG, 100, fOut);
104
- } else {
105
- image.compress(Bitmap.CompressFormat.JPEG, 90, fOut);
106
- }
107
-
108
- fOut.flush();
109
- fOut.close();
110
-
111
- long cacheDirSize = (long) dirSize * 1024 * 1024;
112
- long newSize = image.getByteCount() + getDirSize(cacheDir);
113
- // free up some cached data if size of cache dir exceeds CACHE_DIR_MAX_SIZE
114
- if (newSize > cacheDirSize) {
115
- cleanDir(cacheDir, cacheDirSize / 2);
116
- }
117
-
118
- WritableMap map = Arguments.createMap();
119
- map.putString("path", "file://" + file.getAbsolutePath());
120
- map.putDouble("size", image.getByteCount());
121
- map.putString("mime", "image/" + format);
122
- map.putDouble("width", image.getWidth());
123
- map.putDouble("height", image.getHeight());
124
- return map;
125
- } catch (Exception e) {
126
- promise.reject("CreateThumbnail_ERROR", e);
127
- }
128
- return null;
129
- }
130
-
131
- @Override
132
- protected void onPostExecuteGuarded(ReadableMap readableArray) {
133
- promise.resolve(readableArray);
134
- }
135
- }
136
-
137
- // delete previously added files one by one untill requred space is available
138
- private static void cleanDir(File dir, long bytes) {
139
- long bytesDeleted = 0;
140
- File[] files = dir.listFiles();
141
- Arrays.sort(files, LastModifiedFileComparator.LASTMODIFIED_COMPARATOR);
142
-
143
- for (File file : files) {
144
- bytesDeleted += file.length();
145
- file.delete();
146
-
147
- if (bytesDeleted >= bytes) {
148
- break;
149
- }
150
- }
151
- }
152
-
153
- private static File createDirIfNotExists(String path) {
154
- File dir = new File(path);
155
- if (dir.exists()) {
156
- return dir;
157
- }
158
-
159
- try {
160
- dir.mkdirs();
161
- // Add .nomedia to hide the thumbnail directory from gallery
162
- File noMedia = new File(path, ".nomedia");
163
- noMedia.createNewFile();
164
- } catch (IOException e) {
165
- e.printStackTrace();
166
- }
167
-
168
- return dir;
169
- }
170
-
171
- private static Bitmap getBitmapAtTime(Context context, String filePath, int time, Map headers) {
172
- MediaMetadataRetriever retriever = new MediaMetadataRetriever();
173
- if (URLUtil.isFileUrl(filePath)) {
174
- String decodedPath;
175
- try {
176
- decodedPath = URLDecoder.decode(filePath, "UTF-8");
177
- } catch (UnsupportedEncodingException e) {
178
- decodedPath = filePath;
179
- }
180
-
181
- retriever.setDataSource(decodedPath.replace("file://", ""));
182
- } else if (filePath.contains("content://")) {
183
- retriever.setDataSource(context, Uri.parse(filePath));
184
- } else {
185
- if (VERSION.SDK_INT < 14) {
186
- throw new IllegalStateException("Remote videos aren't supported on sdk_version < 14");
187
- }
188
- retriever.setDataSource(filePath, headers);
189
- }
190
-
191
- Bitmap image = retriever.getFrameAtTime(time * 1000, MediaMetadataRetriever.OPTION_CLOSEST_SYNC);
192
- try {
193
- retriever.release();
194
- } catch(IOException e) {
195
- e.printStackTrace();
196
- }
197
- if (image == null) {
198
- throw new IllegalStateException("File doesn't exist or not supported");
199
- }
200
- return image;
201
- }
202
-
203
- private static long getDirSize(File dir) {
204
- long size = 0;
205
- File[] files = dir.listFiles();
206
-
207
- for (File file : files) {
208
- if (file.isFile()) {
209
- size += file.length();
210
- }
211
- }
212
-
213
- return size;
214
- }
215
- }
@@ -1,372 +0,0 @@
1
- package com.shakebug;
2
-
3
- import static com.facebook.react.bridge.UiThreadUtil.runOnUiThread;
4
-
5
- import android.app.Activity;
6
- import android.content.res.ColorStateList;
7
- import android.graphics.Color;
8
- import android.media.MediaMetadataRetriever;
9
- import android.net.Uri;
10
- import android.os.Build;
11
- import android.view.Gravity;
12
- import android.view.ViewGroup;
13
- import android.widget.LinearLayout;
14
- import android.widget.ProgressBar;
15
- import android.widget.TextView;
16
-
17
- import androidx.annotation.NonNull;
18
- import androidx.annotation.Nullable;
19
- import androidx.appcompat.app.AlertDialog;
20
-
21
- import com.facebook.react.bridge.Arguments;
22
- import com.facebook.react.bridge.LifecycleEventListener;
23
- import com.facebook.react.bridge.Promise;
24
- import com.facebook.react.bridge.ReactApplicationContext;
25
- import com.facebook.react.bridge.ReactContext;
26
- import com.facebook.react.bridge.ReactContextBaseJavaModule;
27
- import com.facebook.react.bridge.ReactMethod;
28
- import com.facebook.react.bridge.ReadableMap;
29
- import com.facebook.react.bridge.WritableMap;
30
- import com.facebook.react.module.annotations.ReactModule;
31
- import com.facebook.react.modules.core.DeviceEventManagerModule;
32
- import com.shakebug.interfaces.VideoTrimListener;
33
- import com.shakebug.utils.StorageUtil;
34
- import com.shakebug.widgets.VideoTrimmerView;
35
-
36
- import java.io.IOException;
37
-
38
- @ReactModule(name = VideoTrimModule.NAME)
39
- public class VideoTrimModule extends ReactContextBaseJavaModule implements VideoTrimListener, LifecycleEventListener {
40
- public static final String NAME = "ShakebugSDKVideoTrim";
41
- private static Boolean isInit = false;
42
- private VideoTrimmerView trimmerView;
43
- private AlertDialog alertDialog;
44
- private AlertDialog mProgressDialog;
45
- private ProgressBar mProgressBar;
46
- private int listenerCount = 0;
47
-
48
- private Promise showEditorPromise;
49
-
50
- private boolean enableCancelDialog = true;
51
- private String cancelDialogTitle = "Warning!";
52
- private String cancelDialogMessage = "Are you sure want to cancel?";
53
- private String cancelDialogCancelText = "Close";
54
- private String cancelDialogConfirmText = "Proceed";
55
- private boolean enableSaveDialog = true;
56
- private String saveDialogTitle = "Confirmation!";
57
- private String saveDialogMessage = "Are you sure want to save?";
58
- private String saveDialogCancelText = "Close";
59
- private String saveDialogConfirmText = "Proceed";
60
- private String trimmingText = "Trimming video...";
61
-
62
- public VideoTrimModule(ReactApplicationContext reactContext) {
63
- super(reactContext);
64
- }
65
-
66
- @Override
67
- @NonNull
68
- public String getName() {
69
- return NAME;
70
- }
71
-
72
-
73
- @ReactMethod
74
- public void showEditor(String videoPath, ReadableMap config, Promise promise) {
75
- showEditorPromise = promise;
76
- if (trimmerView != null || alertDialog != null) {
77
- return;
78
- }
79
-
80
- if (!isValidVideo(videoPath)) {
81
- WritableMap map = Arguments.createMap();
82
- map.putString("message", "File is not a valid video");
83
- sendEvent(getReactApplicationContext(), "onError", map);
84
- return;
85
- }
86
-
87
- enableCancelDialog = config.hasKey("enableCancelDialog") ? config.getBoolean("enableCancelDialog") : true;
88
- cancelDialogTitle = config.hasKey("cancelDialogTitle") ? config.getString("cancelDialogTitle") : "Warning!";
89
- cancelDialogMessage = config.hasKey("cancelDialogMessage") ? config.getString("cancelDialogMessage") : "Are you sure want to cancel?";
90
- cancelDialogCancelText = config.hasKey("cancelDialogCancelText") ? config.getString("cancelDialogCancelText") : "Close";
91
- cancelDialogConfirmText = config.hasKey("cancelDialogConfirmText") ? config.getString("cancelDialogConfirmText") : "Proceed";
92
-
93
- enableSaveDialog = config.hasKey("enableSaveDialog") ? config.getBoolean("enableSaveDialog") : true;
94
- saveDialogTitle = config.hasKey("saveDialogTitle") ? config.getString("saveDialogTitle") : "Confirmation!";
95
- saveDialogMessage = config.hasKey("saveDialogMessage") ? config.getString("saveDialogMessage") : "Are you sure want to save?";
96
- saveDialogCancelText = config.hasKey("saveDialogCancelText") ? config.getString("saveDialogCancelText") : "Close";
97
- saveDialogConfirmText = config.hasKey("saveDialogConfirmText") ? config.getString("saveDialogConfirmText") : "Proceed";
98
- trimmingText = config.hasKey("trimmingText") ? config.getString("trimmingText") : "Trimming video...";
99
-
100
- Activity activity = getReactApplicationContext().getCurrentActivity();
101
-
102
- if (!isInit) {
103
- init(activity);
104
- isInit = true;
105
- }
106
-
107
- // here is NOT main thread, we need to create VideoTrimmerView on UI thread, so that later we can update it using same thread
108
-
109
- runOnUiThread(() -> {
110
- trimmerView = new VideoTrimmerView(getReactApplicationContext(), config, null);
111
- trimmerView.setOnTrimVideoListener(this);
112
- trimmerView.initVideoByURI(Uri.parse(videoPath));
113
-
114
- AlertDialog.Builder builder = new AlertDialog.Builder(activity, android.R.style.Theme_Black_NoTitleBar_Fullscreen);
115
- builder.setCancelable(false);
116
- alertDialog = builder.create();
117
- alertDialog.setView(trimmerView);
118
- alertDialog.show();
119
-
120
- // 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)
121
- alertDialog.setOnDismissListener(dialog -> {
122
- // This is called in same thread as the trimmer view -> UI thread
123
- if (trimmerView != null) {
124
- trimmerView.onDestroy();
125
- trimmerView = null;
126
- }
127
- hideDialog();
128
- sendEvent(getReactApplicationContext(), "onHide", null);
129
- });
130
- sendEvent(getReactApplicationContext(), "onShow", null);
131
- });
132
- }
133
-
134
- private void init(Activity activity) {
135
- isInit = true;
136
- // we have to init this before create videoTrimmerView
137
- BaseUtils.init(getReactApplicationContext());
138
- }
139
-
140
- @Override
141
- public void onHostResume() {
142
-
143
- }
144
-
145
- @Override
146
- public void onHostPause() {
147
- if (trimmerView != null) {
148
- trimmerView.onVideoPause();
149
- trimmerView.setRestoreState(true);
150
- }
151
- }
152
-
153
- @Override
154
- public void onHostDestroy() {
155
- hideDialog();
156
- }
157
-
158
- @Override public void onStartTrim() {
159
- sendEvent(getReactApplicationContext(), "onStartTrimming", null);
160
- runOnUiThread(() -> {
161
- buildDialog();
162
- });
163
- }
164
-
165
- @Override public void onTrimmingProgress(int percentage) {
166
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
167
- mProgressBar.setProgress(percentage, true);
168
- } else {
169
- mProgressBar.setProgress(percentage);
170
- }
171
- }
172
-
173
-
174
- @Override public void onFinishTrim(String in) {
175
- runOnUiThread(() -> {
176
- WritableMap map = Arguments.createMap();
177
- map.putString("outputPath", in);
178
- sendEvent(getReactApplicationContext(), "onFinishTrimming", map);
179
- showEditorPromise.resolve(in);
180
- });
181
- }
182
-
183
- @Override public void onError(String errorMessage) {
184
- WritableMap map = Arguments.createMap();
185
- map.putString("message", errorMessage);
186
- sendEvent(getReactApplicationContext(), "onError", map);
187
- this.hideDialog();
188
- }
189
-
190
- @Override public void onCancel() {
191
- if (!enableCancelDialog) {
192
- sendEvent(getReactApplicationContext(), "onCancelTrimming", null);
193
- hideDialog();
194
- return;
195
- }
196
-
197
- AlertDialog.Builder builder = new AlertDialog.Builder(getReactApplicationContext().getCurrentActivity());
198
- builder.setMessage(cancelDialogMessage);
199
- builder.setTitle(cancelDialogTitle);
200
- builder.setCancelable(false);
201
- builder.setPositiveButton(cancelDialogConfirmText, (dialog, which) -> {
202
- dialog.cancel();
203
- sendEvent(getReactApplicationContext(), "onCancelTrimming", null);
204
- hideDialog();
205
- });
206
- builder.setNegativeButton(cancelDialogCancelText, (dialog, which) -> {
207
- dialog.cancel();
208
- });
209
- AlertDialog alertDialog = builder.create();
210
- alertDialog.show();
211
- }
212
-
213
- @Override public void onSave() {
214
- if (!enableSaveDialog) {
215
- trimmerView.onSaveClicked();
216
- return;
217
- }
218
-
219
- AlertDialog.Builder builder = new AlertDialog.Builder(getReactApplicationContext().getCurrentActivity());
220
- builder.setMessage(saveDialogMessage);
221
- builder.setTitle(saveDialogTitle);
222
- builder.setCancelable(false);
223
- builder.setPositiveButton(saveDialogConfirmText, (dialog, which) -> {
224
- dialog.cancel();
225
- trimmerView.onSaveClicked();
226
- });
227
- builder.setNegativeButton(saveDialogCancelText, (dialog, which) -> {
228
- dialog.cancel();
229
- });
230
- AlertDialog alertDialog = builder.create();
231
- alertDialog.show();
232
- }
233
-
234
- @ReactMethod
235
- private void hideDialog() {
236
- if (mProgressDialog != null) {
237
- if (mProgressDialog.isShowing()) mProgressDialog.dismiss();
238
- mProgressBar = null;
239
- mProgressDialog = null;
240
- }
241
-
242
- if (alertDialog != null) {
243
- if(alertDialog.isShowing()) {
244
- alertDialog.dismiss();
245
- }
246
- alertDialog = null;
247
- }
248
- }
249
-
250
- private void buildDialog() {
251
- Activity activity = getReactApplicationContext().getCurrentActivity();
252
- // Create the parent layout for the dialog
253
- LinearLayout layout = new LinearLayout(activity);
254
- layout.setLayoutParams(new ViewGroup.LayoutParams(
255
- ViewGroup.LayoutParams.WRAP_CONTENT,
256
- ViewGroup.LayoutParams.WRAP_CONTENT
257
- ));
258
- layout.setOrientation(LinearLayout.VERTICAL);
259
- layout.setGravity(Gravity.CENTER_HORIZONTAL);
260
- layout.setPadding(16, 32, 16, 32);
261
-
262
- // Create and add the TextView
263
- TextView textView = new TextView(activity);
264
- textView.setLayoutParams(new ViewGroup.LayoutParams(
265
- ViewGroup.LayoutParams.WRAP_CONTENT,
266
- ViewGroup.LayoutParams.WRAP_CONTENT
267
- ));
268
- textView.setText(trimmingText);
269
- textView.setTextSize(18);
270
- layout.addView(textView);
271
-
272
- // Create and add the ProgressBar
273
- mProgressBar = new ProgressBar(activity, null, android.R.attr.progressBarStyleHorizontal);
274
- mProgressBar.setLayoutParams(new ViewGroup.LayoutParams(
275
- ViewGroup.LayoutParams.MATCH_PARENT,
276
- ViewGroup.LayoutParams.WRAP_CONTENT
277
- ));
278
- mProgressBar.setProgressTintList(ColorStateList.valueOf(Color.parseColor("#2196F3")));
279
- layout.addView(mProgressBar);
280
-
281
- // Create the AlertDialog
282
- AlertDialog.Builder builder = new AlertDialog.Builder(activity);
283
- builder.setCancelable(false);
284
- builder.setView(layout);
285
-
286
- // Show the dialog
287
- mProgressDialog = builder.create();
288
- mProgressDialog.show();
289
- }
290
-
291
- @ReactMethod
292
- public void addListener(String eventName) {
293
- // This method is required by React
294
- listenerCount += 1;
295
- }
296
-
297
- @ReactMethod
298
- public void removeListeners(Integer count) {
299
- // This method is required by React
300
- listenerCount -= count;
301
- }
302
-
303
- private void sendEvent(ReactContext reactContext, String eventName, @Nullable WritableMap params) {
304
- if (listenerCount > 0) {
305
- WritableMap map = params != null ? params : Arguments.createMap();
306
- map.putString("name", eventName);
307
- reactContext
308
- .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
309
- .emit("ShakebugSDKVideoTrim", map);
310
- }
311
- }
312
-
313
-
314
- public boolean isValidVideo(String filePath) {
315
- MediaMetadataRetriever retriever = new MediaMetadataRetriever();
316
-
317
- try {
318
- retriever.setDataSource(getReactApplicationContext(), Uri.parse(filePath));
319
- } catch (Exception e){
320
- e.printStackTrace();
321
- return false;
322
- }
323
-
324
- String hasVideo = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_HAS_VIDEO);
325
- return "yes".equals(hasVideo);
326
- }
327
-
328
- @ReactMethod
329
- private void isValidVideo(String filePath, Promise promise) {
330
- promise.resolve(isValidVideo(filePath));
331
- }
332
-
333
- @ReactMethod
334
- private void saveVideo(String filePath, Promise promise) {
335
- try {
336
- StorageUtil.saveVideoToGallery(getReactApplicationContext(), filePath);
337
- } catch (IOException e) {
338
- e.printStackTrace();
339
- WritableMap mapE = Arguments.createMap();
340
- mapE.putString("message", "Fail while copying file to Gallery");
341
- sendEvent(getReactApplicationContext(), "onError", mapE);
342
- }
343
-
344
- this.hideDialog();
345
- promise.resolve(null);
346
- }
347
-
348
- @ReactMethod
349
- private void listFiles(Promise promise) {
350
- String[] files = StorageUtil.listFiles(getReactApplicationContext());
351
- promise.resolve(Arguments.fromArray(files));
352
- }
353
-
354
- @ReactMethod
355
- private void cleanFiles(Promise promise) {
356
- String[] files = StorageUtil.listFiles(getReactApplicationContext());
357
- int successCount = 0;
358
- for (String file : files) {
359
- boolean state = StorageUtil.deleteFile(file);
360
- if (state) {
361
- successCount++;
362
- }
363
- }
364
- promise.resolve(successCount);
365
- }
366
-
367
- @ReactMethod
368
- private void deleteFile(String filePath, Promise promise) {
369
- boolean state = StorageUtil.deleteFile(filePath);
370
- promise.resolve(state);
371
- }
372
- }
@@ -1,54 +0,0 @@
1
- package com.shakebug.adapters;
2
-
3
- import android.content.Context;
4
- import android.graphics.Bitmap;
5
- import android.view.LayoutInflater;
6
- import android.view.View;
7
- import android.view.ViewGroup;
8
- import android.widget.ImageView;
9
- import android.widget.LinearLayout;
10
- import androidx.annotation.NonNull;
11
- import androidx.recyclerview.widget.RecyclerView;
12
- import com.shakebug.R;
13
- import com.shakebug.utils.VideoTrimmerUtil;
14
- import java.util.ArrayList;
15
- import java.util.List;
16
-
17
- public class VideoTrimmerAdapter extends RecyclerView.Adapter {
18
- private final List<Bitmap> mBitmaps = new ArrayList<>();
19
- private final LayoutInflater mInflater;
20
-
21
- public VideoTrimmerAdapter(Context context) {
22
- this.mInflater = LayoutInflater.from(context);
23
- }
24
-
25
- @NonNull @Override public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
26
- return new TrimmerViewHolder(mInflater.inflate(R.layout.video_thumb_item_layout, parent, false));
27
- }
28
-
29
- @Override public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
30
- ((TrimmerViewHolder) holder).thumbImageView.setImageBitmap(mBitmaps.get(position));
31
- }
32
-
33
- @Override public int getItemCount() {
34
- return mBitmaps.size();
35
- }
36
-
37
- public void addBitmaps(Bitmap bitmap) {
38
- mBitmaps.add(bitmap);
39
- notifyItemInserted(mBitmaps.size() - 1);
40
- }
41
-
42
- private static final class TrimmerViewHolder extends RecyclerView.ViewHolder {
43
- ImageView thumbImageView;
44
-
45
- TrimmerViewHolder(View itemView) {
46
- super(itemView);
47
- thumbImageView = itemView.findViewById(R.id.thumb);
48
- LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) thumbImageView.getLayoutParams();
49
- layoutParams.width = VideoTrimmerUtil.VIDEO_FRAMES_WIDTH / VideoTrimmerUtil.MAX_COUNT_RANGE;
50
- thumbImageView.setLayoutParams(layoutParams);
51
- }
52
- }
53
- }
54
-