react-native-radar 3.7.6-beta.1 → 3.7.6-beta.4
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/android/build.gradle +1 -1
- package/ios/RNRadar.h +0 -1
- package/ios/RNRadar.m +10 -15
- package/js/index.js +4 -7
- package/package.json +5 -4
- package/js/helpers.js +0 -15
- package/js/ui/README.md +0 -67
- package/js/ui/autocomplete.jsx +0 -280
- package/js/ui/map-logo.png +0 -0
- package/js/ui/map.jsx +0 -66
- package/js/ui/marker.png +0 -0
- package/js/ui/radar-logo.png +0 -0
- package/js/ui/search.png +0 -0
package/android/build.gradle
CHANGED
package/ios/RNRadar.h
CHANGED
package/ios/RNRadar.m
CHANGED
|
@@ -139,14 +139,6 @@ RCT_EXPORT_METHOD(setAnonymousTrackingEnabled:(BOOL)enabled) {
|
|
|
139
139
|
[Radar setAnonymousTrackingEnabled:enabled];
|
|
140
140
|
}
|
|
141
141
|
|
|
142
|
-
RCT_EXPORT_METHOD(host:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) {
|
|
143
|
-
resolve([RadarSettings host]);
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
RCT_EXPORT_METHOD(publishableKey:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) {
|
|
147
|
-
resolve([RadarSettings publishableKey]);
|
|
148
|
-
}
|
|
149
|
-
|
|
150
142
|
RCT_REMAP_METHOD(getPermissionsStatus, getPermissionsStatusWithResolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) {
|
|
151
143
|
CLAuthorizationStatus status = [CLLocationManager authorizationStatus];
|
|
152
144
|
NSString *statusStr;
|
|
@@ -737,16 +729,19 @@ RCT_EXPORT_METHOD(autocomplete:(NSDictionary *)optionsDict resolve:(RCTPromiseRe
|
|
|
737
729
|
}
|
|
738
730
|
|
|
739
731
|
NSDictionary *nearDict = optionsDict[@"near"];
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
NSDate *timestamp = [NSDate new];
|
|
745
|
-
near = [[CLLocation alloc] initWithCoordinate:CLLocationCoordinate2DMake(latitude, longitude) altitude:-1 horizontalAccuracy:5 verticalAccuracy:-1 timestamp:timestamp];
|
|
746
|
-
}
|
|
732
|
+
if (nearDict == nil || ![nearDict isKindOfClass:[NSDictionary class]]) {
|
|
733
|
+
if (reject) {
|
|
734
|
+
reject([Radar stringForStatus:RadarStatusErrorBadRequest], [Radar stringForStatus:RadarStatusErrorBadRequest], nil);
|
|
735
|
+
}
|
|
747
736
|
|
|
737
|
+
return;
|
|
738
|
+
}
|
|
748
739
|
|
|
749
740
|
NSString *query = optionsDict[@"query"];
|
|
741
|
+
double latitude = [RCTConvert double:nearDict[@"latitude"]];
|
|
742
|
+
double longitude = [RCTConvert double:nearDict[@"longitude"]];
|
|
743
|
+
NSDate *timestamp = [NSDate new];
|
|
744
|
+
CLLocation *near = [[CLLocation alloc] initWithCoordinate:CLLocationCoordinate2DMake(latitude, longitude) altitude:-1 horizontalAccuracy:5 verticalAccuracy:-1 timestamp:timestamp];
|
|
750
745
|
NSNumber *limitNumber = optionsDict[@"limit"];
|
|
751
746
|
int limit;
|
|
752
747
|
if (limitNumber != nil && [limitNumber isKindOfClass:[NSNumber class]]) {
|
package/js/index.js
CHANGED
|
@@ -1,12 +1,9 @@
|
|
|
1
1
|
import { Platform } from 'react-native';
|
|
2
2
|
|
|
3
3
|
let module = {};
|
|
4
|
-
if (Platform.OS === 'web')
|
|
5
|
-
module =
|
|
6
|
-
|
|
4
|
+
if (Platform.OS === 'web')
|
|
5
|
+
module = require('./index.web').default;
|
|
6
|
+
else
|
|
7
7
|
module = require('./index.native').default;
|
|
8
|
-
}
|
|
9
|
-
export default module;
|
|
10
8
|
|
|
11
|
-
export
|
|
12
|
-
export { default as Map } from './ui/map';
|
|
9
|
+
export default module;
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"description": "React Native module for Radar, the leading geofencing and location tracking platform",
|
|
4
4
|
"homepage": "https://radar.com",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
|
-
"version": "3.7.6-beta.
|
|
6
|
+
"version": "3.7.6-beta.4",
|
|
7
7
|
"main": "js/index.js",
|
|
8
8
|
"files": [
|
|
9
9
|
"android",
|
|
@@ -13,7 +13,9 @@
|
|
|
13
13
|
"react-native-radar.podspec"
|
|
14
14
|
],
|
|
15
15
|
"scripts": {
|
|
16
|
-
"test": "jest ./test/*.test.js"
|
|
16
|
+
"test": "jest ./test/*.test.js",
|
|
17
|
+
"check-latest-tag": "node ./scripts/check-latest-tag.cjs",
|
|
18
|
+
"check-beta-tag": "node ./scripts/check-beta-tag.cjs"
|
|
17
19
|
},
|
|
18
20
|
"jest": {
|
|
19
21
|
"preset": "react-native",
|
|
@@ -25,8 +27,7 @@
|
|
|
25
27
|
},
|
|
26
28
|
"peerDependencies": {
|
|
27
29
|
"react": ">= 16.8.6",
|
|
28
|
-
"react-native": ">= 0.60.0"
|
|
29
|
-
"@maplibre/maplibre-react-native": "^9.0.1"
|
|
30
|
+
"react-native": ">= 0.60.0"
|
|
30
31
|
},
|
|
31
32
|
"devDependencies": {
|
|
32
33
|
"@babel/core": "^7.2.2",
|
package/js/helpers.js
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { NativeModules, Platform } from 'react-native';
|
|
2
|
-
|
|
3
|
-
if (!NativeModules.RNRadar && (Platform.OS === 'ios' || Platform.OS === 'android')) {
|
|
4
|
-
throw new Error('NativeModules.RNRadar is undefined');
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
const getHost = () => (
|
|
8
|
-
NativeModules.RNRadar.host()
|
|
9
|
-
);
|
|
10
|
-
|
|
11
|
-
const getPublishableKey = () => (
|
|
12
|
-
NativeModules.RNRadar.publishableKey()
|
|
13
|
-
);
|
|
14
|
-
|
|
15
|
-
export { getHost, getPublishableKey };
|
package/js/ui/README.md
DELETED
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
## Example usage
|
|
2
|
-
|
|
3
|
-
We provide UI elements for autocomplete & maps to make building easy.
|
|
4
|
-
|
|
5
|
-
If you're using the Map element, you'll need to install [Maplibre React Native](https://github.com/maplibre/maplibre-react-native).
|
|
6
|
-
```
|
|
7
|
-
npm install @maplibre/maplibre-react-native
|
|
8
|
-
```
|
|
9
|
-
|
|
10
|
-
Then make sure to complete required [platform specific installation steps](https://github.com/maplibre/maplibre-react-native/blob/main/docs/GettingStarted.md#review-platform-specific-info) as well.
|
|
11
|
-
|
|
12
|
-
### Adding a map
|
|
13
|
-
|
|
14
|
-
We've taken care of linking the map tile server to the map, so all you need to do is make sure you've initialized the Radar SDK and use `<Map>`
|
|
15
|
-
|
|
16
|
-
```
|
|
17
|
-
import {StyleSheet, View} from 'react-native';
|
|
18
|
-
import Radar, { Map } from 'react-native-radar';
|
|
19
|
-
|
|
20
|
-
export default function App() {
|
|
21
|
-
Radar.initialize('prj_place_your_own_token_here');
|
|
22
|
-
|
|
23
|
-
// A quirk of Map Libre requires us to set their deprecated access token to null
|
|
24
|
-
MapLibreGL.setAccessToken(null);
|
|
25
|
-
|
|
26
|
-
return (
|
|
27
|
-
<View style={styles.page}>
|
|
28
|
-
<Map />
|
|
29
|
-
</View>
|
|
30
|
-
);
|
|
31
|
-
}
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
TODO: fill in details on customization, including using MapLibre elements
|
|
35
|
-
|
|
36
|
-
### Adding an address autocomplete
|
|
37
|
-
|
|
38
|
-
Adding an address search autocomplete is similarly easy. Our `<Autocomplete>` element is comprised of a TextInput and Flatlist with the results.
|
|
39
|
-
|
|
40
|
-
The example below provides optional `location` and `onSelect` props to the component. Providing a location will improve autocomplete result quality. Without it, the API utilizes the IP address location to rank results.
|
|
41
|
-
|
|
42
|
-
```
|
|
43
|
-
import Radar, { Map } from 'react-native-radar';
|
|
44
|
-
|
|
45
|
-
export default function App() {
|
|
46
|
-
const [location, setLocation] = useState(null);
|
|
47
|
-
|
|
48
|
-
Radar.trackOnce().then((result) => {
|
|
49
|
-
setLocation({
|
|
50
|
-
latitude: result.location.latitude,
|
|
51
|
-
longitude: result.location.longitude,
|
|
52
|
-
});
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
const onSelect (selectedAddress) => {
|
|
56
|
-
// Do something with the selected address
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
return (
|
|
60
|
-
<View style={style.page}>
|
|
61
|
-
<Autocomplete location={location} onSelect={onSelect} />
|
|
62
|
-
</View>
|
|
63
|
-
);
|
|
64
|
-
}
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
TODO: fill in details of customization
|
package/js/ui/autocomplete.jsx
DELETED
|
@@ -1,280 +0,0 @@
|
|
|
1
|
-
// Autocomplete.js
|
|
2
|
-
import React, { useState, useCallback, useRef } from 'react';
|
|
3
|
-
import {
|
|
4
|
-
View,
|
|
5
|
-
TextInput,
|
|
6
|
-
FlatList,
|
|
7
|
-
TouchableOpacity,
|
|
8
|
-
Text,
|
|
9
|
-
StyleSheet,
|
|
10
|
-
Image,
|
|
11
|
-
} from 'react-native';
|
|
12
|
-
import Radar from '../index.native';
|
|
13
|
-
|
|
14
|
-
const defaultStyles = StyleSheet.create({
|
|
15
|
-
container: {
|
|
16
|
-
width: '100%',
|
|
17
|
-
alignItems: 'center',
|
|
18
|
-
justifyContent: 'center',
|
|
19
|
-
padding: 8,
|
|
20
|
-
},
|
|
21
|
-
inputContainer: {
|
|
22
|
-
flexDirection: 'row',
|
|
23
|
-
alignItems: 'center',
|
|
24
|
-
width: '95%',
|
|
25
|
-
backgroundColor: 'white',
|
|
26
|
-
borderRadius: 5,
|
|
27
|
-
shadowColor: "#061A2B",
|
|
28
|
-
shadowOffset: {
|
|
29
|
-
width: 0,
|
|
30
|
-
height: 4,
|
|
31
|
-
},
|
|
32
|
-
shadowOpacity: 0.1,
|
|
33
|
-
shadowRadius: 12,
|
|
34
|
-
elevation: 5,
|
|
35
|
-
},
|
|
36
|
-
inputIcon: {
|
|
37
|
-
marginLeft: 10,
|
|
38
|
-
height: 18,
|
|
39
|
-
width: 18,
|
|
40
|
-
backgroundColor: 'white',
|
|
41
|
-
color: 'white',
|
|
42
|
-
},
|
|
43
|
-
input: {
|
|
44
|
-
flex: 1,
|
|
45
|
-
backgroundColor: 'white',
|
|
46
|
-
height: 40,
|
|
47
|
-
fontSize: 14,
|
|
48
|
-
paddingTop: 2,
|
|
49
|
-
paddingHorizontal: 8,
|
|
50
|
-
borderRadius: 5,
|
|
51
|
-
shadowOpacity: 0,
|
|
52
|
-
},
|
|
53
|
-
inputFocused: {
|
|
54
|
-
shadowColor: "#81BEFF",
|
|
55
|
-
shadowOffset: {
|
|
56
|
-
width: 0,
|
|
57
|
-
height: 0,
|
|
58
|
-
},
|
|
59
|
-
shadowOpacity: 1,
|
|
60
|
-
shadowRadius: 4,
|
|
61
|
-
elevation: 4,
|
|
62
|
-
},
|
|
63
|
-
resultListWrapper: {
|
|
64
|
-
width: '95%',
|
|
65
|
-
marginTop: 8,
|
|
66
|
-
backgroundColor: 'white',
|
|
67
|
-
borderRadius: 5,
|
|
68
|
-
paddingVertical: 8,
|
|
69
|
-
paddingHorizontal: 8,
|
|
70
|
-
shadowColor: "#061A2B",
|
|
71
|
-
shadowOffset: {
|
|
72
|
-
width: 0,
|
|
73
|
-
height: 4,
|
|
74
|
-
},
|
|
75
|
-
shadowOpacity: 0.1,
|
|
76
|
-
shadowRadius: 12,
|
|
77
|
-
elevation: 5,
|
|
78
|
-
},
|
|
79
|
-
resultList: {
|
|
80
|
-
width: '100%',
|
|
81
|
-
},
|
|
82
|
-
resultItem: {
|
|
83
|
-
paddingRight: 16,
|
|
84
|
-
paddingVertical: 8,
|
|
85
|
-
height: 56,
|
|
86
|
-
fontSize: 12,
|
|
87
|
-
},
|
|
88
|
-
addressContainer: {
|
|
89
|
-
flexDirection: 'row',
|
|
90
|
-
alignItems: 'center',
|
|
91
|
-
},
|
|
92
|
-
pinIconContainer: {
|
|
93
|
-
width: 28,
|
|
94
|
-
},
|
|
95
|
-
pinIcon: {
|
|
96
|
-
height: 20,
|
|
97
|
-
width: 20,
|
|
98
|
-
marginRight: 8,
|
|
99
|
-
marginBottom: 14,
|
|
100
|
-
},
|
|
101
|
-
addressTextContainer: {
|
|
102
|
-
flex: 1,
|
|
103
|
-
},
|
|
104
|
-
addressText: {
|
|
105
|
-
fontSize: 14,
|
|
106
|
-
color: '#000',
|
|
107
|
-
fontWeight: '600',
|
|
108
|
-
},
|
|
109
|
-
addressSubtext: {
|
|
110
|
-
fontSize: 12,
|
|
111
|
-
color: '#5A6872',
|
|
112
|
-
},
|
|
113
|
-
footerContainer: {
|
|
114
|
-
flexDirection: 'row',
|
|
115
|
-
alignItems: 'center',
|
|
116
|
-
padding: 10,
|
|
117
|
-
alignSelf: 'flex-end',
|
|
118
|
-
},
|
|
119
|
-
footerText: {
|
|
120
|
-
marginTop: 2,
|
|
121
|
-
marginRight: 4,
|
|
122
|
-
fontSize: 10,
|
|
123
|
-
color: '#5A6872',
|
|
124
|
-
},
|
|
125
|
-
logo: {
|
|
126
|
-
width: 50,
|
|
127
|
-
height: 15,
|
|
128
|
-
resizeMode: 'contain',
|
|
129
|
-
},
|
|
130
|
-
});
|
|
131
|
-
|
|
132
|
-
const defaultAutocompleteOptions = {
|
|
133
|
-
debounceMS: 200,
|
|
134
|
-
threshold: 3,
|
|
135
|
-
limit: 8,
|
|
136
|
-
placeholder: 'Search address',
|
|
137
|
-
showPin: true,
|
|
138
|
-
};
|
|
139
|
-
|
|
140
|
-
const autocompleteUI = ({ options = {}, onSelect, location, style = {} }) => {
|
|
141
|
-
const [query, setQuery] = useState('');
|
|
142
|
-
const [results, setResults] = useState([]);
|
|
143
|
-
const [isOpen, setIsOpen] = useState(false);
|
|
144
|
-
const [isInputFocused, setInputFocused] = useState(false);
|
|
145
|
-
const timerRef = useRef(null);
|
|
146
|
-
|
|
147
|
-
const config = { ...defaultAutocompleteOptions, ...options };
|
|
148
|
-
|
|
149
|
-
const fetchResults = useCallback(async (searchQuery) => {
|
|
150
|
-
if (searchQuery.length < config.threshold) return;
|
|
151
|
-
|
|
152
|
-
const params = { query: searchQuery, limit: config.limit };
|
|
153
|
-
|
|
154
|
-
if (location && location.latitude && location.longitude) {
|
|
155
|
-
params.near = location;
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
try {
|
|
159
|
-
const result = await Radar.autocomplete(params);
|
|
160
|
-
setResults(result.addresses);
|
|
161
|
-
setIsOpen(true);
|
|
162
|
-
} catch (error) {
|
|
163
|
-
if (config.onError && typeof config.onError === 'function') {
|
|
164
|
-
config.onError(error);
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
}, [config]);
|
|
168
|
-
|
|
169
|
-
const handleInput = useCallback(
|
|
170
|
-
(text) => {
|
|
171
|
-
setQuery(text);
|
|
172
|
-
|
|
173
|
-
// Clear the existing timer
|
|
174
|
-
if (timerRef.current) {
|
|
175
|
-
clearTimeout(timerRef.current);
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
if (text.length < config.threshold) {
|
|
179
|
-
return;
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
// Set the new timer
|
|
183
|
-
timerRef.current = setTimeout(() => {
|
|
184
|
-
fetchResults(text);
|
|
185
|
-
}, config.debounceMS);
|
|
186
|
-
},
|
|
187
|
-
[config, fetchResults],
|
|
188
|
-
);
|
|
189
|
-
|
|
190
|
-
const handleSelect = (item) => {
|
|
191
|
-
setQuery(item.formattedAddress);
|
|
192
|
-
setIsOpen(false);
|
|
193
|
-
|
|
194
|
-
if (typeof onSelect === 'function') {
|
|
195
|
-
onSelect(item);
|
|
196
|
-
}
|
|
197
|
-
};
|
|
198
|
-
|
|
199
|
-
const renderFooter = () => {
|
|
200
|
-
if (results.length === 0) return null;
|
|
201
|
-
|
|
202
|
-
return (
|
|
203
|
-
<View style={styles.footerContainer}>
|
|
204
|
-
<View style={{ flexDirection: 'row', alignItems: 'center' }}>
|
|
205
|
-
<Text style={styles.footerText}>Powered by</Text>
|
|
206
|
-
<Image source={require('./radar-logo.png')} resizeMode="contain" style={defaultStyles.logo} />
|
|
207
|
-
</View>
|
|
208
|
-
</View>
|
|
209
|
-
);
|
|
210
|
-
};
|
|
211
|
-
|
|
212
|
-
const renderItem = ({ item }) => (
|
|
213
|
-
<TouchableOpacity style={styles.resultItem} onPress={() => handleSelect(item)}>
|
|
214
|
-
<View style={styles.addressContainer}>
|
|
215
|
-
<View style={styles.pinIconContainer}>
|
|
216
|
-
{config.showPin ? (
|
|
217
|
-
<Image source={require('./marker.png')} style={styles.pinIcon} />
|
|
218
|
-
) : null}
|
|
219
|
-
</View>
|
|
220
|
-
<View style={styles.addressTextContainer}>
|
|
221
|
-
<Text numberOfLines={1} style={styles.addressText}>
|
|
222
|
-
{item.addressLabel || item?.placeLabel}
|
|
223
|
-
</Text>
|
|
224
|
-
<Text numberOfLines={1} style={styles.addressSubtext}>
|
|
225
|
-
{item?.formattedAddress?.replace(`${item?.addressLabel || item?.placeLabel}, `, '')}
|
|
226
|
-
</Text>
|
|
227
|
-
</View>
|
|
228
|
-
</View>
|
|
229
|
-
</TouchableOpacity>
|
|
230
|
-
);
|
|
231
|
-
|
|
232
|
-
const styles = {
|
|
233
|
-
...defaultStyles,
|
|
234
|
-
container: StyleSheet.compose(defaultStyles.container, style.container),
|
|
235
|
-
input: StyleSheet.compose(defaultStyles.input, style.input),
|
|
236
|
-
resultList: StyleSheet.compose(defaultStyles.resultList, style.resultList),
|
|
237
|
-
resultItem: StyleSheet.compose(defaultStyles.resultItem, style.resultItem),
|
|
238
|
-
addressContainer: StyleSheet.compose(defaultStyles.addressContainer, style.addressContainer),
|
|
239
|
-
pinIconContainer: StyleSheet.compose(defaultStyles.pinIconContainer, style.pinIconContainer),
|
|
240
|
-
pinIcon: StyleSheet.compose(defaultStyles.pinIcon, style.pinIcon),
|
|
241
|
-
addressTextContainer: StyleSheet.compose(defaultStyles.addressTextContainer, style.addressTextContainer),
|
|
242
|
-
addressText: StyleSheet.compose(defaultStyles.addressText, style.addressText),
|
|
243
|
-
addressSubtext: StyleSheet.compose(defaultStyles.addressSubtext, style.addressSubtext),
|
|
244
|
-
footerContainer: StyleSheet.compose(defaultStyles.footerContainer, style.footerContainer),
|
|
245
|
-
footerText: StyleSheet.compose(defaultStyles.footerText, style.footerText),
|
|
246
|
-
};
|
|
247
|
-
|
|
248
|
-
const inputStyle = isInputFocused
|
|
249
|
-
? StyleSheet.compose(styles.inputContainer, defaultStyles.inputFocused)
|
|
250
|
-
: styles.inputContainer;
|
|
251
|
-
|
|
252
|
-
return (
|
|
253
|
-
<View style={styles.container}>
|
|
254
|
-
<View style={inputStyle}>
|
|
255
|
-
<Image source={require('./search.png')} style={styles.inputIcon} />
|
|
256
|
-
<TextInput
|
|
257
|
-
style={styles.input}
|
|
258
|
-
onChangeText={handleInput}
|
|
259
|
-
onFocus={() => setInputFocused(true)}
|
|
260
|
-
onBlur={() => setInputFocused(false)}
|
|
261
|
-
value={query}
|
|
262
|
-
placeholder={config.placeholder}
|
|
263
|
-
/>
|
|
264
|
-
</View>
|
|
265
|
-
{isOpen && (
|
|
266
|
-
<View style={defaultStyles.resultListWrapper}>
|
|
267
|
-
<FlatList
|
|
268
|
-
style={styles.resultList}
|
|
269
|
-
data={results}
|
|
270
|
-
renderItem={renderItem}
|
|
271
|
-
keyExtractor={(item) => item.formattedAddress + item.postalCode}
|
|
272
|
-
ListFooterComponent={renderFooter}
|
|
273
|
-
/>
|
|
274
|
-
</View>
|
|
275
|
-
)}
|
|
276
|
-
</View>
|
|
277
|
-
);
|
|
278
|
-
};
|
|
279
|
-
|
|
280
|
-
export default autocompleteUI;
|
package/js/ui/map-logo.png
DELETED
|
Binary file
|
package/js/ui/map.jsx
DELETED
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
import React, { useState, useEffect } from 'react';
|
|
2
|
-
import { StyleSheet, View, Image } from 'react-native';
|
|
3
|
-
import MapLibreGL from '@maplibre/maplibre-react-native';
|
|
4
|
-
import { getHost, getPublishableKey } from '../helpers';
|
|
5
|
-
|
|
6
|
-
const DEFAULT_STYLE = 'radar-default-v1';
|
|
7
|
-
|
|
8
|
-
const styles = StyleSheet.create({
|
|
9
|
-
container: {
|
|
10
|
-
flex: 1,
|
|
11
|
-
},
|
|
12
|
-
map: {
|
|
13
|
-
flex: 1,
|
|
14
|
-
},
|
|
15
|
-
logo: {
|
|
16
|
-
position: 'absolute',
|
|
17
|
-
bottom: -10,
|
|
18
|
-
left: 5,
|
|
19
|
-
width: 50,
|
|
20
|
-
height: 50,
|
|
21
|
-
resizeMode: 'contain',
|
|
22
|
-
},
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
const createStyleURL = async (style = DEFAULT_STYLE) => {
|
|
26
|
-
const host = await getHost();
|
|
27
|
-
const publishableKey = await getPublishableKey();
|
|
28
|
-
return `${host}/maps/styles/${style}?publishableKey=${publishableKey}`;
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
const RadarMap = ({ mapOptions, children }) => {
|
|
32
|
-
const [styleURL, setStyleURL] = useState(null);
|
|
33
|
-
|
|
34
|
-
useEffect(() => {
|
|
35
|
-
createStyleURL(mapOptions?.mapStyle || DEFAULT_STYLE).then((result) => {
|
|
36
|
-
setStyleURL(result);
|
|
37
|
-
});
|
|
38
|
-
}, [mapOptions]);
|
|
39
|
-
|
|
40
|
-
if (!styleURL) {
|
|
41
|
-
return null;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
return (
|
|
45
|
-
<View style={styles.container}>
|
|
46
|
-
<MapLibreGL.MapView
|
|
47
|
-
style={styles.map}
|
|
48
|
-
pitchEnabled={false}
|
|
49
|
-
compassEnabled={false}
|
|
50
|
-
logoEnabled={false}
|
|
51
|
-
attributionEnabled
|
|
52
|
-
onRegionDidChange={mapOptions.onRegionDidChange ? mapOptions.onRegionDidChange : null}
|
|
53
|
-
styleURL={styleURL}
|
|
54
|
-
>
|
|
55
|
-
<MapLibreGL.UserLocation />
|
|
56
|
-
{children}
|
|
57
|
-
</MapLibreGL.MapView>
|
|
58
|
-
<Image
|
|
59
|
-
source={require('./map-logo.png')}
|
|
60
|
-
style={styles.logo}
|
|
61
|
-
/>
|
|
62
|
-
</View>
|
|
63
|
-
);
|
|
64
|
-
};
|
|
65
|
-
|
|
66
|
-
export default RadarMap;
|
package/js/ui/marker.png
DELETED
|
Binary file
|
package/js/ui/radar-logo.png
DELETED
|
Binary file
|
package/js/ui/search.png
DELETED
|
Binary file
|