shakebug-react-native 2.4.15 → 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.
- package/README.md +6 -0
- package/android/src/main/java/com/shakebug/ConnectivityReceiver.java +12 -7
- package/android/src/main/java/com/shakebug/DrawingView.java +13 -3
- package/android/src/main/java/com/shakebug/RecordScreenModule.java +6 -3
- package/android/src/main/java/com/shakebug/ViewShot.java +1 -0
- package/ios/CustomScreenShot/ShakebugSDKCustomScreenCapture.m +6 -2
- package/ios/ScreenShot/ShakebugCapture.m +3 -1
- package/ios/SketchCanvas/DrawingView.m +14 -1
- package/package.json +1 -1
- package/shakebug-react-native-2.4.15.tgz +0 -0
- package/src/APIs/MatchKey.js +1 -1
- package/src/Assets/images/shake.png +0 -0
- package/src/Assets/images/undo.png +0 -0
- package/src/Assets/images/undo@2x.png +0 -0
- package/src/Assets/images/undo@3x.png +0 -0
- package/src/Componanats/CustomAlert.js +8 -4
- package/src/Componanats/Icons.js +278 -0
- package/src/Componanats/KeyboardAvoidingWrapper.js +31 -39
- package/src/Componanats/LoadingModal.js +7 -4
- package/src/Componanats/NavigationContext.js +8 -1
- package/src/Componanats/ReviewModal.js +18 -11
- package/src/Componanats/SafeAreaHelper.js +70 -0
- package/src/Componanats/ShakeFunction.js +655 -364
- package/src/Componanats/ShakebugBottomSheet.js +729 -0
- package/src/Componanats/Theme.js +96 -0
- package/src/Componanats/ZoomableImage.js +350 -0
- package/src/Componanats/localization.js +32 -3
- package/src/Screens/AddDetailsScreen.js +800 -439
- package/src/Screens/FirstScreen.js +950 -540
- package/src/Screens/Shakebug.js +78 -44
- package/src/Screens/TrimVideoScreen.js +40 -7
- package/src/index.tsx +16 -7
- package/shakebug-react-native-2.4.14.tgz +0 -0
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 =
|
|
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
|
-
|
|
129
|
-
sendConnectivityChangedEvent();
|
|
130
|
-
}
|
|
128
|
+
sendConnectivityChangedEvent();
|
|
131
129
|
}
|
|
132
130
|
}
|
|
133
131
|
|
|
134
132
|
protected void sendConnectivityChangedEvent() {
|
|
135
|
-
getReactContext()
|
|
136
|
-
|
|
137
|
-
|
|
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
|
-
|
|
57
|
-
|
|
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
|
|
|
@@ -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,
|
|
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,
|
|
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
|
-
|
|
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.
|
|
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
|
package/src/APIs/MatchKey.js
CHANGED
|
@@ -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",
|
|
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 {
|
|
2
|
-
|
|
1
|
+
import {
|
|
2
|
+
KeyboardAvoidingView,
|
|
3
|
+
Platform,
|
|
4
|
+
ScrollView,
|
|
5
|
+
View,
|
|
6
|
+
} from 'react-native';
|
|
7
|
+
import React from 'react';
|
|
3
8
|
|
|
4
|
-
const KeyboardAvoidingWrapper = ({
|
|
5
|
-
|
|
9
|
+
const KeyboardAvoidingWrapper = ({
|
|
10
|
+
children,
|
|
11
|
+
style,
|
|
12
|
+
contentContainerStyle,
|
|
13
|
+
scrollEnabled = true,
|
|
14
|
+
bounces = false,
|
|
15
|
+
}) => {
|
|
6
16
|
return (
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
}}
|
|
13
|
-
|
|
14
|
-
|
|
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
|
-
<
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
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 = '#
|
|
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
|
);
|