shakebug-react-native 2.4.9 → 2.4.11

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 (51) hide show
  1. package/README.md +0 -12
  2. package/VideoPlayer/PlayVideo.tsx +4 -46
  3. package/VideoPlayer/index.js +6 -43
  4. package/android/src/main/java/com/shakebug/BaseUtils.java +7 -19
  5. package/android/src/main/java/com/shakebug/DeviceUtil.java +34 -21
  6. package/android/src/main/java/com/shakebug/ShakebugPackage.java +3 -3
  7. package/android/src/main/java/com/shakebug/UnitConverter.java +8 -8
  8. package/android/src/main/java/com/shakebug/VideoPlayerModule.java +81 -0
  9. package/android/src/main/java/com/shakebug/VideoTrimModule.java +387 -0
  10. package/android/src/main/java/com/shakebug/VideoTrimUtil.java +133 -0
  11. package/android/src/main/java/com/shakebug/adapters/VideoTrimmerAdapter.java +53 -0
  12. package/android/src/main/java/com/shakebug/callback/SingleCallback.java +0 -6
  13. package/android/src/main/java/com/shakebug/thread/BackgroundExecutor.java +1 -93
  14. package/android/src/main/java/com/shakebug/thread/UiThreadExecutor.java +0 -37
  15. package/android/src/main/java/com/shakebug/utils/StorageUtil.java +135 -0
  16. package/android/src/main/java/com/shakebug/utils/VideoTrimmerUtil.java +70 -0
  17. package/android/src/main/java/com/shakebug/widgets/RangeSeekBarView.java +534 -0
  18. package/android/src/main/java/com/shakebug/widgets/SpacesItemDecoration2.java +1 -2
  19. package/android/src/main/java/com/shakebug/widgets/VideoPlayerView.java +317 -0
  20. package/android/src/main/java/com/shakebug/widgets/VideoTrimmerView.java +520 -0
  21. package/android/src/main/res/drawable/ic_volume_off.xml +10 -0
  22. package/android/src/main/res/drawable/ic_volume_on.xml +10 -0
  23. package/android/src/main/res/layout/{video_player_view.xml → shakebug_video_player_view.xml} +29 -9
  24. package/ios/TrimVideo/ShakebugSDKVideoTrim.swift +389 -0
  25. package/ios/TrimVideo/VideoTrim-Bridging-Header.h +10 -0
  26. package/ios/TrimVideo/VideoTrim.m +23 -0
  27. package/ios/TrimVideo/VideoTrimmer.swift +810 -0
  28. package/ios/TrimVideo/VideoTrimmerThumb.swift +119 -0
  29. package/ios/TrimVideo/VideoTrimmerViewController.swift +322 -0
  30. package/ios/VideoPlayer/VideoPlayerModule.m +23 -7
  31. package/package.json +1 -1
  32. package/src/APIs/AddIssue.js +7 -5
  33. package/src/APIs/AddReview.js +5 -2
  34. package/src/APIs/CustomUserId.js +5 -2
  35. package/src/APIs/EndSession.js +3 -2
  36. package/src/APIs/Event.js +5 -2
  37. package/src/APIs/FetchRemoteCodeAPI.js +5 -2
  38. package/src/APIs/MatchKey.js +3 -2
  39. package/src/APIs/StartSession.js +44 -23
  40. package/src/Componanats/LoadingModal.js +59 -0
  41. package/src/Componanats/ShakeFunction.js +32 -14
  42. package/src/Screens/AddDetailsScreen.js +28 -31
  43. package/src/Screens/FirstScreen.js +15 -18
  44. package/src/Screens/Shakebug.js +11 -6
  45. package/src/Screens/TrimVideoScreen.js +37 -22
  46. package/src/index.tsx +7 -6
  47. package/trimVideo/src/index.tsx +12 -48
  48. package/Volumes:.fileloc +0 -8
  49. package/shakebug-react-native-2.4.8.tgz +0 -0
  50. /package/android/src/main/res/layout/{video_thumb_item_layout.xml → shakebug_video_thumb_item_layout.xml} +0 -0
  51. /package/android/src/main/res/layout/{video_trimmer_view.xml → shakebug_video_trimmer_view.xml} +0 -0
