shakebug-react-native 2.4.14 → 2.4.16

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 (32) hide show
  1. package/README.md +6 -0
  2. package/android/src/main/java/com/shakebug/ConnectivityReceiver.java +12 -7
  3. package/android/src/main/java/com/shakebug/DrawingView.java +13 -3
  4. package/android/src/main/java/com/shakebug/RecordScreenModule.java +6 -3
  5. package/android/src/main/java/com/shakebug/ViewShot.java +1 -0
  6. package/ios/CustomScreenShot/ShakebugSDKCustomScreenCapture.m +6 -2
  7. package/ios/ScreenShot/ShakebugCapture.m +3 -1
  8. package/ios/SketchCanvas/DrawingView.m +14 -1
  9. package/package.json +1 -1
  10. package/shakebug-react-native-2.4.15.tgz +0 -0
  11. package/src/APIs/MatchKey.js +1 -1
  12. package/src/Assets/images/shake.png +0 -0
  13. package/src/Assets/images/undo.png +0 -0
  14. package/src/Assets/images/undo@2x.png +0 -0
  15. package/src/Assets/images/undo@3x.png +0 -0
  16. package/src/Componanats/CustomAlert.js +8 -4
  17. package/src/Componanats/Icons.js +278 -0
  18. package/src/Componanats/KeyboardAvoidingWrapper.js +31 -39
  19. package/src/Componanats/LoadingModal.js +7 -4
  20. package/src/Componanats/NavigationContext.js +8 -1
  21. package/src/Componanats/ReviewModal.js +18 -11
  22. package/src/Componanats/SafeAreaHelper.js +70 -0
  23. package/src/Componanats/ShakeFunction.js +655 -364
  24. package/src/Componanats/ShakebugBottomSheet.js +729 -0
  25. package/src/Componanats/Theme.js +96 -0
  26. package/src/Componanats/ZoomableImage.js +350 -0
  27. package/src/Componanats/localization.js +111 -82
  28. package/src/Screens/AddDetailsScreen.js +800 -439
  29. package/src/Screens/FirstScreen.js +950 -540
  30. package/src/Screens/Shakebug.js +78 -44
  31. package/src/Screens/TrimVideoScreen.js +40 -7
  32. package/src/index.tsx +16 -7
