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
package/README.md CHANGED
@@ -23,6 +23,18 @@ Or if you prefer to use Yarn instead of npm:
23
23
  yarn add shakebug-react-native
24
24
  ```
25
25
 
26
+ Make sure to install Required Libraries also
27
+
28
+ ```bash
29
+ npm i react-native-view-shot react-native-video react-native-video-trim
30
+ ```
31
+ Or if you prefer to use Yarn instead of npm:
32
+
33
+ ```bash
34
+ yarn add react-native-view-shot react-native-video react-native-video-trim
35
+ ```
36
+
37
+
26
38
  ### iOS
27
39
 
28
40
  1. You need to provide permissions inside `ios/YourProjectName/info.plist`:
@@ -37,8 +49,12 @@ Or if you prefer to use Yarn instead of npm:
37
49
  <key>NSPhotoLibraryUsageDescription</key>
38
50
  <string></string>
39
51
  ```
52
+ 2. Manage Architecture:
53
+ ```bash
54
+ ENV['RCT_NEW_ARCH_ENABLED'] = '0'
55
+ ```
40
56
 
41
- 2. CocoaPods installation:
57
+ 3. CocoaPods installation:
42
58
 
43
59
  ```bash
44
60
  cd ios && pod install && cd ..
@@ -1,35 +1,38 @@
1
- import React, { useEffect } from 'react';
1
+ import React, { useEffect, useState } from 'react';
2
2
  import { NativeModules, Image, TouchableOpacity, ImageBackground, NativeEventEmitter, Platform, StatusBar } from 'react-native';
3
3
  import { PlayVideo } from './PlayVideo';
4
+ import Video from 'react-native-video';
4
5
 
5
6
  const VideoPlayer = ({ videoUri, img, goToScreenAtIndex, UpdateStatusBar }) => {
6
- useEffect(() => {
7
- if (Platform.OS == 'android') {
8
- const eventEmitter = new NativeEventEmitter(NativeModules.VideoPlayerModule);
9
- const subscription = eventEmitter.addListener('ShakebugSDKVideoPlayer', (event) => {
10
- switch (event.name) {
11
- case 'onCancelPlayer': {
12
- UpdateStatusBar()
13
- goToScreenAtIndex(3)
14
- break;
15
- }
16
- default:
17
- break;
18
- }
19
- });
7
+ // useEffect(() => {
8
+ // if (Platform.OS == 'android') {
9
+ // const eventEmitter = new NativeEventEmitter(NativeModules.VideoPlayerModule);
10
+ // const subscription = eventEmitter.addListener('ShakebugSDKVideoPlayer', (event) => {
11
+ // switch (event.name) {
12
+ // case 'onCancelPlayer': {
13
+ // UpdateStatusBar()
14
+ // goToScreenAtIndex(3)
15
+ // break;
16
+ // }
17
+ // default:
18
+ // break;
19
+ // }
20
+ // });
20
21
 
21
- return () => {
22
- subscription.remove();
23
- };
24
- }
25
- }, []);
22
+ // return () => {
23
+ // subscription.remove();
24
+ // };
25
+ // }
26
+ // }, []);
27
+
28
+ const [isPlayVideo, setIsPlayVideo] = useState(false);
26
29
 
27
30
  const playVideo = () => {
28
- // StatusBar.setHidden(true)
29
- PlayVideo(videoUri)
31
+ setIsPlayVideo(true)
30
32
  }
31
-
33
+
32
34
  return (
35
+ !isPlayVideo ? (
33
36
  <ImageBackground
34
37
  source={{ uri: img }}
35
38
  style={{
@@ -63,6 +66,17 @@ const VideoPlayer = ({ videoUri, img, goToScreenAtIndex, UpdateStatusBar }) => {
63
66
  />
64
67
  </TouchableOpacity>
65
68
  </ImageBackground>
69
+ )
70
+ : (<Video
71
+ source={{ uri: videoUri }}
72
+ style={{
73
+ width: "90%",
74
+ marginLeft: '5%',
75
+ height: "100%"
76
+ }}
77
+ controls={true}
78
+ fullscreen={Platform.OS == 'ios' && true}
79
+ />)
66
80
  );
67
81
  };
68
82
 
@@ -155,7 +155,6 @@ dependencies {
155
155
  implementation "androidx.core:core:1.3.1"
156
156
  implementation "androidx.exifinterface:exifinterface:1.3.3"
157
157
  implementation 'androidx.recyclerview:recyclerview:1.3.2'
158
- implementation 'com.arthenica:ffmpeg-kit-full:6.0-2'
159
158
 
160
159
 
161
160
  def firebaseBomVersion = safeExtGet("firebaseBomVersion", null)
@@ -0,0 +1,217 @@
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;
9
+ import android.os.Build.VERSION;
10
+ import android.os.Handler;
11
+ import android.os.Looper;
12
+ import android.text.TextUtils;
13
+ import android.webkit.URLUtil;
14
+
15
+ import com.facebook.react.bridge.Arguments;
16
+ import com.facebook.react.bridge.Promise;
17
+ import com.facebook.react.bridge.ReactApplicationContext;
18
+ import com.facebook.react.bridge.ReactContextBaseJavaModule;
19
+ import com.facebook.react.bridge.ReactMethod;
20
+ import com.facebook.react.bridge.ReadableMap;
21
+ import com.facebook.react.bridge.WritableMap;
22
+
23
+ import org.apache.commons.io.comparator.LastModifiedFileComparator;
24
+
25
+ import java.io.File;
26
+ import java.io.FileOutputStream;
27
+ import java.io.IOException;
28
+ import java.io.OutputStream;
29
+ import java.io.UnsupportedEncodingException;
30
+ import java.net.URLDecoder;
31
+ import java.util.Arrays;
32
+ import java.util.HashMap;
33
+ import java.util.Map;
34
+ import java.util.UUID;
35
+ import java.util.concurrent.Executor;
36
+ import java.util.concurrent.Executors;
37
+
38
+ public class CreateThumbnailModule extends ReactContextBaseJavaModule {
39
+ private final Executor executor = Executors.newSingleThreadExecutor();
40
+ private final Handler handler = new Handler(Looper.getMainLooper());
41
+ private final ReactApplicationContext reactContext;
42
+
43
+ public CreateThumbnailModule(ReactApplicationContext reactContext) {
44
+ super(reactContext);
45
+ this.reactContext = reactContext;
46
+ }
47
+
48
+ @Override
49
+ public String getName() {
50
+ return "CreateThumbnail";
51
+ }
52
+
53
+ @ReactMethod
54
+ public void create(ReadableMap options, Promise promise) {
55
+ executor.execute(() -> {
56
+ try {
57
+ ReadableMap data = processData(options);
58
+ handler.post(() -> {
59
+ promise.resolve(data);
60
+ });
61
+ } catch (IOException e) {
62
+ handler.post(() -> {
63
+ promise.reject("CreateThumbnail_ERROR", e);
64
+ });
65
+ }
66
+ });
67
+ }
68
+
69
+ private ReadableMap processData(ReadableMap options) throws IOException {
70
+ String format = options.hasKey("format") ? options.getString("format") : "jpeg";
71
+ String cacheName = options.hasKey("cacheName") ? options.getString("cacheName") : "";
72
+
73
+ String thumbnailDir = reactContext.getApplicationContext().getCacheDir().getAbsolutePath() + "/thumbnails";
74
+ File cacheDir = createDirIfNotExists(thumbnailDir);
75
+ if (!TextUtils.isEmpty(cacheName)) {
76
+ File file = new File(thumbnailDir, cacheName + "." + format);
77
+ if (file.exists()) {
78
+ WritableMap map = Arguments.createMap();
79
+ map.putString("path", "file://" + file.getAbsolutePath());
80
+ Bitmap image = BitmapFactory.decodeFile(file.getAbsolutePath());
81
+ map.putDouble("size", image.getByteCount());
82
+ map.putString("mime", "image/" + format);
83
+ map.putDouble("width", image.getWidth());
84
+ map.putDouble("height", image.getHeight());
85
+ return map;
86
+ }
87
+ }
88
+
89
+ String filePath = options.hasKey("url") ? options.getString("url") : "";
90
+ int dirSize = options.hasKey("dirSize") ? options.getInt("dirSize") : 100;
91
+ int timeStamp = options.hasKey("timeStamp") ? options.getInt("timeStamp") : 0;
92
+ int maxWidth = options.hasKey("maxWidth") ? options.getInt("maxWidth") : 512;
93
+ int maxHeight = options.hasKey("maxHeight") ? options.getInt("maxHeight") : 512;
94
+ boolean onlySyncedFrames = options.hasKey("onlySyncedFrames") ? options.getBoolean("onlySyncedFrames") : true;
95
+ HashMap headers = options.hasKey("headers") ? options.getMap("headers").toHashMap() : new HashMap<String, String>();
96
+ String fileName = TextUtils.isEmpty(cacheName) ? ("thumb-" + UUID.randomUUID().toString()) : cacheName + "." + format;
97
+ OutputStream fOut = null;
98
+ File file = new File(cacheDir, fileName);
99
+ Context context = reactContext;
100
+ Bitmap image = getBitmapAtTime(context, filePath, timeStamp, maxWidth, maxHeight, onlySyncedFrames, headers);
101
+ file.createNewFile();
102
+ fOut = new FileOutputStream(file);
103
+
104
+ // 100 means no compression, the lower you go, the stronger the compression
105
+ if (format.equals("png")) {
106
+ image.compress(Bitmap.CompressFormat.PNG, 100, fOut);
107
+ } else {
108
+ image.compress(Bitmap.CompressFormat.JPEG, 90, fOut);
109
+ }
110
+
111
+ fOut.flush();
112
+ fOut.close();
113
+
114
+ long cacheDirSize = (long) dirSize * 1024 * 1024;
115
+ long newSize = image.getByteCount() + getDirSize(cacheDir);
116
+ // free up some cached data if size of cache dir exceeds CACHE_DIR_MAX_SIZE
117
+ if (newSize > cacheDirSize) {
118
+ cleanDir(cacheDir, cacheDirSize / 2);
119
+ }
120
+
121
+ WritableMap map = Arguments.createMap();
122
+ map.putString("path", "file://" + file.getAbsolutePath());
123
+ map.putDouble("size", image.getByteCount());
124
+ map.putString("mime", "image/" + format);
125
+ map.putDouble("width", image.getWidth());
126
+ map.putDouble("height", image.getHeight());
127
+ return map;
128
+ }
129
+
130
+ // delete previously added files one by one untill requred space is available
131
+ private static void cleanDir(File dir, long bytes) {
132
+ long bytesDeleted = 0;
133
+ File[] files = dir.listFiles();
134
+ Arrays.sort(files, LastModifiedFileComparator.LASTMODIFIED_COMPARATOR);
135
+
136
+ for (File file : files) {
137
+ bytesDeleted += file.length();
138
+ file.delete();
139
+
140
+ if (bytesDeleted >= bytes) {
141
+ break;
142
+ }
143
+ }
144
+ }
145
+
146
+ private static File createDirIfNotExists(String path) {
147
+ File dir = new File(path);
148
+ if (dir.exists()) {
149
+ return dir;
150
+ }
151
+
152
+ try {
153
+ dir.mkdirs();
154
+ // Add .nomedia to hide the thumbnail directory from gallery
155
+ File noMedia = new File(path, ".nomedia");
156
+ noMedia.createNewFile();
157
+ } catch (IOException e) {
158
+ e.printStackTrace();
159
+ }
160
+
161
+ return dir;
162
+ }
163
+
164
+ private static Bitmap getBitmapAtTime(Context context, String filePath, int time, int maxWidth, int maxHeight, boolean onlySyncedFrames, Map headers) throws IOException, IllegalStateException {
165
+ MediaMetadataRetriever retriever = new MediaMetadataRetriever();
166
+ if (URLUtil.isFileUrl(filePath)) {
167
+ String decodedPath;
168
+ try {
169
+ decodedPath = URLDecoder.decode(filePath, "UTF-8");
170
+ } catch (UnsupportedEncodingException e) {
171
+ decodedPath = filePath;
172
+ }
173
+
174
+ retriever.setDataSource(decodedPath.replace("file://", ""));
175
+ } else if (filePath.contains("content://")) {
176
+ retriever.setDataSource(context, Uri.parse(filePath));
177
+ } else {
178
+ if (VERSION.SDK_INT < 14) {
179
+ throw new IllegalStateException("Remote videos aren't supported on sdk_version < 14");
180
+ }
181
+ retriever.setDataSource(filePath, headers);
182
+ }
183
+
184
+ Bitmap image;
185
+ if (Build.VERSION.SDK_INT >= 27) {
186
+ image = retriever.getScaledFrameAtTime(time * 1000, MediaMetadataRetriever.OPTION_CLOSEST_SYNC, maxWidth, maxHeight);
187
+ } else {
188
+ // If on versions lower than API 27, use other methods to get frames
189
+ image = retriever.getFrameAtTime(time * 1000, MediaMetadataRetriever.OPTION_CLOSEST_SYNC);
190
+ if (image != null) {
191
+ image = Bitmap.createScaledBitmap(image, maxWidth, maxHeight, true);
192
+ }
193
+ }
194
+ try {
195
+ retriever.release();
196
+ } catch(IOException e) {
197
+ e.printStackTrace();
198
+ }
199
+ if (image == null) {
200
+ throw new IllegalStateException("File doesn't exist or not supported");
201
+ }
202
+ return image;
203
+ }
204
+
205
+ private static long getDirSize(File dir) {
206
+ long size = 0;
207
+ File[] files = dir.listFiles();
208
+
209
+ for (File file : files) {
210
+ if (file.isFile()) {
211
+ size += file.length();
212
+ }
213
+ }
214
+
215
+ return size;
216
+ }
217
+ }
@@ -41,8 +41,7 @@ public class NetInfoModule extends ReactContextBaseJavaModule implements AmazonF
41
41
  mAmazonConnectivityChecker.register();
42
42
  }
43
43
 
44
- @Override
45
- public void onCatalystInstanceDestroy() {
44
+ public void stopDetection() {
46
45
  mAmazonConnectivityChecker.unregister();
47
46
  mConnectivityReceiver.unregister();
48
47
  mConnectivityReceiver.hasListener = false;
@@ -153,9 +153,7 @@ public class RNDeviceModule extends ReactContextBaseJavaModule {
153
153
  getReactApplicationContext().registerReceiver(headphoneConnectionReceiver, filter);
154
154
  }
155
155
 
156
-
157
- @Override
158
- public void onCatalystInstanceDestroy() {
156
+ public void stopDetection() {
159
157
  getReactApplicationContext().unregisterReceiver(receiver);
160
158
  getReactApplicationContext().unregisterReceiver(headphoneConnectionReceiver);
161
159
  }
@@ -22,13 +22,13 @@ public class ShakebugPackage implements ReactPackage {
22
22
  public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
23
23
 
24
24
  return Arrays.<NativeModule>asList(
25
- new Shakebug(reactContext, "ShakebugSDKRNSensorsGyroscope", Sensor.TYPE_GYROSCOPE),
26
- new Shakebug(reactContext, "ShakebugSDKRNSensorsAccelerometer", Sensor.TYPE_ACCELEROMETER),
27
- new Shakebug(reactContext, "ShakebugSDKRNSensorsGravity", Sensor.TYPE_GRAVITY),
28
- new Shakebug(reactContext, "ShakebugSDKRNSensorsMagnetometer", Sensor.TYPE_MAGNETIC_FIELD),
29
- new Shakebug(reactContext, "ShakebugSDKRNSensorsBarometer", Sensor.TYPE_PRESSURE),
30
- new Shakebug(reactContext, "ShakebugSDKRNSensorsOrientation", Sensor.TYPE_ROTATION_VECTOR),
31
- new ShakebugSDKScreenShotModule(reactContext),
25
+ new ShakebugSensors(reactContext, "ShakebugSDKRNSensorsGyroscope", Sensor.TYPE_GYROSCOPE),
26
+ new ShakebugSensors(reactContext, "ShakebugSDKRNSensorsAccelerometer", Sensor.TYPE_ACCELEROMETER),
27
+ new ShakebugSensors(reactContext, "ShakebugSDKRNSensorsGravity", Sensor.TYPE_GRAVITY),
28
+ new ShakebugSensors(reactContext, "ShakebugSDKRNSensorsMagnetometer", Sensor.TYPE_MAGNETIC_FIELD),
29
+ new ShakebugSensors(reactContext, "ShakebugSDKRNSensorsBarometer", Sensor.TYPE_PRESSURE),
30
+ new ShakebugSensors(reactContext, "ShakebugSDKRNSensorsOrientation", Sensor.TYPE_ROTATION_VECTOR),
31
+ // new ShakebugSDKScreenShotModule(reactContext),
32
32
  new ShakebugSDKImagePickerModule(reactContext),
33
33
  new RecordScreenModule(reactContext),
34
34
  new RNDeviceModule(reactContext),
@@ -37,9 +37,9 @@ public class ShakebugPackage implements ReactPackage {
37
37
  new NetInfoModule(reactContext),
38
38
  new RNLocalizeModule(reactContext),
39
39
  new SharedPreferencesModule(reactContext),
40
- new VideoPlayerModule(reactContext),
41
- new VideoThumbnailModule(reactContext),
42
- new VideoTrimModule(reactContext),
40
+ // new VideoPlayerModule(reactContext),
41
+ new CreateThumbnailModule(reactContext),
42
+ // new VideoTrimModule(reactContext),
43
43
  new ScreenshotDetectorModule(reactContext)
44
44
  );
45
45
  }
@@ -1,11 +1,8 @@
1
1
  package com.shakebug;
2
2
 
3
- import androidx.annotation.NonNull;
4
-
5
3
  import android.hardware.Sensor;
6
4
  import android.hardware.SensorEvent;
7
5
  import android.hardware.SensorEventListener;
8
- import android.hardware.SensorListener;
9
6
  import android.hardware.SensorManager;
10
7
  import android.os.SystemClock;
11
8
  import androidx.annotation.Nullable;
@@ -16,14 +13,11 @@ import com.facebook.react.bridge.Promise;
16
13
  import com.facebook.react.bridge.ReactApplicationContext;
17
14
  import com.facebook.react.bridge.ReactContextBaseJavaModule;
18
15
  import com.facebook.react.bridge.ReactMethod;
19
- import com.facebook.react.module.annotations.ReactModule;
20
16
  import com.facebook.react.bridge.WritableMap;
21
17
  import com.facebook.react.modules.core.DeviceEventManagerModule;
22
18
 
23
- @ReactModule(name = Shakebug.NAME)
19
+ public class ShakebugSensors extends ReactContextBaseJavaModule implements SensorEventListener {
24
20
 
25
- public class Shakebug extends ReactContextBaseJavaModule implements SensorEventListener {
26
- public static final String NAME = "AwesomeLibrary";
27
21
  private final ReactApplicationContext reactContext;
28
22
  private final SensorManager sensorManager;
29
23
  private final Sensor sensor;
@@ -37,8 +31,9 @@ public class Shakebug extends ReactContextBaseJavaModule implements SensorEventL
37
31
  private float[] orientation = new float[3];
38
32
  private float[] quaternion = new float[4];
39
33
 
40
- private Boolean isBeingObserved = false;
41
- public Shakebug(ReactApplicationContext reactContext, String sensorName, int sensorType) {
34
+ private int listenerCount = 0;
35
+
36
+ public ShakebugSensors(ReactApplicationContext reactContext, String sensorName, int sensorType) {
42
37
  super(reactContext);
43
38
  this.reactContext = reactContext;
44
39
  this.sensorType = sensorType;
@@ -47,12 +42,6 @@ public class Shakebug extends ReactContextBaseJavaModule implements SensorEventL
47
42
  this.sensor = this.sensorManager.getDefaultSensor(this.sensorType);
48
43
  }
49
44
 
50
- // @Override
51
- // @NonNull
52
- // public String getName() {
53
- // return NAME;
54
- // }
55
-
56
45
  // RN Methods
57
46
  @ReactMethod
58
47
  public void isAvailable(Promise promise) {
@@ -77,12 +66,12 @@ public class Shakebug extends ReactContextBaseJavaModule implements SensorEventL
77
66
  @ReactMethod
78
67
  public void startUpdates() {
79
68
  // Milliseconds to Microseconds conversion
80
- sensorManager.registerListener((SensorEventListener) this, sensor, this.interval * 1000);
69
+ sensorManager.registerListener(this, sensor, this.interval * 1000);
81
70
  }
82
71
 
83
72
  @ReactMethod
84
73
  public void stopUpdates() {
85
- sensorManager.unregisterListener((SensorEventListener) this);
74
+ sensorManager.unregisterListener(this);
86
75
  }
87
76
 
88
77
  @Override
@@ -105,8 +94,9 @@ public class Shakebug extends ReactContextBaseJavaModule implements SensorEventL
105
94
  }
106
95
  }
107
96
 
97
+ @Override
108
98
  public void onSensorChanged(SensorEvent sensorEvent) {
109
- if(!isBeingObserved) {
99
+ if(this.listenerCount <= 0) {
110
100
  return; // avoid all the computation if there are no observers
111
101
  }
112
102
 
@@ -161,6 +151,7 @@ public class Shakebug extends ReactContextBaseJavaModule implements SensorEventL
161
151
  }
162
152
  }
163
153
 
154
+ @Override
164
155
  public void onAccuracyChanged(Sensor sensor, int accuracy) {
165
156
  }
166
157
 
@@ -168,14 +159,17 @@ public class Shakebug extends ReactContextBaseJavaModule implements SensorEventL
168
159
  // not implementing this method will cause a warning on RN 0.65 onwards
169
160
  @ReactMethod
170
161
  public void addListener(String eventName) {
171
- isBeingObserved = true;
162
+ this.listenerCount += 1;
172
163
  }
173
164
 
174
165
  // this is called by RN when the last listener is deregistered
175
166
  // not implementing this method will cause a warning on RN 0.65 onwards
176
167
  @ReactMethod
177
168
  public void removeListeners(Integer count) {
178
- isBeingObserved = false;
179
- stopUpdates(); // maybe only calling `stopUpdates()` is enough
169
+ this.listenerCount -= count;
170
+ // If we no longer have listeners registered we should also probably also stop the sensor since the sensor events are essentially being dropped.
171
+ if (this.sensorManager != null && this.listenerCount <= 0) {
172
+ stopUpdates(); // maybe only calling `stopUpdates()` is enough
173
+ }
180
174
  }
181
- }
175
+ }
@@ -9,6 +9,7 @@
9
9
  #ifdef RCT_NEW_ARCH_ENABLED
10
10
 
11
11
  #import <RNLocalizeSpec/RNLocalizeSpec.h>
12
+
12
13
  @interface ShakebugSDKRNLocalize : NSObject <NativeRNLocalizeSpec>
13
14
 
14
15
  #else
@@ -7,6 +7,7 @@
7
7
  //
8
8
 
9
9
  #import <React/RCTBridgeModule.h>
10
+ #import <React/RCTUtils.h>
10
11
 
11
- @interface ShakebugSDKVideoThumbnailManager : NSObject <RCTBridgeModule>
12
+ @interface CreateThumbnail : NSObject <RCTBridgeModule>
12
13
  @end
@@ -0,0 +1,82 @@
1
+ //
2
+ // VideoThumbnailManager.m
3
+ // Shakebug
4
+ //
5
+ // Created by ideveloper2 on 26/04/24.
6
+ // Copyright © 2024 Facebook. All rights reserved.
7
+ //
8
+
9
+ #import "CreateThumbnail.h"
10
+ #import <AVFoundation/AVFoundation.h>
11
+ #import <UIKit/UIKit.h>
12
+
13
+ @implementation CreateThumbnail
14
+
15
+ RCT_EXPORT_MODULE();
16
+
17
+ RCT_EXPORT_METHOD(create:(NSDictionary *)options resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
18
+ {
19
+ NSString *urlString = options[@"url"];
20
+ NSNumber *timeStamp = options[@"timeStamp"] ?: @(0);
21
+ NSNumber *maxWidth = options[@"maxWidth"] ?: @(512);
22
+ NSNumber *maxHeight = options[@"maxHeight"] ?: @(512);
23
+ NSString *format = options[@"format"] ?: @"jpeg";
24
+ NSString *cacheName = options[@"cacheName"];
25
+
26
+ if (!urlString || ![urlString isKindOfClass:[NSString class]]) {
27
+ reject(@"CreateThumbnail_ERROR", @"Invalid URL", nil);
28
+ return;
29
+ }
30
+
31
+ NSURL *url = [NSURL URLWithString:urlString];
32
+ if ([url.scheme isEqualToString:@"file"]) {
33
+ url = [NSURL fileURLWithPath:url.path];
34
+ }
35
+
36
+ AVAsset *asset = [AVAsset assetWithURL:url];
37
+ AVAssetImageGenerator *imageGenerator = [[AVAssetImageGenerator alloc] initWithAsset:asset];
38
+ imageGenerator.appliesPreferredTrackTransform = YES;
39
+ imageGenerator.maximumSize = CGSizeMake(maxWidth.floatValue, maxHeight.floatValue);
40
+
41
+ CMTime time = CMTimeMakeWithSeconds(timeStamp.floatValue / 1000.0, 600);
42
+ NSError *error = nil;
43
+ CMTime actualTime;
44
+ CGImageRef cgImage = [imageGenerator copyCGImageAtTime:time actualTime:&actualTime error:&error];
45
+
46
+ if (error || !cgImage) {
47
+ reject(@"FAIL_TO_LOAD_MEDIA", @"Failed to load duration: Operation Stopped", error);
48
+ return;
49
+ }
50
+
51
+ UIImage *image = [UIImage imageWithCGImage:cgImage];
52
+ CGImageRelease(cgImage);
53
+
54
+ NSData *imageData;
55
+ NSString *mime;
56
+ if ([format.lowercaseString isEqualToString:@"png"]) {
57
+ imageData = UIImagePNGRepresentation(image);
58
+ mime = @"image/png";
59
+ } else {
60
+ imageData = UIImageJPEGRepresentation(image, 0.9);
61
+ mime = @"image/jpeg";
62
+ }
63
+
64
+ NSString *fileName = cacheName ?: [NSString stringWithFormat:@"thumb-%@.%@", [[NSUUID UUID] UUIDString], format];
65
+ NSString *thumbDir = [NSTemporaryDirectory() stringByAppendingPathComponent:@"thumbnails"];
66
+ [[NSFileManager defaultManager] createDirectoryAtPath:thumbDir withIntermediateDirectories:YES attributes:nil error:nil];
67
+
68
+ NSString *filePath = [thumbDir stringByAppendingPathComponent:fileName];
69
+ [imageData writeToFile:filePath atomically:YES];
70
+
71
+ NSDictionary *result = @{
72
+ @"path": [NSString stringWithFormat:@"file://%@", filePath],
73
+ @"size": @(imageData.length),
74
+ @"mime": mime,
75
+ @"width": @(image.size.width),
76
+ @"height": @(image.size.height)
77
+ };
78
+
79
+ resolve(result);
80
+ }
81
+
82
+ @end
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "shakebug-react-native",
3
3
  "title": "shakebug-react-native",
4
- "version": "2.1.0",
4
+ "version": "2.2.1",
5
5
  "description": "Shakebug allows users to report the bug from your mobile phone for your application. Here users just need to shake their mobile and all the data regarding bugs & crashes can be seen by developers through their log in panel easily",
6
6
  "main": "src/index.tsx",
7
7
  "scripts": {
@@ -31,8 +31,6 @@
31
31
  "@react-navigation/native": "^6.1.9",
32
32
  "html2canvas": "^1.4.1",
33
33
  "react-native-logs": "^5.1.0",
34
- "react-native-safe-area-context": "^4.14.0",
35
- "react-native-screens": "^4.3.0",
36
34
  "rxjs": "^7.8.1",
37
35
  "typescript": "^5.3.3"
38
36
  },
@@ -42,7 +40,6 @@
42
40
  },
43
41
  "devDependencies": {
44
42
  "flow-bin": "^0.170.0",
45
- "html-webpack-plugin": "^5.5.1",
46
- "react-native-windows": "^0.63.16"
43
+ "html-webpack-plugin": "^5.5.1"
47
44
  }
48
45
  }
@@ -21,7 +21,6 @@ Pod::Spec.new do |s|
21
21
  s.source = { :git => "https://github.com/github_account/react-native-shakebug.git", :tag => "#{s.version}" }
22
22
 
23
23
  s.source_files = "ios/**/*.{h,c,cc,cpp,m,mm,swift}"
24
- s.dependency "ffmpeg-kit-ios-#{ENV['FFMPEGKIT_PACKAGE'] || 'min'}", ENV['FFMPEGKIT_PACKAGE_VERSION'] || '~> 6.0'
25
24
  s.requires_arc = true
26
25
 
27
26
  s.dependency "React"