@@ -0,0 +1,119 @@
1
+ //
2
+ // VideoTrimmerThumb.swift
3
+ // Shakebug
4
+ //
5
+ // Created by ideveloper2 on 26/04/24.
6
+ // Copyright © 2024 Facebook. All rights reserved.
7
+ //
8
+
9
+ import UIKit
10
+
11
+ @available(iOS 13.0, *)
12
+ class VideoTrimmerThumb: UIView {
13
+ var isActive = false
14
+
15
+ var leadingChevronImageView = UIImageView(image: UIImage(systemName: "chevron.compact.left"))
16
+ var trailingChevronView = UIImageView(image: UIImage(systemName: "chevron.compact.right"))
17
+
18
+ var wrapperView = UIView()
19
+ var leadingView = UIView()
20
+ var trailingView = UIView()
21
+ var topView = UIView()
22
+ var bottomView = UIView()
23
+
24
+ let leadingGrabber = UIControl()
25
+ let trailingGrabber = UIControl()
26
+
27
+ let chevronWidth = CGFloat(16)
28
+ let edgeHeight = CGFloat(4)
29
+
30
+ // MARK: - Input
31
+ @objc private func x(_ sender: Any) {
32
+
33
+ }
34
+
35
+ // MARK: - Private
36
+ private func updateColor() {
37
+ let color = UIColor.systemYellow
38
+ leadingView.backgroundColor = color
39
+ trailingView.backgroundColor = color
40
+ topView.backgroundColor = color
41
+ bottomView.backgroundColor = color
42
+ }
43
+
44
+ private func setup() {
45
+
46
+ leadingChevronImageView.contentMode = .scaleAspectFill
47
+ trailingChevronView.contentMode = .scaleAspectFill
48
+
49
+ leadingChevronImageView.tintColor = .white
50
+ trailingChevronView.tintColor = .white
51
+
52
+ leadingChevronImageView.tintAdjustmentMode = .normal
53
+ trailingChevronView.tintAdjustmentMode = .normal
54
+
55
+ leadingView.layer.cornerRadius = 6
56
+ leadingView.layer.cornerCurve = .continuous
57
+ leadingView.layer.maskedCorners = [.layerMinXMaxYCorner, .layerMinXMinYCorner]
58
+
59
+ trailingView.layer.cornerRadius = 6
60
+ trailingView.layer.cornerCurve = .continuous
61
+ trailingView.layer.maskedCorners = [.layerMaxXMaxYCorner, .layerMaxXMinYCorner]
62
+
63
+ leadingView.addSubview(leadingChevronImageView)
64
+ trailingView.addSubview(trailingChevronView)
65
+
66
+ // wrapperView.layer.shadowColor = UIColor.black.cgColor
67
+ // wrapperView.layer.shadowOffset = .zero
68
+ // wrapperView.layer.shadowRadius = 2
69
+ // wrapperView.layer.shadowOpacity = 0.25
70
+
71
+ wrapperView.addSubview(leadingView)
72
+ wrapperView.addSubview(trailingView)
73
+ wrapperView.addSubview(topView)
74
+ wrapperView.addSubview(bottomView)
75
+ addSubview(wrapperView)
76
+
77
+ wrapperView.addSubview(leadingGrabber)
78
+ wrapperView.addSubview(trailingGrabber)
79
+
80
+ updateColor()
81
+ }
82
+
83
+
84
+
85
+ // MARK: - UIView
86
+
87
+ override func layoutSubviews() {
88
+ super.layoutSubviews()
89
+
90
+ let size = bounds.size
91
+
92
+ wrapperView.frame = CGRect(origin: .zero, size: size)
93
+
94
+ leadingView.frame = CGRect(x: 0, y: 0, width: chevronWidth, height: bounds.height)
95
+ trailingView.frame = CGRect(x: bounds.width - chevronWidth, y: 0, width: chevronWidth, height: bounds.height)
96
+ topView.frame = CGRect(x: chevronWidth, y: 0, width: bounds.width - chevronWidth * 2, height: edgeHeight)
97
+ bottomView.frame = CGRect(x: chevronWidth, y: bounds.height - edgeHeight, width: bounds.width - chevronWidth * 2, height: edgeHeight)
98
+
99
+ let chevronHorizontalInset = CGFloat(2)
100
+ let chevronVerticalInset = CGFloat(8)
101
+ let chevronFrame = CGRect(x: chevronHorizontalInset, y: chevronVerticalInset, width: chevronWidth - chevronHorizontalInset * 2, height: size.height - chevronVerticalInset * 2)
102
+
103
+ leadingChevronImageView.frame = chevronFrame
104
+ trailingChevronView.frame = chevronFrame
105
+
106
+ leadingGrabber.frame = leadingView.frame
107
+ trailingGrabber.frame = trailingView.frame
108
+ }
109
+
110
+ override init(frame: CGRect) {
111
+ super.init(frame: frame)
112
+ setup()
113
+ }
114
+
115
+ required init?(coder: NSCoder) {
116
+ super.init(coder: coder)
117
+ setup()
118
+ }
119
+ }
@@ -0,0 +1,322 @@
1
+ //
2
+ // VideoTrimmerViewController.swift
3
+ // Shakebug
4
+ //
5
+ // Created by ideveloper2 on 26/04/24.
6
+ // Copyright © 2024 Facebook. All rights reserved.
7
+ //
8
+
9
+ import UIKit
10
+ import AVKit
11
+
12
+ extension CMTime {
13
+ var displayString: String {
14
+ let offset = TimeInterval(seconds)
15
+ let numberOfNanosecondsFloat = (offset - TimeInterval(Int(offset))) * 1000.0
16
+ let nanoseconds = Int(numberOfNanosecondsFloat)
17
+ let formatter = DateComponentsFormatter()
18
+ formatter.unitsStyle = .positional
19
+ formatter.zeroFormattingBehavior = .pad
20
+ formatter.allowedUnits = [.minute, .second]
21
+ return String(format: "%@.%03d", formatter.string(from: offset) ?? "00:00", nanoseconds)
22
+ }
23
+ }
24
+
25
+ extension AVAsset {
26
+ var fullRange: CMTimeRange {
27
+ return CMTimeRange(start: .zero, duration: duration)
28
+ }
29
+ func trimmedComposition(_ range: CMTimeRange) -> AVAsset {
30
+ guard CMTimeRangeEqual(fullRange, range) == false else {return self}
31
+
32
+ let composition = AVMutableComposition()
33
+ try? composition.insertTimeRange(range, of: self, at: .zero)
34
+
35
+ if let videoTrack = tracks(withMediaType: .video).first {
36
+ composition.tracks.forEach {$0.preferredTransform = videoTrack.preferredTransform}
37
+ }
38
+ return composition
39
+ }
40
+ }
41
+
42
+ @available(iOS 13.0, *)
43
+ class VideoTrimmerViewController: UIViewController {
44
+ var asset: AVAsset!
45
+ var maximumDuration: Int?
46
+ var minimumDuration: Int?
47
+ var cancelBtnText = "Cancel"
48
+ var saveButtonText = "Save"
49
+ var cancelBtnClicked: (() -> Void)?
50
+ var saveBtnClicked: ((CMTimeRange) -> Void)?
51
+
52
+ let playerController = AVPlayerViewController()
53
+ var trimmer: VideoTrimmer!
54
+ var timingStackView: UIStackView!
55
+ var leadingTrimLabel: UILabel!
56
+ var currentTimeLabel: UILabel!
57
+ var trailingTrimLabel: UILabel!
58
+
59
+ private var btnStackView: UIStackView!
60
+ private var cancelBtn: UIButton!
61
+ private var playBtn: UIButton!
62
+ private var saveBtn: UIButton!
63
+ private let playIcon = UIImage(systemName: "play.fill")
64
+ private let pauseIcon = UIImage(systemName: "pause.fill")
65
+
66
+ private var wasPlaying = false
67
+ private var player: AVPlayer! {playerController.player}
68
+ private var timeObserverToken: Any?
69
+
70
+
71
+ // MARK: - Input
72
+ @objc private func didBeginTrimming(_ sender: VideoTrimmer) {
73
+ updateLabels()
74
+
75
+ wasPlaying = (player.timeControlStatus != .paused)
76
+ player.pause()
77
+
78
+ updatePlayerAsset()
79
+ }
80
+
81
+ @objc private func didEndTrimming(_ sender: VideoTrimmer) {
82
+ updateLabels()
83
+
84
+ updatePlayerAsset()
85
+
86
+ if wasPlaying == true {
87
+ player.play()
88
+ }
89
+ }
90
+
91
+ @objc private func selectedRangeDidChanged(_ sender: VideoTrimmer) {
92
+ updateLabels()
93
+ if trimmer.trimmingState == .leading {
94
+ player.seek(to: trimmer.selectedRange.start, toleranceBefore: .zero, toleranceAfter: .zero)
95
+ } else if trimmer.trimmingState == .trailing {
96
+ player.seek(to: trimmer.selectedRange.end, toleranceBefore: .zero, toleranceAfter: .zero)
97
+ }
98
+ }
99
+
100
+ @objc private func didBeginScrubbing(_ sender: VideoTrimmer) {
101
+ updateLabels()
102
+
103
+ wasPlaying = (player.timeControlStatus != .paused)
104
+ player.pause()
105
+ }
106
+
107
+ @objc private func didEndScrubbing(_ sender: VideoTrimmer) {
108
+ updateLabels()
109
+
110
+ if wasPlaying == true {
111
+ player.play()
112
+ }
113
+ }
114
+
115
+ @objc private func progressDidChanged(_ sender: VideoTrimmer) {
116
+ updateLabels()
117
+
118
+ player.seek(to: trimmer.progress, toleranceBefore: .zero, toleranceAfter: .zero)
119
+ }
120
+
121
+ // MARK: - Private
122
+ private func updateLabels() {
123
+ leadingTrimLabel.text = trimmer.selectedRange.start.displayString
124
+ currentTimeLabel.text = trimmer.progress.displayString
125
+ trailingTrimLabel.text = trimmer.selectedRange.end.displayString
126
+ }
127
+
128
+ private func updatePlayerAsset() {
129
+ if player.currentItem == nil {
130
+ let item = AVPlayerItem(asset: asset)
131
+ player.replaceCurrentItem(with: item)
132
+ }
133
+
134
+ if trimmer.trimmingState == .none {
135
+ player.currentItem?.forwardPlaybackEndTime = trimmer.selectedRange.end
136
+
137
+ let currentTime = player.currentTime().seconds
138
+ let endTime = trimmer.selectedRange.end.seconds
139
+ let startTime = trimmer.selectedRange.start.seconds
140
+
141
+ if currentTime < startTime || currentTime >= endTime - 0.05 {
142
+ player.seek(to: trimmer.selectedRange.start, toleranceBefore: .zero, toleranceAfter: .zero)
143
+ }
144
+ } else {
145
+ player.currentItem?.forwardPlaybackEndTime = .invalid
146
+ }
147
+ }
148
+
149
+ // MARK: - UIViewController
150
+ override func viewDidLoad() {
151
+ super.viewDidLoad()
152
+
153
+ view.backgroundColor = .black
154
+
155
+ // bottom action buttons
156
+ cancelBtn = UIButton(type: .system)
157
+ cancelBtn.setTitle(cancelBtnText, for: .normal)
158
+ cancelBtn.titleLabel?.font = .systemFont(ofSize: 18)
159
+ cancelBtn.setTitleColor(.white, for: .normal)
160
+ cancelBtn.addTarget(self, action: #selector(onCancelBtnClicked), for: .touchUpInside)
161
+
162
+
163
+ playBtn = UIButton(type: .system)
164
+ playBtn.setImage(playIcon, for: .normal)
165
+ playBtn.tintColor = .systemBlue
166
+ playBtn.addTarget(self, action: #selector(togglePlay(sender:)), for: .touchUpInside)
167
+
168
+ saveBtn = UIButton(type: .system)
169
+ saveBtn.setTitle(saveButtonText, for: .normal)
170
+ saveBtn.titleLabel?.font = .systemFont(ofSize: 18)
171
+ saveBtn.setTitleColor(.systemBlue, for: .normal)
172
+ saveBtn.addTarget(self, action: #selector(onSaveBtnClicked), for: .touchUpInside)
173
+
174
+ btnStackView = UIStackView(arrangedSubviews: [cancelBtn, playBtn, saveBtn])
175
+ btnStackView.axis = .horizontal
176
+ btnStackView.alignment = .fill
177
+ btnStackView.distribution = .fillEqually
178
+ btnStackView.spacing = UIStackView.spacingUseSystem
179
+ view.addSubview(btnStackView)
180
+ btnStackView.translatesAutoresizingMaskIntoConstraints = false
181
+ NSLayoutConstraint.activate([
182
+ btnStackView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor, constant: 16),
183
+ btnStackView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor, constant: -16),
184
+ btnStackView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -16),
185
+ ])
186
+
187
+ // time labels
188
+ leadingTrimLabel = UILabel()
189
+ leadingTrimLabel.font = UIFont.preferredFont(forTextStyle: .caption1)
190
+ leadingTrimLabel.textAlignment = .left
191
+ leadingTrimLabel.textColor = .white
192
+
193
+ currentTimeLabel = UILabel()
194
+ currentTimeLabel.font = UIFont.preferredFont(forTextStyle: .caption1)
195
+ currentTimeLabel.textAlignment = .center
196
+ currentTimeLabel.textColor = .white
197
+
198
+ trailingTrimLabel = UILabel()
199
+ trailingTrimLabel.font = UIFont.preferredFont(forTextStyle: .caption1)
200
+ trailingTrimLabel.textAlignment = .right
201
+ trailingTrimLabel.textColor = .white
202
+
203
+ timingStackView = UIStackView(arrangedSubviews: [leadingTrimLabel, currentTimeLabel, trailingTrimLabel])
204
+ timingStackView.axis = .horizontal
205
+ timingStackView.alignment = .fill
206
+ timingStackView.distribution = .fillEqually
207
+ timingStackView.spacing = UIStackView.spacingUseSystem
208
+ view.addSubview(timingStackView)
209
+ timingStackView.translatesAutoresizingMaskIntoConstraints = false
210
+ NSLayoutConstraint.activate([
211
+ timingStackView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor, constant: 16),
212
+ timingStackView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor, constant: -16),
213
+ timingStackView.bottomAnchor.constraint(equalTo: btnStackView.topAnchor, constant: -8),
214
+ ])
215
+
216
+ // THIS IS WHERE WE SETUP THE VIDEOTRIMMER:
217
+ trimmer = VideoTrimmer()
218
+ trimmer.asset = asset // this should happen before trimmer.selectedRange below otherwise its didSet will override
219
+ trimmer.minimumDuration = CMTime(seconds: 1, preferredTimescale: 600)
220
+
221
+ if maximumDuration != nil {
222
+ trimmer.maximumDuration = CMTime(seconds: max(1, Double(maximumDuration!)), preferredTimescale: 600) // minimum 1 second
223
+
224
+ // guard check to make sure max duration can only <= asset.duration
225
+ if CMTimeCompare(trimmer.maximumDuration, asset.duration) == 1 {
226
+ trimmer.maximumDuration = asset.duration
227
+ }
228
+
229
+ trimmer.selectedRange = CMTimeRange(start: .zero, end: trimmer.maximumDuration)
230
+ }
231
+
232
+ if minimumDuration != nil {
233
+ trimmer.minimumDuration = CMTime(seconds: max(1, Double(minimumDuration!)), preferredTimescale: 600) // minimum 1 second
234
+ }
235
+
236
+ trimmer.addTarget(self, action: #selector(didBeginTrimming(_:)), for: VideoTrimmer.didBeginTrimming)
237
+ trimmer.addTarget(self, action: #selector(didEndTrimming(_:)), for: VideoTrimmer.didEndTrimming)
238
+ trimmer.addTarget(self, action: #selector(selectedRangeDidChanged(_:)), for: VideoTrimmer.selectedRangeChanged)
239
+ trimmer.addTarget(self, action: #selector(didBeginScrubbing(_:)), for: VideoTrimmer.didBeginScrubbing)
240
+ trimmer.addTarget(self, action: #selector(didEndScrubbing(_:)), for: VideoTrimmer.didEndScrubbing)
241
+ trimmer.addTarget(self, action: #selector(progressDidChanged(_:)), for: VideoTrimmer.progressChanged)
242
+ view.addSubview(trimmer)
243
+ trimmer.translatesAutoresizingMaskIntoConstraints = false
244
+ NSLayoutConstraint.activate([
245
+ trimmer.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor),
246
+ trimmer.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor),
247
+ trimmer.bottomAnchor.constraint(equalTo: timingStackView.topAnchor, constant: -16),
248
+ trimmer.heightAnchor.constraint(equalToConstant: 50),
249
+ ])
250
+
251
+ playerController.showsPlaybackControls = false // hide control buttons
252
+ if #available(iOS 16.0, *) {
253
+ playerController.allowsVideoFrameAnalysis = false // hide live text
254
+ }
255
+ playerController.player = AVPlayer()
256
+ try? AVAudioSession.sharedInstance().setCategory(.playback, mode: .default, options: []) // this is to play audio even when device is in silent mode
257
+ addChild(playerController)
258
+ view.addSubview(playerController.view)
259
+ playerController.view.translatesAutoresizingMaskIntoConstraints = false
260
+ NSLayoutConstraint.activate([
261
+ playerController.view.leadingAnchor.constraint(equalTo: view.leadingAnchor),
262
+ playerController.view.trailingAnchor.constraint(equalTo: view.trailingAnchor),
263
+ playerController.view.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
264
+ playerController.view.bottomAnchor.constraint(equalTo: trimmer.topAnchor, constant: -16)
265
+ ])
266
+
267
+ updatePlayerAsset()
268
+
269
+ timeObserverToken = player.addPeriodicTimeObserver(forInterval: CMTime(value: 1, timescale: 30), queue: .main) { [weak self] time in
270
+ guard let self = self else {return}
271
+
272
+ self.currentTimeLabel.text = time.displayString
273
+ self.trimmer.progress = time
274
+
275
+ if self.player.timeControlStatus == .playing {
276
+ self.playBtn.setImage(self.pauseIcon, for: .normal)
277
+ } else {
278
+ self.playBtn.setImage(self.playIcon, for: .normal)
279
+ }
280
+ }
281
+
282
+ updateLabels()
283
+ }
284
+
285
+ override func viewWillDisappear(_ animated: Bool) {
286
+ super.viewWillDisappear(animated)
287
+
288
+ player.pause()
289
+ if timeObserverToken != nil {
290
+ player.removeTimeObserver(timeObserverToken as Any)
291
+ timeObserverToken = nil
292
+ }
293
+ playerController.player = nil
294
+ playerController.dismiss(animated: false, completion: nil)
295
+ }
296
+
297
+ @objc private func togglePlay(sender: UIButton) {
298
+ if player.timeControlStatus == .playing {
299
+ player.pause()
300
+ } else {
301
+ let currentTime = player.currentTime().seconds
302
+ let endTime = trimmer.selectedRange.end.seconds
303
+ let startTime = trimmer.selectedRange.start.seconds
304
+
305
+ if currentTime >= endTime - 0.05 || currentTime < startTime {
306
+ player.seek(to: trimmer.selectedRange.start, toleranceBefore: .zero, toleranceAfter: .zero) { _ in
307
+ self.player.play()
308
+ }
309
+ } else {
310
+ player.play()
311
+ }
312
+ }
313
+ }
314
+
315
+ @objc func onSaveBtnClicked() {
316
+ saveBtnClicked?(trimmer.selectedRange)
317
+ }
318
+
319
+ @objc func onCancelBtnClicked() {
320
+ cancelBtnClicked?()
321
+ }
322
+ }
@@ -2,24 +2,40 @@
2
2
  // VideoPlayerModule.m
3
3
  // Shakebug
4
4
  //
5
- // Created by ideveloper2 on 23/04/24.
6
- // Copyright © 2024 Facebook. All rights reserved.
7
- //
8
5
 
9
6
  #import "VideoPlayerModule.h"
10
7
  #import <React/RCTLog.h>
8
+ #import <React/RCTUtils.h>
11
9
 
12
10
  @implementation ShakebugSDKVideoPlayerModule
13
11
 
14
- RCT_EXPORT_MODULE();
12
+ RCT_EXPORT_MODULE(ShakebugSDKVideoPlayerModule);
13
+
14
+ + (BOOL)requiresMainQueueSetup {
15
+ return YES;
16
+ }
15
17
 
16
18
  RCT_EXPORT_METHOD(playVideo:(NSString *)videoURLString) {
17
- NSURL *videoURL = [NSURL URLWithString:videoURLString];
19
+ if (!videoURLString || videoURLString.length == 0) {
20
+ RCTLogError(@"Invalid video URL");
21
+ return;
22
+ }
23
+
24
+ NSURL *videoURL;
25
+ if ([videoURLString hasPrefix:@"http://"] || [videoURLString hasPrefix:@"https://"]) {
26
+ videoURL = [NSURL URLWithString:videoURLString];
27
+ } else {
28
+ NSString *cleanPath = [videoURLString stringByReplacingOccurrencesOfString:@"file://" withString:@""];
29
+ videoURL = [NSURL fileURLWithPath:cleanPath];
30
+ }
31
+
18
32
  if (videoURL) {
19
33
  dispatch_async(dispatch_get_main_queue(), ^{
20
34
  ShakebugSDKVideoPlayerViewController *videoPlayerVC = [[ShakebugSDKVideoPlayerViewController alloc] initWithVideoURL:videoURL];
21
- UIViewController *rootViewController = [[[[UIApplication sharedApplication] delegate] window] rootViewController];
22
- [rootViewController presentViewController:videoPlayerVC animated:YES completion:nil];
35
+ UIViewController *rootViewController = RCTPresentedViewController();
36
+ if (rootViewController) {
37
+ [rootViewController presentViewController:videoPlayerVC animated:YES completion:nil];
38
+ }
23
39
  });
24
40
  } else {
25
41
  RCTLogError(@"Invalid video URL");
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.4.9",
4
+ "version": "2.4.11",
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
  "types": "src/index.tsx",
@@ -2,10 +2,11 @@ import { NativeModules, Platform } from "react-native";
2
2
  import DeviceInfo from "../../DeviceInfo";
3
3
  import NetInfo from "../../NetInfo/src";
4
4
 
5
- const BASE_URL = global.ShakebugSDKEndPointURL;
6
- const API_KEY = global.ShakebugSDKEndPointURLheaderKey;
7
5
 
8
6
  async function AddIssueApi(session_id, application_id, path, isVideo, desc, email) {
7
+ const BASE_URL = global.ShakebugSDKEndPointURL || "https://www.shakebug.com/api/v1.6/webservice.php/";
8
+ const API_KEY = global.ShakebugSDKEndPointURLheaderKey || "MarchShake2022";
9
+
9
10
  try {
10
11
 
11
12
  const { ShakebugSDKSharedPreferencesModule } = NativeModules;
@@ -30,7 +31,7 @@ async function AddIssueApi(session_id, application_id, path, isVideo, desc, emai
30
31
  let totalMemory = await DeviceInfo.getTotalMemory();
31
32
  let usedMemory = await DeviceInfo.getUsedMemory();
32
33
  let memoryInBytes = totalMemory - usedMemory;
33
-
34
+
34
35
  let memory = "";
35
36
  if (memoryInBytes >= 1024 * 1024 * 1024) {
36
37
  memory = (memoryInBytes / (1024 * 1024 * 1024)).toFixed(2) + " GB";
@@ -50,7 +51,7 @@ async function AddIssueApi(session_id, application_id, path, isVideo, desc, emai
50
51
  formData.append("applicationsid", application_id);
51
52
  formData.append("session_id", session_id);
52
53
  formData.append("batteryLevel", batteryLevel);
53
- formData.append("image", {uri: media, name: name, type: type});
54
+ formData.append("image", { uri: media, name: name, type: type });
54
55
  formData.append("memory", memory);
55
56
  formData.append("email", email);
56
57
  formData.append("devicemodel", `${architecture[0]} -- ${model}`);
@@ -63,7 +64,8 @@ async function AddIssueApi(session_id, application_id, path, isVideo, desc, emai
63
64
  formData.append("custom_user_id", Custom_User_Id || "")
64
65
  formData.append("sdk_version", global.sdk_version)
65
66
  formData.append("platform", Platform.OS)
66
-
67
+ formData.append("sdk_platform", global.sdk_platform)
68
+ formData.append("sdk_platform_version", global.sdk_platform_version)
67
69
 
68
70
  const response = await fetch(BASE_URL, {
69
71
  method: 'POST',
@@ -1,9 +1,10 @@
1
1
  import { NativeModules } from "react-native";
2
2
 
3
- const BASE_URL = global.ShakebugSDKEndPointURL;
4
- const API_KEY = global.ShakebugSDKEndPointURLheaderKey;
5
3
 
6
4
  async function AddReviewApi(rating, review, applicationsid, session_id) {
5
+ const BASE_URL = global.ShakebugSDKEndPointURL || "https://www.shakebug.com/api/v1.6/webservice.php/";
6
+ const API_KEY = global.ShakebugSDKEndPointURLheaderKey || "MarchShake2022";
7
+
7
8
 
8
9
  const { ShakebugSDKSharedPreferencesModule } = NativeModules;
9
10
 
@@ -18,6 +19,8 @@ async function AddReviewApi(rating, review, applicationsid, session_id) {
18
19
  formData.append("session_id", session_id);
19
20
  formData.append("appVersion", global.sdk_version);
20
21
  formData.append("custom_user_id", Custom_User_Id || "");
22
+ formData.append("sdk_platform", global.sdk_platform)
23
+ formData.append("sdk_platform_version", global.sdk_platform_version)
21
24
 
22
25
  const response = await fetch(BASE_URL, {
23
26
  method: 'POST',
@@ -1,9 +1,10 @@
1
1
  import { NativeModules } from "react-native";
2
2
 
3
- const BASE_URL = global.ShakebugSDKEndPointURL;
4
- const API_KEY = global.ShakebugSDKEndPointURLheaderKey;
5
3
 
6
4
  async function CustomUserIdApi(id, name, email, country, other, applicationsid) {
5
+ const BASE_URL = global.ShakebugSDKEndPointURL || "https://www.shakebug.com/api/v1.6/webservice.php/";
6
+ const API_KEY = global.ShakebugSDKEndPointURLheaderKey || "MarchShake2022";
7
+
7
8
 
8
9
  const { ShakebugSDKSharedPreferencesModule } = NativeModules;
9
10
 
@@ -19,6 +20,8 @@ async function CustomUserIdApi(id, name, email, country, other, applicationsid)
19
20
  formData.append("country", country?.trim());
20
21
  formData.append("other", other);
21
22
  formData.append("applicationsid", applicationsid);
23
+ formData.append("sdk_platform", global.sdk_platform)
24
+ formData.append("sdk_platform_version", global.sdk_platform_version)
22
25
 
23
26
  const response = await fetch(BASE_URL, {
24
27
  method: 'POST',
@@ -1,7 +1,8 @@
1
- const BASE_URL = global.ShakebugSDKEndPointURL;
2
- const API_KEY = global.ShakebugSDKEndPointURLheaderKey;
3
1
 
4
2
  async function SessionEndApi(session_id) {
3
+ const BASE_URL = global.ShakebugSDKEndPointURL || "https://www.shakebug.com/api/v1.6/webservice.php/";
4
+ const API_KEY = global.ShakebugSDKEndPointURLheaderKey || "MarchShake2022";
5
+
5
6
  try {
6
7
 
7
8
  const formData = new FormData();
package/src/APIs/Event.js CHANGED
@@ -2,10 +2,11 @@ import { NativeModules } from "react-native";
2
2
  import DeviceInfo from "../../DeviceInfo";
3
3
  import NetInfo from "../../NetInfo/src";
4
4
 
5
- const BASE_URL = global.ShakebugSDKEndPointURL;
6
- const API_KEY = global.ShakebugSDKEndPointURLheaderKey;
7
5
 
8
6
  async function EventApi(application_id, name, value, session_id) {
7
+ const BASE_URL = global.ShakebugSDKEndPointURL || "https://www.shakebug.com/api/v1.6/webservice.php/";
8
+ const API_KEY = global.ShakebugSDKEndPointURLheaderKey || "MarchShake2022";
9
+
9
10
  try {
10
11
 
11
12
  const { ShakebugSDKSharedPreferencesModule } = NativeModules;
@@ -20,6 +21,8 @@ async function EventApi(application_id, name, value, session_id) {
20
21
  formData.append("session_id", session_id);
21
22
  formData.append("custom_user_id", Custom_User_Id || "")
22
23
  formData.append("sdk_version", global.sdk_version)
24
+ formData.append("sdk_platform", global.sdk_platform)
25
+ formData.append("sdk_platform_version", global.sdk_platform_version)
23
26
 
24
27
  const response = await fetch(BASE_URL, {
25
28
  method: 'POST',
@@ -1,10 +1,11 @@
1
1
  import { NativeModules } from "react-native";
2
2
  import DeviceInfo from "../../DeviceInfo";
3
3
 
4
- const BASE_URL = global.ShakebugSDKEndPointURL;
5
- const API_KEY = global.ShakebugSDKEndPointURLheaderKey;
6
4
 
7
5
  async function FetchRemoteCodeAPI(config_key, applicationsid, session_id) {
6
+ const BASE_URL = global.ShakebugSDKEndPointURL || "https://www.shakebug.com/api/v1.6/webservice.php/";
7
+ const API_KEY = global.ShakebugSDKEndPointURLheaderKey || "MarchShake2022";
8
+
8
9
 
9
10
  try {
10
11
  const { ShakebugSDKSharedPreferencesModule } = NativeModules;
@@ -20,6 +21,8 @@ async function FetchRemoteCodeAPI(config_key, applicationsid, session_id) {
20
21
  formData.append("appVersion", DeviceInfo?.getVersion());
21
22
  formData.append("session_id", session_id);
22
23
  formData.append("custom_user_id", Custom_User_Id || "");
24
+ formData.append("sdk_platform", global.sdk_platform)
25
+ formData.append("sdk_platform_version", global.sdk_platform_version)
23
26
 
24
27
  const response = await fetch(BASE_URL, {
25
28
  method: "POST",
@@ -1,7 +1,8 @@
1
- const BASE_URL = global.ShakebugSDKEndPointURL;
2
- const API_KEY = global.ShakebugSDKEndPointURLheaderKey;
3
1
 
4
2
  async function MatchKeyApi(appkey, BundleId) {
3
+ const BASE_URL = global.ShakebugSDKEndPointURL || "https://www.shakebug.com/api/v1.6/webservice.php/";
4
+ const API_KEY = global.ShakebugSDKEndPointURLheaderKey || "MarchShake2022";
5
+
5
6
 
6
7
  const formData = new FormData();
7
8
  formData.append("method", "matchKeys")