package/README.md CHANGED
@@ -220,6 +220,12 @@ export default App = () => {
220
220
  <td>If you have on-premise hosting plan then following prop will be used.</td>
221
221
  <td></td>
222
222
  </tr>
223
+ <tr>
224
+ <td>theme</td>
225
+ <td>String ("auto" | "light" | "dark")</td>
226
+ <td>Set theme mode for Shakebug SDK screens. Defaults to "auto" to automatically adapt to the application and system theme.</td>
227
+ <td>"auto"</td>
228
+ </tr>
223
229
  </table>
224
230
 
225
231
  ## Methods
@@ -39,7 +39,7 @@ public abstract class ConnectivityReceiver {
39
39
  private final WifiManager mWifiManager;
40
40
  private final TelephonyManager mTelephonyManager;
41
41
  private final ReactApplicationContext mReactContext;
42
- public boolean hasListener = false;
42
+ public boolean hasListener = true;
43
43
 
44
44
  @Nonnull
45
45
  private ConnectionType mConnectionType = ConnectionType.UNKNOWN;
@@ -125,16 +125,21 @@ public abstract class ConnectivityReceiver {
125
125
  mConnectionType = connectionType;
126
126
  mCellularGeneration = cellularGeneration;
127
127
  mIsInternetReachable = isInternetReachable;
128
- if (hasListener) {
129
- sendConnectivityChangedEvent();
130
- }
128
+ sendConnectivityChangedEvent();
131
129
  }
132
130
  }
133
131
 
134
132
  protected void sendConnectivityChangedEvent() {
135
- getReactContext()
136
- .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
137
- .emit("netInfo.networkStatusDidChange", createConnectivityEventMap(null));
133
+ ReactApplicationContext reactContext = getReactContext();
134
+ if (reactContext != null && reactContext.hasActiveCatalystInstance()) {
135
+ try {
136
+ reactContext
137
+ .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
138
+ .emit("netInfo.networkStatusDidChange", createConnectivityEventMap(null));
139
+ } catch (Exception e) {
140
+ // Ignore exception if emitter is not yet ready
141
+ }
142
+ }
138
143
  }
139
144
 
140
145
  protected WritableMap createConnectivityEventMap(@Nullable final String requestedInterface) {
@@ -53,11 +53,21 @@ public class DrawingView extends View {
53
53
 
54
54
  @Override
55
55
  public boolean onTouchEvent(MotionEvent event) {
56
- float x = event.getX();
57
- float y = event.getY();
56
+ if (canvas == null || bitmap == null || getWidth() <= 0 || getHeight() <= 0) {
57
+ return false;
58
+ }
59
+
60
+ float rawX = event.getX();
61
+ float rawY = event.getY();
62
+ float x = Math.max(0, Math.min(getWidth(), rawX));
63
+ float y = Math.max(0, Math.min(getHeight(), rawY));
58
64
 
59
65
  switch (event.getAction()) {
60
66
  case MotionEvent.ACTION_DOWN:
67
+ // Only allow drawing to start strictly inside the view boundaries
68
+ if (rawX < 0 || rawX > getWidth() || rawY < 0 || rawY > getHeight()) {
69
+ return false;
70
+ }
61
71
  lastX = x;
62
72
  lastY = y;
63
73
  return true;
@@ -65,7 +75,7 @@ public class DrawingView extends View {
65
75
  float dx = Math.abs(x - lastX);
66
76
  float dy = Math.abs(y - lastY);
67
77
  if (dx >= 4 || dy >= 4) {
68
- // Draw on the internal bitmap canvas
78
+ // Draw on the internal bitmap canvas (strictly clamped to image boundaries)
69
79
  canvas.drawLine(lastX, lastY, x, y, paint);
70
80
  invalidate();
71
81
  lastX = x;
@@ -66,19 +66,22 @@ public class RecordScreenModule extends ReactContextBaseJavaModule implements HB
66
66
  if (requestCode == SCREEN_RECORD_REQUEST_CODE) {
67
67
  if (resultCode == AppCompatActivity.RESULT_OK) {
68
68
  hbRecorder.startScreenRecording(intent, resultCode);
69
+ if (startPromise != null) {
70
+ startPromise.resolve("started");
71
+ startPromise = null;
72
+ }
69
73
  } else {
70
74
  if (startPromise != null) {
71
75
  startPromise.resolve("permission_error");
76
+ startPromise = null;
72
77
  }
73
78
  }
74
79
  } else {
75
80
  if (startPromise != null) {
76
81
  startPromise.reject("404", "cancel!");
82
+ startPromise = null;
77
83
  }
78
84
  }
79
- if (startPromise != null) {
80
- startPromise.resolve("started");
81
- }
82
85
  }
83
86
  };
84
87
 
@@ -373,6 +373,7 @@ public class ViewShot implements UIBlock {
373
373
  // Debug.waitForDebugger();
374
374
 
375
375
  final Canvas c = new Canvas(bitmap);
376
+ c.drawColor(Color.WHITE);
376
377
  view.draw(c);
377
378
 
378
379
  //after view is drawn, go through children
@@ -26,9 +26,13 @@ RCT_EXPORT_METHOD(captureScreen:(RCTPromiseResolveBlock)resolve
26
26
  return;
27
27
  }
28
28
 
29
- // Create a context for capturing all windows
29
+ // Create a context for capturing all windows with solid white base
30
30
  UIScreen *mainScreen = [UIScreen mainScreen];
31
- UIGraphicsBeginImageContextWithOptions(mainScreen.bounds.size, NO, mainScreen.scale);
31
+ UIGraphicsBeginImageContextWithOptions(mainScreen.bounds.size, YES, mainScreen.scale);
32
+
33
+ // Pre-fill with clean white background so transparent window roots don't render black
34
+ [[UIColor whiteColor] setFill];
35
+ UIRectFill(mainScreen.bounds);
32
36
 
33
37
  // Render each window onto the context
34
38
  for (UIWindow *window in windows) {
@@ -125,7 +125,9 @@ RCT_EXPORT_METHOD(captureRef:(nonnull NSNumber *)target
125
125
  scrollView.frame = CGRectMake(0, 0, scrollView.contentSize.width, scrollView.contentSize.height);
126
126
  }
127
127
 
128
- UIGraphicsBeginImageContextWithOptions(size, NO, 0);
128
+ UIGraphicsBeginImageContextWithOptions(size, YES, 0);
129
+ [[UIColor whiteColor] setFill];
130
+ UIRectFill((CGRect){CGPointZero, size});
129
131
 
130
132
  if (renderInContext) {
131
133
  [rendered.layer renderInContext: UIGraphicsGetCurrentContext()];
@@ -41,6 +41,7 @@
41
41
  self.paths = [NSMutableArray array];
42
42
  self.pathColors = [NSMutableArray array]; // Initialize the colors array
43
43
  self.backgroundColor = [UIColor clearColor];
44
+ self.clipsToBounds = YES;
44
45
  }
45
46
 
46
47
  - (void)setColor:(UIColor *)color {
@@ -61,6 +62,11 @@
61
62
  UITouch *touch = [touches anyObject];
62
63
  CGPoint touchPoint = [touch locationInView:self];
63
64
 
65
+ // Do not allow drawing to start outside image bounds
66
+ if (!CGRectContainsPoint(self.bounds, touchPoint)) {
67
+ return;
68
+ }
69
+
64
70
  self.path = [UIBezierPath bezierPath];
65
71
  self.path.lineWidth = self.pathWidth; // Set the line width for the new path
66
72
  [self.path moveToPoint:touchPoint];
@@ -70,9 +76,16 @@
70
76
  }
71
77
 
72
78
  - (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
79
+ if (!self.path) return;
73
80
  UITouch *touch = [touches anyObject];
74
81
  CGPoint touchPoint = [touch locationInView:self];
75
- [self.path addLineToPoint:touchPoint];
82
+
83
+ // Clamp to image bounds so stroke never extends outside
84
+ CGFloat clampedX = MAX(0, MIN(self.bounds.size.width, touchPoint.x));
85
+ CGFloat clampedY = MAX(0, MIN(self.bounds.size.height, touchPoint.y));
86
+ CGPoint clampedPoint = CGPointMake(clampedX, clampedY);
87
+
88
+ [self.path addLineToPoint:clampedPoint];
76
89
  [self setNeedsDisplay];
77
90
  }
78
91
 
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.14",
4
+ "version": "2.4.16",
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",
Binary file
@@ -6,7 +6,7 @@ async function MatchKeyApi(appkey, BundleId) {
6
6
 
7
7
  const formData = new FormData();
8
8
  formData.append("method", "matchKeys")
9
- formData.append("bundleid", BundleId)
9
+ formData.append("bundleid", "com.softnoesis.financeeye")
10
10
  formData.append("appkey", appkey)
11
11
 
12
12
 
Binary file
Binary file
Binary file
Binary file
@@ -1,7 +1,10 @@
1
1
  import React from 'react';
2
- import { View, Text, Button, StyleSheet, Modal, TouchableOpacity } from 'react-native';
2
+ import { View, Text, Button, StyleSheet, Modal, TouchableOpacity, useColorScheme } from 'react-native';
3
+ import { isShakebugDark } from './Theme';
3
4
 
4
- const CustomeAlert = ({color, isVisible, OnPrees, text = ""}) => {
5
+ const CustomeAlert = ({color = '#313A46', isVisible, OnPrees, text = ""}) => {
6
+ const colorScheme = useColorScheme();
7
+ const isDark = isShakebugDark(colorScheme);
5
8
 
6
9
  return (
7
10
  <Modal
@@ -13,17 +16,18 @@ const CustomeAlert = ({color, isVisible, OnPrees, text = ""}) => {
13
16
  <View
14
17
  style={[
15
18
  styles.container, {
19
+ backgroundColor: isDark ? '#2b2f38' : '#fff',
16
20
  height: (text && text.length > 120) ? 300 : (text && text.length < 50) ? 170 : 200
17
21
  }]}
18
22
  >
19
- <Text style={styles.text}>
23
+ <Text style={[styles.text, { color: isDark ? '#fff' : '#000' }]}>
20
24
  {text}
21
25
  </Text>
22
26
 
23
27
  <TouchableOpacity
24
28
  style={{
25
29
  width: '100%',
26
- backgroundColor: color,
30
+ backgroundColor: color || '#313A46',
27
31
  height: 40,
28
32
  alignItems: 'center',
29
33
  justifyContent: 'center',
@@ -0,0 +1,278 @@
1
+ import React from 'react';
2
+ import { View } from 'react-native';
3
+
4
+ /**
5
+ * Clean vector Left Chevron (<)
6
+ */
7
+ export const BackChevronIcon = ({ color = '#ffffff', size = 22, strokeWidth = 2.6 }) => (
8
+ <View style={{ width: size, height: size, justifyContent: 'center', alignItems: 'center' }}>
9
+ <View
10
+ style={{
11
+ width: size * 0.44,
12
+ height: size * 0.44,
13
+ borderLeftWidth: strokeWidth,
14
+ borderBottomWidth: strokeWidth,
15
+ borderColor: color,
16
+ transform: [{ rotate: '45deg' }],
17
+ marginLeft: size * 0.12,
18
+ }}
19
+ />
20
+ </View>
21
+ );
22
+
23
+ /**
24
+ * Clean vector Right Chevron (>)
25
+ */
26
+ export const ForwardChevronIcon = ({ color = '#ffffff', size = 22, strokeWidth = 2.6 }) => (
27
+ <View style={{ width: size, height: size, justifyContent: 'center', alignItems: 'center' }}>
28
+ <View
29
+ style={{
30
+ width: size * 0.44,
31
+ height: size * 0.44,
32
+ borderRightWidth: strokeWidth,
33
+ borderTopWidth: strokeWidth,
34
+ borderColor: color,
35
+ transform: [{ rotate: '45deg' }],
36
+ marginRight: size * 0.12,
37
+ }}
38
+ />
39
+ </View>
40
+ );
41
+
42
+ /**
43
+ * Clean vector Close Circle with (X)
44
+ */
45
+ export const CloseCircleIcon = ({ color = '#ffffff', size = 26, strokeWidth = 1.8 }) => (
46
+ <View
47
+ style={{
48
+ width: size,
49
+ height: size,
50
+ borderRadius: size / 2,
51
+ borderWidth: 1.5,
52
+ borderColor: color,
53
+ justifyContent: 'center',
54
+ alignItems: 'center',
55
+ }}
56
+ >
57
+ <View style={{ width: size * 0.44, height: size * 0.44, justifyContent: 'center', alignItems: 'center' }}>
58
+ <View
59
+ style={{
60
+ position: 'absolute',
61
+ width: size * 0.46,
62
+ height: strokeWidth,
63
+ backgroundColor: color,
64
+ borderRadius: strokeWidth / 2,
65
+ transform: [{ rotate: '45deg' }],
66
+ }}
67
+ />
68
+ <View
69
+ style={{
70
+ position: 'absolute',
71
+ width: size * 0.46,
72
+ height: strokeWidth,
73
+ backgroundColor: color,
74
+ borderRadius: strokeWidth / 2,
75
+ transform: [{ rotate: '-45deg' }],
76
+ }}
77
+ />
78
+ </View>
79
+ </View>
80
+ );
81
+
82
+ /**
83
+ * Clean vector Mail / Envelope Icon
84
+ */
85
+ export const MailIcon = ({ color = '#94a3b8', size = 18 }) => {
86
+ const w = size * 1.18;
87
+ const h = size * 0.82;
88
+ const flapW = w * 0.68;
89
+ return (
90
+ <View
91
+ style={{
92
+ width: w,
93
+ height: h,
94
+ borderRadius: 3,
95
+ borderWidth: 1.6,
96
+ borderColor: color,
97
+ justifyContent: 'center',
98
+ alignItems: 'center',
99
+ overflow: 'hidden',
100
+ position: 'relative',
101
+ }}
102
+ >
103
+ <View
104
+ style={{
105
+ position: 'absolute',
106
+ top: -flapW * 0.48,
107
+ width: flapW,
108
+ height: flapW,
109
+ borderBottomWidth: 1.5,
110
+ borderRightWidth: 1.5,
111
+ borderColor: color,
112
+ transform: [{ rotate: '45deg' }],
113
+ }}
114
+ />
115
+ </View>
116
+ );
117
+ };
118
+
119
+ /**
120
+ * Clean vector Camera Icon (Screenshot badge)
121
+ */
122
+ export const CameraIcon = ({ color = '#ffffff', size = 13 }) => {
123
+ const w = size * 1.25;
124
+ const h = size * 0.85;
125
+ return (
126
+ <View style={{ width: w, height: size * 1.05, justifyContent: 'flex-end', alignItems: 'center' }}>
127
+ {/* Top flash/shutter bump */}
128
+ <View
129
+ style={{
130
+ width: w * 0.36,
131
+ height: size * 0.22,
132
+ backgroundColor: color,
133
+ borderTopLeftRadius: 2,
134
+ borderTopRightRadius: 2,
135
+ marginBottom: -0.5,
136
+ }}
137
+ />
138
+ {/* Camera body */}
139
+ <View
140
+ style={{
141
+ width: w,
142
+ height: h,
143
+ borderRadius: 3,
144
+ borderWidth: 1.4,
145
+ borderColor: color,
146
+ justifyContent: 'center',
147
+ alignItems: 'center',
148
+ }}
149
+ >
150
+ {/* Lens circle */}
151
+ <View
152
+ style={{
153
+ width: h * 0.52,
154
+ height: h * 0.52,
155
+ borderRadius: (h * 0.52) / 2,
156
+ borderWidth: 1.3,
157
+ borderColor: color,
158
+ }}
159
+ />
160
+ </View>
161
+ </View>
162
+ );
163
+ };
164
+
165
+ /**
166
+ * Clean vector Photo Gallery Icon (Replace Image)
167
+ * Frame with sun/circle dot and mountain peaks
168
+ */
169
+ export const PhotoGalleryIcon = ({ color = '#313A46', size = 18 }) => {
170
+ const w = size * 1.15;
171
+ const h = size * 0.92;
172
+ return (
173
+ <View
174
+ style={{
175
+ width: w,
176
+ height: h,
177
+ borderRadius: 3.5,
178
+ borderWidth: 1.6,
179
+ borderColor: color,
180
+ overflow: 'hidden',
181
+ position: 'relative',
182
+ justifyContent: 'flex-end',
183
+ }}
184
+ >
185
+ {/* Sun / Moon Dot */}
186
+ <View
187
+ style={{
188
+ position: 'absolute',
189
+ top: 2.2,
190
+ left: 2.8,
191
+ width: 3.2,
192
+ height: 3.2,
193
+ borderRadius: 1.6,
194
+ backgroundColor: color,
195
+ }}
196
+ />
197
+ {/* Mountain peaks container */}
198
+ <View
199
+ style={{
200
+ flexDirection: 'row',
201
+ alignItems: 'flex-end',
202
+ width: '100%',
203
+ height: '70%',
204
+ overflow: 'hidden',
205
+ }}
206
+ >
207
+ {/* Left small peak */}
208
+ <View
209
+ style={{
210
+ width: w * 0.48,
211
+ height: w * 0.48,
212
+ backgroundColor: color,
213
+ transform: [{ rotate: '45deg' }],
214
+ marginLeft: -w * 0.08,
215
+ marginBottom: -w * 0.16,
216
+ }}
217
+ />
218
+ {/* Right taller peak */}
219
+ <View
220
+ style={{
221
+ width: w * 0.65,
222
+ height: w * 0.65,
223
+ backgroundColor: color,
224
+ transform: [{ rotate: '45deg' }],
225
+ marginLeft: -w * 0.12,
226
+ marginBottom: -w * 0.22,
227
+ }}
228
+ />
229
+ </View>
230
+ </View>
231
+ );
232
+ };
233
+
234
+ /**
235
+ * Clean vector Camcorder / Video Camera Icon (Replace Video & Video badge)
236
+ * Rounded camera body with lens cone on the right
237
+ */
238
+ export const CamcorderIcon = ({ color = '#313A46', size = 18 }) => {
239
+ const bodyW = size * 0.78;
240
+ const bodyH = size * 0.64;
241
+ const lensW = size * 0.34;
242
+ const lensH = bodyH * 0.75;
243
+ return (
244
+ <View
245
+ style={{
246
+ width: bodyW + lensW + 2,
247
+ height: bodyH,
248
+ flexDirection: 'row',
249
+ alignItems: 'center',
250
+ }}
251
+ >
252
+ {/* Camcorder body */}
253
+ <View
254
+ style={{
255
+ width: bodyW,
256
+ height: bodyH,
257
+ borderRadius: 3,
258
+ borderWidth: 1.6,
259
+ borderColor: color,
260
+ }}
261
+ />
262
+ {/* Lens triangle pointing right */}
263
+ <View
264
+ style={{
265
+ width: 0,
266
+ height: 0,
267
+ borderTopWidth: lensH * 0.42,
268
+ borderBottomWidth: lensH * 0.42,
269
+ borderLeftWidth: lensW,
270
+ borderTopColor: 'transparent',
271
+ borderBottomColor: 'transparent',
272
+ borderLeftColor: color,
273
+ marginLeft: 2,
274
+ }}
275
+ />
276
+ </View>
277
+ );
278
+ };
@@ -1,43 +1,35 @@
1
- import { KeyboardAvoidingView, Platform, TouchableWithoutFeedback, Dimensions, View, ScrollView } from 'react-native'
2
- import React from 'react'
1
+ import {
2
+ KeyboardAvoidingView,
3
+ Platform,
4
+ ScrollView,
5
+ View,
6
+ } from 'react-native';
7
+ import React from 'react';
3
8
 
4
- const KeyboardAvoidingWrapper = ({ children }) => {
5
-
9
+ const KeyboardAvoidingWrapper = ({
10
+ children,
11
+ style,
12
+ contentContainerStyle,
13
+ scrollEnabled = true,
14
+ bounces = false,
15
+ }) => {
6
16
  return (
7
- Platform.OS == 'ios' ? (
8
- <KeyboardAvoidingView
9
- style={{
10
- width: '100%',
11
- height: '100%'
12
- }}
13
- behavior={Platform.OS == 'ios' ? 'padding' : 'height'}
14
- enabled={false}
17
+ <KeyboardAvoidingView
18
+ style={[{ flex: 1 }, style]}
19
+ behavior={Platform.OS === 'ios' ? 'padding' : undefined}
20
+ >
21
+ <ScrollView
22
+ style={{ flex: 1 }}
23
+ contentContainerStyle={[{ flexGrow: 1 }, contentContainerStyle]}
24
+ keyboardShouldPersistTaps="handled"
25
+ showsVerticalScrollIndicator={false}
26
+ scrollEnabled={scrollEnabled}
27
+ bounces={bounces}
15
28
  >
16
- <TouchableWithoutFeedback >{children}
17
- </TouchableWithoutFeedback>
18
- </KeyboardAvoidingView>) : (
19
- <KeyboardAvoidingView
20
- style={{
21
- width: '100%',
22
- height: "100%",
23
- backgroundColor: "#fff"
24
- }}
25
- behavior={Platform.OS == 'ios' ? 'padding' : 'height'}
26
- keyboardVerticalOffset={Platform.OS === 'android' ? -130 : 0}
27
- >
28
- <TouchableWithoutFeedback >
29
- <View
30
- style={{
31
- height: '100%',
32
- minHeight: Dimensions.get('window').height*0.97,
33
- }}
34
- >
35
- {children}
36
- </View>
37
- </TouchableWithoutFeedback>
38
- </KeyboardAvoidingView>
39
- )
40
- )
41
- }
29
+ <View style={{ flex: 1 }}>{children}</View>
30
+ </ScrollView>
31
+ </KeyboardAvoidingView>
32
+ );
33
+ };
42
34
 
43
- export default KeyboardAvoidingWrapper;
35
+ export default KeyboardAvoidingWrapper;
@@ -1,15 +1,18 @@
1
1
  import React from 'react';
2
- import { View, ActivityIndicator, StyleSheet, Text } from 'react-native';
2
+ import { View, ActivityIndicator, StyleSheet, Text, useColorScheme } from 'react-native';
3
+ import { isShakebugDark } from './Theme';
3
4
 
4
- const LoadingModal = ({ visible, color = '#1dd3e3', text = '' }) => {
5
+ const LoadingModal = ({ visible, color = '#2E2E2E', text = '' }) => {
6
+ const colorScheme = useColorScheme();
7
+ const isDark = isShakebugDark(colorScheme);
5
8
  if (!visible) return null;
6
9
 
7
10
  return (
8
11
  <View style={styles.overlay} pointerEvents="auto">
9
12
  <View style={styles.backdrop} />
10
- <View style={styles.indicatorContainer}>
13
+ <View style={[styles.indicatorContainer, { backgroundColor: isDark ? '#2b2f38' : '#ffffff' }]}>
11
14
  <ActivityIndicator size="large" color={color} />
12
- {text ? <Text style={styles.text}>{text}</Text> : null}
15
+ {text ? <Text style={[styles.text, { color: isDark ? '#ffffff' : '#000000' }]}>{text}</Text> : null}
13
16
  </View>
14
17
  </View>
15
18
  );
@@ -12,6 +12,13 @@ export const NavigationProvider = ({ children }) => {
12
12
  setNavigationState((prevState) => [...prevState, { name: screen, params }]);
13
13
  };
14
14
 
15
+ const replace = (screen, params = {}) => {
16
+ setNavigationState((prevState) => {
17
+ const copy = prevState.length > 1 ? prevState.slice(0, -1) : [];
18
+ return [...copy, { name: screen, params }];
19
+ });
20
+ };
21
+
15
22
  const goBack = (steps = 1) => {
16
23
  setNavigationState((prevState) => prevState.slice(0, -steps));
17
24
  };
@@ -32,7 +39,7 @@ export const NavigationProvider = ({ children }) => {
32
39
  }, [navigationState]);
33
40
 
34
41
  return (
35
- <NavigationContext.Provider value={{ navigationState, navigate, goBack, focusedScreen, goToScreenAtIndex}}>
42
+ <NavigationContext.Provider value={{ navigationState, navigate, replace, goBack, focusedScreen, goToScreenAtIndex}}>
36
43
  {children}
37
44
  </NavigationContext.Provider>
38
45
  );