@rnmapbox/maps 10.1.0-rc.3 → 10.1.0-rc.5
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 +1 -30
- package/android/src/main/java/com/rnmapbox/rnmbx/RNMBXPackage.kt +11 -0
- package/android/src/main/java/com/rnmapbox/rnmbx/components/annotation/RNMBXPointAnnotation.kt +33 -35
- package/android/src/main/java/com/rnmapbox/rnmbx/components/mapview/RNMBXMapView.kt +173 -106
- package/android/src/main/java/com/rnmapbox/rnmbx/components/mapview/RNMBXMapViewManager.kt +7 -0
- package/android/src/main/java/com/rnmapbox/rnmbx/modules/RNMBXOfflineModuleLegacy.kt +444 -0
- package/android/src/main/java/com/rnmapbox/rnmbx/utils/GeoJSONUtils.kt +5 -0
- package/android/src/main/mapbox-v11-compat/v10/com/rnmapbox/rnmbx/v11compat/Annotation.kt +4 -0
- package/android/src/main/mapbox-v11-compat/v11/com/rnmapbox/rnmbx/v11compat/Annotation.kt +0 -1
- package/android/src/main/old-arch/com/facebook/react/viewmanagers/RNMBXMapViewManagerDelegate.java +3 -0
- package/android/src/main/old-arch/com/facebook/react/viewmanagers/RNMBXMapViewManagerInterface.java +1 -0
- package/ios/RNMBX/RNMBXEvent.swift +2 -0
- package/ios/RNMBX/RNMBXMapView.swift +66 -39
- package/ios/RNMBX/RNMBXMapViewComponentView.mm +26 -20
- package/ios/RNMBX/RNMBXMapViewManager.m +1 -0
- package/ios/RNMBX/RNMBXMarkerViewContentComponentView.mm +15 -1
- package/ios/RNMBX/RNMBXOfflineModule.m +1 -1
- package/ios/RNMBX/RNMBXOfflineModuleLegacy.m +33 -0
- package/ios/RNMBX/RNMBXOfflineModuleLegacy.swift +431 -0
- package/ios/RNMBX/RNMBXPointAnnotation.swift +33 -0
- package/lib/commonjs/Mapbox.js +8 -0
- package/lib/commonjs/Mapbox.js.map +1 -1
- package/lib/commonjs/components/MapView.js.map +1 -1
- package/lib/commonjs/modules/offline/OfflinePackLegacy.js +40 -0
- package/lib/commonjs/modules/offline/OfflinePackLegacy.js.map +1 -0
- package/lib/commonjs/modules/offline/offlineManager.js +4 -4
- package/lib/commonjs/modules/offline/offlineManager.js.map +1 -1
- package/lib/commonjs/modules/offline/offlineManagerLegacy.js +166 -0
- package/lib/commonjs/modules/offline/offlineManagerLegacy.js.map +1 -0
- package/lib/commonjs/specs/RNMBXMapViewNativeComponent.js.map +1 -1
- package/lib/module/Mapbox.js +1 -0
- package/lib/module/Mapbox.js.map +1 -1
- package/lib/module/components/MapView.js.map +1 -1
- package/lib/module/modules/offline/OfflinePackLegacy.js +34 -0
- package/lib/module/modules/offline/OfflinePackLegacy.js.map +1 -0
- package/lib/module/modules/offline/offlineManager.js +4 -4
- package/lib/module/modules/offline/offlineManager.js.map +1 -1
- package/lib/module/modules/offline/offlineManagerLegacy.js +154 -0
- package/lib/module/modules/offline/offlineManagerLegacy.js.map +1 -0
- package/lib/module/specs/RNMBXMapViewNativeComponent.js.map +1 -1
- package/lib/typescript/src/Mapbox.d.ts +1 -0
- package/lib/typescript/src/Mapbox.d.ts.map +1 -1
- package/lib/typescript/src/components/Images.d.ts +1 -1
- package/lib/typescript/src/components/MapView.d.ts +6 -1
- package/lib/typescript/src/components/MapView.d.ts.map +1 -1
- package/lib/typescript/src/modules/offline/OfflinePackLegacy.d.ts +24 -0
- package/lib/typescript/src/modules/offline/OfflinePackLegacy.d.ts.map +1 -0
- package/lib/typescript/src/modules/offline/offlineManager.d.ts +1 -1
- package/lib/typescript/src/modules/offline/offlineManager.d.ts.map +1 -1
- package/lib/typescript/src/modules/offline/offlineManagerLegacy.d.ts +93 -0
- package/lib/typescript/src/modules/offline/offlineManagerLegacy.d.ts.map +1 -0
- package/lib/typescript/src/specs/RNMBXMapViewNativeComponent.d.ts +1 -0
- package/lib/typescript/src/specs/RNMBXMapViewNativeComponent.d.ts.map +1 -1
- package/package.json +3 -2
- package/setup-jest.js +15 -0
- package/src/Mapbox.ts +1 -0
- package/src/components/Images.tsx +1 -1
- package/src/components/MapView.tsx +7 -1
- package/src/modules/offline/OfflinePackLegacy.ts +55 -0
- package/src/modules/offline/offlineManager.ts +4 -4
- package/src/modules/offline/offlineManagerLegacy.ts +181 -0
- package/src/specs/RNMBXMapViewNativeComponent.ts +2 -0
|
@@ -0,0 +1,444 @@
|
|
|
1
|
+
package com.rnmapbox.rnmbx.modules
|
|
2
|
+
|
|
3
|
+
import android.os.Build
|
|
4
|
+
import android.util.Log
|
|
5
|
+
import com.facebook.react.bridge.Arguments
|
|
6
|
+
import com.facebook.react.bridge.Promise
|
|
7
|
+
import com.facebook.react.bridge.ReactApplicationContext
|
|
8
|
+
import com.facebook.react.bridge.ReactContextBaseJavaModule
|
|
9
|
+
import com.facebook.react.bridge.ReactMethod
|
|
10
|
+
import com.facebook.react.bridge.ReadableMap
|
|
11
|
+
import com.facebook.react.bridge.UiThreadUtil
|
|
12
|
+
import com.facebook.react.bridge.WritableMap
|
|
13
|
+
import com.facebook.react.module.annotations.ReactModule
|
|
14
|
+
import com.mapbox.bindgen.Expected
|
|
15
|
+
import com.mapbox.geojson.FeatureCollection
|
|
16
|
+
import com.mapbox.geojson.Point
|
|
17
|
+
import com.mapbox.maps.CoordinateBounds
|
|
18
|
+
import com.mapbox.maps.GlyphsRasterizationMode
|
|
19
|
+
import com.mapbox.maps.OfflineRegion
|
|
20
|
+
import com.mapbox.maps.OfflineRegionCallback
|
|
21
|
+
import com.mapbox.maps.OfflineRegionCreateCallback
|
|
22
|
+
import com.mapbox.maps.OfflineRegionDownloadState
|
|
23
|
+
import com.mapbox.maps.OfflineRegionManager
|
|
24
|
+
import com.mapbox.maps.OfflineRegionStatus
|
|
25
|
+
import com.mapbox.maps.OfflineRegionTilePyramidDefinition
|
|
26
|
+
import com.rnmapbox.rnmbx.utils.ConvertUtils
|
|
27
|
+
import com.rnmapbox.rnmbx.utils.extensions.toGeometryCollection
|
|
28
|
+
import com.rnmapbox.rnmbx.utils.writableArrayOf
|
|
29
|
+
import com.rnmapbox.rnmbx.v11compat.offlinemanager.getOfflineRegionManager
|
|
30
|
+
import org.json.JSONException
|
|
31
|
+
import org.json.JSONObject
|
|
32
|
+
import java.io.File
|
|
33
|
+
import java.io.UnsupportedEncodingException
|
|
34
|
+
import java.nio.file.Files
|
|
35
|
+
import java.nio.file.Paths
|
|
36
|
+
import java.nio.file.StandardCopyOption
|
|
37
|
+
import kotlin.math.ceil
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
@ReactModule(name = RNMBXOfflineModuleLegacy.REACT_CLASS)
|
|
41
|
+
class RNMBXOfflineModuleLegacy(private val mReactContext: ReactApplicationContext) :
|
|
42
|
+
ReactContextBaseJavaModule(
|
|
43
|
+
mReactContext
|
|
44
|
+
) {
|
|
45
|
+
companion object {
|
|
46
|
+
const val REACT_CLASS = "RNMBXOfflineModuleLegacy"
|
|
47
|
+
const val LOG_TAG = "OfflineModuleLegacy"
|
|
48
|
+
const val DEFAULT_STYLE_URL = "mapbox://styles/mapbox/streets-v11"
|
|
49
|
+
const val DEFAULT_MIN_ZOOM_LEVEL = 10.0
|
|
50
|
+
const val DEFAULT_MAX_ZOOM_LEVEL = 20.0
|
|
51
|
+
const val COMPLETE_REGION_DOWNLOAD_STATE = 2
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
override fun getName(): String {
|
|
55
|
+
return REACT_CLASS
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
val offlineRegionManager: OfflineRegionManager by lazy {
|
|
59
|
+
getOfflineRegionManager {
|
|
60
|
+
RNMBXModule.getAccessToken(mReactContext)
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
private fun makeDefinition(
|
|
65
|
+
bounds: CoordinateBounds,
|
|
66
|
+
options: ReadableMap
|
|
67
|
+
): OfflineRegionTilePyramidDefinition {
|
|
68
|
+
return OfflineRegionTilePyramidDefinition.Builder()
|
|
69
|
+
.styleURL(ConvertUtils.getString("styleURL", options, DEFAULT_STYLE_URL))
|
|
70
|
+
.bounds(bounds)
|
|
71
|
+
.minZoom(ConvertUtils.getDouble("minZoom", options, DEFAULT_MIN_ZOOM_LEVEL))
|
|
72
|
+
.maxZoom(ConvertUtils.getDouble("maxZoom", options, DEFAULT_MAX_ZOOM_LEVEL))
|
|
73
|
+
.pixelRatio(mReactContext.getResources().getDisplayMetrics().density)
|
|
74
|
+
.glyphsRasterizationMode(GlyphsRasterizationMode.IDEOGRAPHS_RASTERIZED_LOCALLY)
|
|
75
|
+
.build()
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
private fun convertPointPairToBounds(boundsFC: FeatureCollection): CoordinateBounds? {
|
|
79
|
+
val geometryCollection = boundsFC.toGeometryCollection()
|
|
80
|
+
val geometries = geometryCollection.geometries()
|
|
81
|
+
if (geometries.size != 2) {
|
|
82
|
+
return null
|
|
83
|
+
}
|
|
84
|
+
val pt0 = geometries.get(0) as Point?
|
|
85
|
+
val pt1 = geometries.get(1) as Point?
|
|
86
|
+
if (pt0 == null || pt1 == null) {
|
|
87
|
+
return null
|
|
88
|
+
}
|
|
89
|
+
return CoordinateBounds(pt0, pt1)
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
private fun createPackCallback(promise: Promise, metadata: ByteArray): OfflineRegionCreateCallback {
|
|
93
|
+
return OfflineRegionCreateCallback { expected ->
|
|
94
|
+
if (expected.isValue) {
|
|
95
|
+
expected.value?.let {
|
|
96
|
+
it.setOfflineRegionDownloadState(OfflineRegionDownloadState.ACTIVE)
|
|
97
|
+
it.setMetadata(metadata) { expectedMetadata ->
|
|
98
|
+
if (expectedMetadata.isError) {
|
|
99
|
+
promise.reject("createPack error:", "Failed to setMetadata")
|
|
100
|
+
} else {
|
|
101
|
+
Log.d(LOG_TAG, "createPack done:")
|
|
102
|
+
promise.resolve(fromOfflineRegion(it))
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
} else {
|
|
107
|
+
Log.d(LOG_TAG, "createPack error:")
|
|
108
|
+
promise.reject("createPack error:", "Failed to create OfflineRegion")
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
private fun fromOfflineRegion(region: OfflineRegion): WritableMap? {
|
|
115
|
+
val bb = region.tilePyramidDefinition?.bounds
|
|
116
|
+
val map = Arguments.createMap()
|
|
117
|
+
|
|
118
|
+
if (bb === null) return map
|
|
119
|
+
|
|
120
|
+
val jsonBounds = writableArrayOf(
|
|
121
|
+
writableArrayOf(bb.east(), bb.north()),
|
|
122
|
+
writableArrayOf(bb.west(), bb.south())
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
map.putArray("bounds", jsonBounds)
|
|
126
|
+
map.putString("metadata", String(region.metadata))
|
|
127
|
+
|
|
128
|
+
return map
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
private fun getMetadataBytes(metadata: String?): ByteArray? {
|
|
132
|
+
var metadataBytes: ByteArray? = null
|
|
133
|
+
if (metadata == null || metadata.isEmpty()) {
|
|
134
|
+
return metadataBytes
|
|
135
|
+
}
|
|
136
|
+
try {
|
|
137
|
+
metadataBytes = metadata.toByteArray(charset("utf-8"))
|
|
138
|
+
} catch (e: UnsupportedEncodingException) {
|
|
139
|
+
Log.w(LOG_TAG, e.localizedMessage)
|
|
140
|
+
}
|
|
141
|
+
return metadataBytes
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
private fun getRegionByName(
|
|
145
|
+
name: String?,
|
|
146
|
+
offlineRegions: List<OfflineRegion>
|
|
147
|
+
): OfflineRegion? {
|
|
148
|
+
if (name.isNullOrEmpty()) {
|
|
149
|
+
return null
|
|
150
|
+
}
|
|
151
|
+
for (region in offlineRegions) {
|
|
152
|
+
try {
|
|
153
|
+
val byteMetadata = region.metadata
|
|
154
|
+
|
|
155
|
+
if (byteMetadata != null) {
|
|
156
|
+
val metadata = JSONObject(String(byteMetadata))
|
|
157
|
+
if (name == metadata.getString("name")) {
|
|
158
|
+
return region
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
} catch (e: JSONException) {
|
|
162
|
+
Log.w(LOG_TAG, e.localizedMessage)
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
return null
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
private fun makeRegionStatus(regionName: String, status: OfflineRegionStatus): WritableMap? {
|
|
169
|
+
val map = Arguments.createMap()
|
|
170
|
+
val progressPercentage = if (status.requiredResourceCount > 0) status.completedResourceCount.toDouble() / status.requiredResourceCount.toDouble() else 0.0
|
|
171
|
+
val percentage = ceil(progressPercentage * 100.0).coerceAtMost(100.0)
|
|
172
|
+
val isCompleted = percentage == 100.0
|
|
173
|
+
val downloadState = if (isCompleted) COMPLETE_REGION_DOWNLOAD_STATE else status.downloadState.ordinal
|
|
174
|
+
|
|
175
|
+
map.putString("name", regionName)
|
|
176
|
+
map.putInt("state", downloadState)
|
|
177
|
+
map.putDouble("percentage", percentage)
|
|
178
|
+
map.putInt("completedResourceCount", status.completedResourceCount.toInt())
|
|
179
|
+
map.putInt("completedResourceSize", status.completedResourceSize.toInt())
|
|
180
|
+
map.putInt("completedTileSize", status.completedTileSize.toInt())
|
|
181
|
+
map.putInt("completedTileCount", status.completedTileCount.toInt())
|
|
182
|
+
map.putInt("requiredResourceCount", status.requiredResourceCount.toInt())
|
|
183
|
+
return map
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
@ReactMethod
|
|
187
|
+
@Throws(JSONException::class)
|
|
188
|
+
fun createPack(options: ReadableMap, promise: Promise) {
|
|
189
|
+
try {
|
|
190
|
+
val metadataBytes: ByteArray? =
|
|
191
|
+
getMetadataBytes(ConvertUtils.getString("metadata", options, ""))
|
|
192
|
+
|
|
193
|
+
val boundsStr = options.getString("bounds")!!
|
|
194
|
+
val boundsFC = FeatureCollection.fromJson(boundsStr)
|
|
195
|
+
val bounds = convertPointPairToBounds(boundsFC)
|
|
196
|
+
|
|
197
|
+
if (metadataBytes == null || bounds == null) {
|
|
198
|
+
promise.reject("createPack error:", "No metadata or bounds set")
|
|
199
|
+
return
|
|
200
|
+
};
|
|
201
|
+
|
|
202
|
+
val definition: OfflineRegionTilePyramidDefinition = makeDefinition(bounds, options)
|
|
203
|
+
|
|
204
|
+
UiThreadUtil.runOnUiThread {
|
|
205
|
+
offlineRegionManager.createOfflineRegion(definition, createPackCallback(promise, metadataBytes))
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
} catch (e: Throwable) {
|
|
209
|
+
promise.reject("createPack error:", e)
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
@ReactMethod
|
|
214
|
+
fun getPacks(promise: Promise) {
|
|
215
|
+
UiThreadUtil.runOnUiThread {
|
|
216
|
+
offlineRegionManager.getOfflineRegions(object: OfflineRegionCallback {
|
|
217
|
+
override fun run(expected: Expected<String, MutableList<OfflineRegion>>) {
|
|
218
|
+
if (expected.isValue) {
|
|
219
|
+
expected.value?.let {
|
|
220
|
+
val payload = Arguments.createArray()
|
|
221
|
+
|
|
222
|
+
for (region in it) {
|
|
223
|
+
payload.pushMap(fromOfflineRegion(region!!))
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
Log.d(LOG_TAG, "getPacks done:" + it.size.toString())
|
|
227
|
+
promise.resolve(payload)
|
|
228
|
+
}
|
|
229
|
+
} else {
|
|
230
|
+
promise.reject("getPacks error:", expected.error)
|
|
231
|
+
Log.d(LOG_TAG, "getPacks error:${expected.error}")
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
})
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
@ReactMethod
|
|
239
|
+
fun deletePack(name: String?, promise: Promise) {
|
|
240
|
+
UiThreadUtil.runOnUiThread {
|
|
241
|
+
offlineRegionManager.getOfflineRegions { regionsExpected ->
|
|
242
|
+
if (regionsExpected.isValue) {
|
|
243
|
+
regionsExpected.value?.let { regions ->
|
|
244
|
+
var region = getRegionByName(name, regions);
|
|
245
|
+
|
|
246
|
+
if (region == null) {
|
|
247
|
+
promise.resolve(null);
|
|
248
|
+
Log.w(LOG_TAG, "deleteRegion - Unknown offline region");
|
|
249
|
+
return@getOfflineRegions
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
region.setOfflineRegionDownloadState(OfflineRegionDownloadState.INACTIVE)
|
|
253
|
+
|
|
254
|
+
region.purge { purgeExpected ->
|
|
255
|
+
if (purgeExpected.isError) {
|
|
256
|
+
promise.reject("deleteRegion error:", purgeExpected.error);
|
|
257
|
+
} else {
|
|
258
|
+
promise.resolve(null);
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
} else {
|
|
263
|
+
promise.reject("deleteRegion error:", regionsExpected.error);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
@ReactMethod
|
|
270
|
+
fun invalidatePack(name: String?, promise: Promise) {
|
|
271
|
+
UiThreadUtil.runOnUiThread {
|
|
272
|
+
offlineRegionManager.getOfflineRegions { expected ->
|
|
273
|
+
if (expected.isValue) {
|
|
274
|
+
expected.value?.let { regions ->
|
|
275
|
+
var region = getRegionByName(name, regions);
|
|
276
|
+
|
|
277
|
+
if (region == null) {
|
|
278
|
+
promise.resolve(null);
|
|
279
|
+
Log.w(LOG_TAG, "invalidateRegion - Unknown offline region");
|
|
280
|
+
return@getOfflineRegions
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
region.invalidate { expected ->
|
|
284
|
+
if (expected.isError) {
|
|
285
|
+
promise.reject("invalidateRegion error:", expected.error);
|
|
286
|
+
} else {
|
|
287
|
+
promise.resolve(null);
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
} else {
|
|
292
|
+
promise.reject("invalidateRegion error:", expected.error);
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
@ReactMethod
|
|
299
|
+
fun getPackStatus(name: String?, promise: Promise) {
|
|
300
|
+
UiThreadUtil.runOnUiThread {
|
|
301
|
+
offlineRegionManager.getOfflineRegions { expected ->
|
|
302
|
+
if (expected.isValue) {
|
|
303
|
+
expected.value?.let { regions ->
|
|
304
|
+
var region = getRegionByName(name, regions);
|
|
305
|
+
|
|
306
|
+
if (region == null) {
|
|
307
|
+
promise.resolve(null);
|
|
308
|
+
Log.w(LOG_TAG, "getPackStatus - Unknown offline region");
|
|
309
|
+
return@getOfflineRegions
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
region.getStatus {
|
|
313
|
+
if (it.isValue) {
|
|
314
|
+
it.value?.let { status ->
|
|
315
|
+
promise.resolve(makeRegionStatus(name!!, status));
|
|
316
|
+
}
|
|
317
|
+
} else {
|
|
318
|
+
promise.reject("getPackStatus error:", expected.error);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
} else {
|
|
323
|
+
promise.reject("getPackStatus error:", expected.error);
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
@ReactMethod
|
|
330
|
+
fun pausePackDownload(name: String?, promise: Promise) {
|
|
331
|
+
UiThreadUtil.runOnUiThread {
|
|
332
|
+
offlineRegionManager.getOfflineRegions { expected ->
|
|
333
|
+
if (expected.isValue) {
|
|
334
|
+
expected.value?.let { regions ->
|
|
335
|
+
var region = getRegionByName(name, regions);
|
|
336
|
+
|
|
337
|
+
if (region == null) {
|
|
338
|
+
promise.resolve(null);
|
|
339
|
+
Log.w(LOG_TAG, "pausePackDownload - Unknown offline region");
|
|
340
|
+
return@getOfflineRegions
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
region.setOfflineRegionDownloadState(OfflineRegionDownloadState.INACTIVE)
|
|
344
|
+
promise.resolve(null)
|
|
345
|
+
}
|
|
346
|
+
} else {
|
|
347
|
+
promise.reject("pausePackDownload error:", expected.error);
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
@ReactMethod
|
|
354
|
+
fun resumePackDownload(name: String?, promise: Promise) {
|
|
355
|
+
UiThreadUtil.runOnUiThread {
|
|
356
|
+
offlineRegionManager.getOfflineRegions { expected ->
|
|
357
|
+
if (expected.isValue) {
|
|
358
|
+
expected.value?.let { regions ->
|
|
359
|
+
var region = getRegionByName(name, regions);
|
|
360
|
+
|
|
361
|
+
if (region == null) {
|
|
362
|
+
promise.resolve(null);
|
|
363
|
+
Log.w(LOG_TAG, "resumeRegionDownload - Unknown offline region");
|
|
364
|
+
return@getOfflineRegions
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
region.setOfflineRegionDownloadState(OfflineRegionDownloadState.ACTIVE)
|
|
368
|
+
promise.resolve(null);
|
|
369
|
+
}
|
|
370
|
+
} else {
|
|
371
|
+
promise.reject("resumeRegionDownload error:", expected.error);
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
@ReactMethod
|
|
378
|
+
fun resetDatabase(promise: Promise) {
|
|
379
|
+
UiThreadUtil.runOnUiThread {
|
|
380
|
+
var purgedCount = 0
|
|
381
|
+
offlineRegionManager.getOfflineRegions { expected ->
|
|
382
|
+
if (expected.isValue) {
|
|
383
|
+
expected.value?.let { regions ->
|
|
384
|
+
if (regions.size == 0) promise.resolve(null)
|
|
385
|
+
|
|
386
|
+
for (region in regions) {
|
|
387
|
+
region.setOfflineRegionDownloadState(OfflineRegionDownloadState.INACTIVE)
|
|
388
|
+
|
|
389
|
+
region.purge { expected ->
|
|
390
|
+
if (expected.isError) {
|
|
391
|
+
promise.reject("resetDatabase error:", expected.error);
|
|
392
|
+
} else {
|
|
393
|
+
purgedCount++
|
|
394
|
+
if (purgedCount == regions.size) {
|
|
395
|
+
Log.d(LOG_TAG, "resetDatabase done: ${regions.size} packs were purged")
|
|
396
|
+
promise.resolve(null)
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
} else {
|
|
403
|
+
promise.reject("resetDatabase error:", expected.error);
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
@ReactMethod
|
|
410
|
+
fun migrateOfflineCache(promise: Promise) {
|
|
411
|
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
|
412
|
+
// Old and new cache file paths
|
|
413
|
+
val targetDirectoryPathName = mReactContext.filesDir.absolutePath + "/.mapbox/map_data"
|
|
414
|
+
val sourcePathName = mReactContext.filesDir.absolutePath + "/mbgl-offline.db"
|
|
415
|
+
val sourcePath = Paths.get(sourcePathName)
|
|
416
|
+
val targetPath = Paths.get("$targetDirectoryPathName/map_data.db")
|
|
417
|
+
|
|
418
|
+
try {
|
|
419
|
+
val source = File(sourcePath.toString())
|
|
420
|
+
|
|
421
|
+
if (!source.exists()) {
|
|
422
|
+
Log.d(LOG_TAG, "Nothing to migrate")
|
|
423
|
+
promise.resolve(false)
|
|
424
|
+
return
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
val directory = File(targetDirectoryPathName)
|
|
428
|
+
|
|
429
|
+
directory.mkdirs()
|
|
430
|
+
Files.move(sourcePath, targetPath, StandardCopyOption.REPLACE_EXISTING)
|
|
431
|
+
Log.d(LOG_TAG, "v10 cache directory created successfully")
|
|
432
|
+
promise.resolve(true)
|
|
433
|
+
} catch (e: Exception) {
|
|
434
|
+
val mes = "${e}... file move unsuccessful"
|
|
435
|
+
Log.d(LOG_TAG, mes)
|
|
436
|
+
promise.reject(mes)
|
|
437
|
+
}
|
|
438
|
+
} else {
|
|
439
|
+
val mes = "\"migrateOfflineCache only supported on api level 26 or later\""
|
|
440
|
+
Log.w(LOG_TAG, "migrateOfflineCache only supported on api level 26 or later")
|
|
441
|
+
promise.reject(mes)
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
}
|
|
@@ -100,6 +100,11 @@ object GeoJSONUtils {
|
|
|
100
100
|
val map: WritableMap = WritableNativeMap()
|
|
101
101
|
map.putString("type", "Feature")
|
|
102
102
|
map.putMap("geometry", toPointGeometry(latLng))
|
|
103
|
+
properties?.let {
|
|
104
|
+
if (it.hasKey("id") == true) {
|
|
105
|
+
map.putString("id", it.getString("id"));
|
|
106
|
+
}
|
|
107
|
+
}
|
|
103
108
|
map.putMap("properties", properties)
|
|
104
109
|
return map
|
|
105
110
|
}
|
|
@@ -21,6 +21,10 @@ fun ViewAnnotationOptions.Builder.height(value: Double): ViewAnnotationOptions.B
|
|
|
21
21
|
return this.height(value.toInt())
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
+
fun com.mapbox.maps.ViewAnnotationOptions.Builder.allowOverlapWithPuck(value: Boolean): ViewAnnotationOptions.Builder {
|
|
25
|
+
return this;
|
|
26
|
+
}
|
|
27
|
+
|
|
24
28
|
abstract class OnViewAnnotationUpdatedListener : _OnViewAnnotationUpdatedListener {
|
|
25
29
|
override fun onViewAnnotationPositionUpdated(
|
|
26
30
|
view: View,
|
package/android/src/main/old-arch/com/facebook/react/viewmanagers/RNMBXMapViewManagerDelegate.java
CHANGED
|
@@ -67,6 +67,9 @@ public class RNMBXMapViewManagerDelegate<T extends View, U extends BaseViewManag
|
|
|
67
67
|
case "pitchEnabled":
|
|
68
68
|
mViewManager.setPitchEnabled(view, new DynamicFromObject(value));
|
|
69
69
|
break;
|
|
70
|
+
case "deselectAnnotationOnTap":
|
|
71
|
+
mViewManager.setDeselectAnnotationOnTap(view, new DynamicFromObject(value));
|
|
72
|
+
break;
|
|
70
73
|
case "requestDisallowInterceptTouchEvent":
|
|
71
74
|
mViewManager.setRequestDisallowInterceptTouchEvent(view, new DynamicFromObject(value));
|
|
72
75
|
break;
|
package/android/src/main/old-arch/com/facebook/react/viewmanagers/RNMBXMapViewManagerInterface.java
CHANGED
|
@@ -28,6 +28,7 @@ public interface RNMBXMapViewManagerInterface<T extends View> {
|
|
|
28
28
|
void setScrollEnabled(T view, Dynamic value);
|
|
29
29
|
void setRotateEnabled(T view, Dynamic value);
|
|
30
30
|
void setPitchEnabled(T view, Dynamic value);
|
|
31
|
+
void setDeselectAnnotationOnTap(T view, Dynamic value);
|
|
31
32
|
void setRequestDisallowInterceptTouchEvent(T view, Dynamic value);
|
|
32
33
|
void setProjection(T view, Dynamic value);
|
|
33
34
|
void setLocalizeLabels(T view, Dynamic value);
|
|
@@ -38,6 +38,8 @@ class RNMBXEvent : NSObject, RNMBXEventProtocol {
|
|
|
38
38
|
case onUserTrackingModeChange
|
|
39
39
|
case vectorSourceLayerPress
|
|
40
40
|
case shapeSourceLayerPress
|
|
41
|
+
case annotationSelected = "annotationselected"
|
|
42
|
+
case annotationDeselected = "annotationdeselected"
|
|
41
43
|
}
|
|
42
44
|
|
|
43
45
|
init(type: EventType, payload: [String:Any?]?) {
|
|
@@ -129,13 +129,16 @@ open class RNMBXMapView: UIView {
|
|
|
129
129
|
private var isGestureActive = false
|
|
130
130
|
|
|
131
131
|
var layerWaiters : [String:[(String) -> Void]] = [:]
|
|
132
|
+
|
|
133
|
+
@objc
|
|
134
|
+
public var deselectAnnotationOnTap: Bool = false
|
|
132
135
|
|
|
133
136
|
#if RNMBX_11
|
|
134
137
|
var cancelables = Set<AnyCancelable>()
|
|
135
138
|
#endif
|
|
136
139
|
|
|
137
|
-
lazy var pointAnnotationManager :
|
|
138
|
-
let result =
|
|
140
|
+
lazy var pointAnnotationManager : RNMBXPointAnnotationManager = {
|
|
141
|
+
let result = RNMBXPointAnnotationManager(annotations: mapView.annotations, mapView: mapView)
|
|
139
142
|
self._removeMapboxLongPressGestureRecognizer()
|
|
140
143
|
return result
|
|
141
144
|
}()
|
|
@@ -1158,11 +1161,29 @@ extension RNMBXMapView: GestureManagerDelegate {
|
|
|
1158
1161
|
return orderedLayers.lazy.reversed().compactMap { layersToSource[$0.id] }.first ?? sources.first
|
|
1159
1162
|
}
|
|
1160
1163
|
|
|
1164
|
+
|
|
1165
|
+
|
|
1166
|
+
func _tapEvent(_ tapPoint: CGPoint) -> RNMBXEvent {
|
|
1167
|
+
let location = self.mapboxMap.coordinate(for: tapPoint)
|
|
1168
|
+
var geojson = Feature(geometry: .point(Point(location)));
|
|
1169
|
+
geojson.properties = [
|
|
1170
|
+
"screenPointX": .number(Double(tapPoint.x)),
|
|
1171
|
+
"screenPointY": .number(Double(tapPoint.y))
|
|
1172
|
+
]
|
|
1173
|
+
let event = RNMBXEvent(type:.tap, payload: logged("reactOnPress") { try geojson.toJSON() })
|
|
1174
|
+
return event
|
|
1175
|
+
}
|
|
1176
|
+
|
|
1161
1177
|
@objc
|
|
1162
1178
|
func doHandleTap(_ sender: UITapGestureRecognizer) {
|
|
1163
1179
|
let tapPoint = sender.location(in: self)
|
|
1164
1180
|
pointAnnotationManager.handleTap(sender) { (_: UITapGestureRecognizer) in
|
|
1165
1181
|
DispatchQueue.main.async {
|
|
1182
|
+
if (self.deselectAnnotationOnTap) {
|
|
1183
|
+
if (self.pointAnnotationManager.deselectCurrentlySelected(deselectAnnotationOnTap: true)) {
|
|
1184
|
+
return
|
|
1185
|
+
}
|
|
1186
|
+
}
|
|
1166
1187
|
let touchableSources = self.touchableSources()
|
|
1167
1188
|
self.doHandleTapInSources(sources: touchableSources, tapPoint: tapPoint, hits: [:], touchedSources: []) { (hits, touchedSources) in
|
|
1168
1189
|
|
|
@@ -1194,14 +1215,7 @@ extension RNMBXMapView: GestureManagerDelegate {
|
|
|
1194
1215
|
|
|
1195
1216
|
} else {
|
|
1196
1217
|
if let reactOnPress = self.reactOnPress {
|
|
1197
|
-
|
|
1198
|
-
var geojson = Feature(geometry: .point(Point(location)));
|
|
1199
|
-
geojson.properties = [
|
|
1200
|
-
"screenPointX": .number(Double(tapPoint.x)),
|
|
1201
|
-
"screenPointY": .number(Double(tapPoint.y))
|
|
1202
|
-
]
|
|
1203
|
-
let event = RNMBXEvent(type:.tap, payload: logged("reactOnPress") { try geojson.toJSON() })
|
|
1204
|
-
self.fireEvent(event: event, callback: reactOnPress)
|
|
1218
|
+
self.fireEvent(event: self._tapEvent(tapPoint), callback: reactOnPress)
|
|
1205
1219
|
}
|
|
1206
1220
|
}
|
|
1207
1221
|
}
|
|
@@ -1341,7 +1355,7 @@ extension RNMBXMapView {
|
|
|
1341
1355
|
}
|
|
1342
1356
|
}
|
|
1343
1357
|
|
|
1344
|
-
class
|
|
1358
|
+
class RNMBXPointAnnotationManager : AnnotationInteractionDelegate {
|
|
1345
1359
|
weak var selected : RNMBXPointAnnotation? = nil
|
|
1346
1360
|
private var draggedAnnotation: PointAnnotation?
|
|
1347
1361
|
|
|
@@ -1349,6 +1363,44 @@ class PointAnnotationManager : AnnotationInteractionDelegate {
|
|
|
1349
1363
|
// We handle taps ourselfs
|
|
1350
1364
|
// onTap(annotations: annotations)
|
|
1351
1365
|
}
|
|
1366
|
+
|
|
1367
|
+
func deselectCurrentlySelected(deselectAnnotationOnTap: Bool = false) -> Bool {
|
|
1368
|
+
if let selected = selected {
|
|
1369
|
+
selected.doDeselect(deselectAnnotationOnMapTap: deselectAnnotationOnTap)
|
|
1370
|
+
self.selected = nil
|
|
1371
|
+
return true
|
|
1372
|
+
}
|
|
1373
|
+
return false
|
|
1374
|
+
}
|
|
1375
|
+
|
|
1376
|
+
func onAnnotationClick(pointAnnotation: RNMBXPointAnnotation) {
|
|
1377
|
+
let oldSelected = selected
|
|
1378
|
+
var newSelected: RNMBXPointAnnotation? = pointAnnotation
|
|
1379
|
+
|
|
1380
|
+
if (newSelected == oldSelected) {
|
|
1381
|
+
newSelected = nil
|
|
1382
|
+
}
|
|
1383
|
+
|
|
1384
|
+
deselectCurrentlySelected()
|
|
1385
|
+
|
|
1386
|
+
if let newSelected = newSelected {
|
|
1387
|
+
newSelected.doSelect()
|
|
1388
|
+
selected = newSelected
|
|
1389
|
+
}
|
|
1390
|
+
}
|
|
1391
|
+
|
|
1392
|
+
func lookup(_ annotation: PointAnnotation) -> RNMBXPointAnnotation? {
|
|
1393
|
+
guard let userInfo = annotation.userInfo else {
|
|
1394
|
+
return nil
|
|
1395
|
+
}
|
|
1396
|
+
if let rnmbxPointAnnotationWeakRef = userInfo[RNMBXPointAnnotation.key] as? WeakRef<RNMBXPointAnnotation> {
|
|
1397
|
+
if let rnmbxPointAnnotation = rnmbxPointAnnotationWeakRef.object {
|
|
1398
|
+
return rnmbxPointAnnotation
|
|
1399
|
+
}
|
|
1400
|
+
}
|
|
1401
|
+
return nil
|
|
1402
|
+
}
|
|
1403
|
+
|
|
1352
1404
|
|
|
1353
1405
|
func onTap(annotations: [Annotation]) {
|
|
1354
1406
|
guard annotations.count > 0 else {
|
|
@@ -1356,34 +1408,9 @@ class PointAnnotationManager : AnnotationInteractionDelegate {
|
|
|
1356
1408
|
}
|
|
1357
1409
|
|
|
1358
1410
|
for annotation in annotations {
|
|
1359
|
-
if let
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
if let RNMBXPointAnnotation = userInfo[RNMBXPointAnnotation.key] as? WeakRef<RNMBXPointAnnotation> {
|
|
1363
|
-
if let pt = RNMBXPointAnnotation.object {
|
|
1364
|
-
let position = pt.superview?.convert(pt.layer.position, to: nil)
|
|
1365
|
-
let location = pt.map?.mapboxMap.coordinate(for: position!)
|
|
1366
|
-
var geojson = Feature(geometry: .point(Point(location!)))
|
|
1367
|
-
geojson.identifier = .string(pt.id)
|
|
1368
|
-
geojson.properties = [
|
|
1369
|
-
"screenPointX": .number(Double(position!.x)),
|
|
1370
|
-
"screenPointY": .number(Double(position!.y))
|
|
1371
|
-
]
|
|
1372
|
-
let event = RNMBXEvent(type:.tap, payload: logged("doHandleTap") { try geojson.toJSON() })
|
|
1373
|
-
if let selected = selected {
|
|
1374
|
-
guard let onDeselected = pt.onDeselected else {
|
|
1375
|
-
return
|
|
1376
|
-
}
|
|
1377
|
-
onDeselected(event.toJSON())
|
|
1378
|
-
selected.onDeselect()
|
|
1379
|
-
}
|
|
1380
|
-
guard let onSelected = pt.onSelected else {
|
|
1381
|
-
return
|
|
1382
|
-
}
|
|
1383
|
-
onSelected(event.toJSON())
|
|
1384
|
-
pt.onSelect()
|
|
1385
|
-
selected = pt
|
|
1386
|
-
}
|
|
1411
|
+
if let annotation = annotation as? PointAnnotation {
|
|
1412
|
+
if let pointAnnotation = lookup(annotation) {
|
|
1413
|
+
onAnnotationClick(pointAnnotation: pointAnnotation)
|
|
1387
1414
|
}
|
|
1388
1415
|
}
|
|
1389
1416
|
}
|