@maplibre/maplibre-react-native 11.0.0-alpha.31 → 11.0.0-alpha.33
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 -1
- package/android/src/main/java/org/maplibre/reactnative/MLRNPackage.kt +10 -12
- package/android/src/main/java/org/maplibre/reactnative/components/mapview/MLRNMapView.kt +9 -0
- package/android/src/main/java/org/maplibre/reactnative/components/mapview/MLRNMapViewManager.kt +5 -1
- package/android/src/main/java/org/maplibre/reactnative/modules/MLRNModule.java +6 -24
- package/android/src/main/java/org/maplibre/reactnative/modules/MLRNOfflineModule.kt +561 -0
- package/ios/components/map-view/MLRNMapView.h +1 -0
- package/ios/components/map-view/MLRNMapView.m +5 -0
- package/ios/components/map-view/MLRNMapViewComponentView.mm +4 -0
- package/ios/modules/mlrn/MLRNModule.m +0 -13
- package/ios/modules/offline/MLRNOfflineModule.h +4 -7
- package/ios/modules/offline/MLRNOfflineModule.mm +693 -0
- package/lib/commonjs/MLRNModule.js +1 -3
- package/lib/commonjs/MLRNModule.js.map +1 -1
- package/lib/commonjs/components/map-view/AndroidTextureMapViewNativeComponent.ts +1 -0
- package/lib/commonjs/components/map-view/MapView.js.map +1 -1
- package/lib/commonjs/components/map-view/MapViewNativeComponent.ts +1 -0
- package/lib/commonjs/index.js +0 -8
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/modules/offline/NativeOfflineModule.js +9 -0
- package/lib/commonjs/modules/offline/NativeOfflineModule.js.map +1 -0
- package/lib/commonjs/modules/offline/OfflineManager.js +124 -164
- package/lib/commonjs/modules/offline/OfflineManager.js.map +1 -1
- package/lib/commonjs/modules/offline/OfflinePack.js +15 -25
- package/lib/commonjs/modules/offline/OfflinePack.js.map +1 -1
- package/lib/module/MLRNModule.js +0 -1
- package/lib/module/MLRNModule.js.map +1 -1
- package/lib/module/components/map-view/AndroidTextureMapViewNativeComponent.ts +1 -0
- package/lib/module/components/map-view/MapView.js.map +1 -1
- package/lib/module/components/map-view/MapViewNativeComponent.ts +1 -0
- package/lib/module/index.js +0 -1
- package/lib/module/index.js.map +1 -1
- package/lib/module/modules/offline/NativeOfflineModule.js +5 -0
- package/lib/module/modules/offline/NativeOfflineModule.js.map +1 -0
- package/lib/module/modules/offline/OfflineManager.js +123 -163
- package/lib/module/modules/offline/OfflineManager.js.map +1 -1
- package/lib/module/modules/offline/OfflinePack.js +14 -25
- package/lib/module/modules/offline/OfflinePack.js.map +1 -1
- package/lib/typescript/commonjs/src/MLRNModule.d.ts +1 -6
- package/lib/typescript/commonjs/src/MLRNModule.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/components/map-view/AndroidTextureMapViewNativeComponent.d.ts +1 -0
- package/lib/typescript/commonjs/src/components/map-view/AndroidTextureMapViewNativeComponent.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/components/map-view/MapView.d.ts +6 -0
- package/lib/typescript/commonjs/src/components/map-view/MapView.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/components/map-view/MapViewNativeComponent.d.ts +1 -0
- package/lib/typescript/commonjs/src/components/map-view/MapViewNativeComponent.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/index.d.ts +2 -5
- package/lib/typescript/commonjs/src/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/modules/offline/NativeOfflineModule.d.ts +50 -0
- package/lib/typescript/commonjs/src/modules/offline/NativeOfflineModule.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/modules/offline/OfflineManager.d.ts +66 -69
- package/lib/typescript/commonjs/src/modules/offline/OfflineManager.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/modules/offline/OfflinePack.d.ts +11 -9
- package/lib/typescript/commonjs/src/modules/offline/OfflinePack.d.ts.map +1 -1
- package/lib/typescript/module/src/MLRNModule.d.ts +1 -6
- package/lib/typescript/module/src/MLRNModule.d.ts.map +1 -1
- package/lib/typescript/module/src/components/map-view/AndroidTextureMapViewNativeComponent.d.ts +1 -0
- package/lib/typescript/module/src/components/map-view/AndroidTextureMapViewNativeComponent.d.ts.map +1 -1
- package/lib/typescript/module/src/components/map-view/MapView.d.ts +6 -0
- package/lib/typescript/module/src/components/map-view/MapView.d.ts.map +1 -1
- package/lib/typescript/module/src/components/map-view/MapViewNativeComponent.d.ts +1 -0
- package/lib/typescript/module/src/components/map-view/MapViewNativeComponent.d.ts.map +1 -1
- package/lib/typescript/module/src/index.d.ts +2 -5
- package/lib/typescript/module/src/index.d.ts.map +1 -1
- package/lib/typescript/module/src/modules/offline/NativeOfflineModule.d.ts +50 -0
- package/lib/typescript/module/src/modules/offline/NativeOfflineModule.d.ts.map +1 -0
- package/lib/typescript/module/src/modules/offline/OfflineManager.d.ts +66 -69
- package/lib/typescript/module/src/modules/offline/OfflineManager.d.ts.map +1 -1
- package/lib/typescript/module/src/modules/offline/OfflinePack.d.ts +11 -9
- package/lib/typescript/module/src/modules/offline/OfflinePack.d.ts.map +1 -1
- package/package.json +7 -3
- package/src/MLRNModule.ts +0 -8
- package/src/components/map-view/AndroidTextureMapViewNativeComponent.ts +1 -0
- package/src/components/map-view/MapView.tsx +7 -0
- package/src/components/map-view/MapViewNativeComponent.ts +1 -0
- package/src/index.ts +13 -5
- package/src/modules/offline/NativeOfflineModule.ts +63 -0
- package/src/modules/offline/OfflineManager.ts +174 -210
- package/src/modules/offline/OfflinePack.ts +22 -32
- package/android/src/main/java/org/maplibre/reactnative/modules/MLRNOfflineModule.java +0 -586
- package/ios/modules/offline/MLRNOfflineModule.m +0 -524
- package/lib/commonjs/modules/offline/OfflineCreatePackOptions.js +0 -37
- package/lib/commonjs/modules/offline/OfflineCreatePackOptions.js.map +0 -1
- package/lib/commonjs/utils/makeNativeBounds.js +0 -11
- package/lib/commonjs/utils/makeNativeBounds.js.map +0 -1
- package/lib/module/modules/offline/OfflineCreatePackOptions.js +0 -32
- package/lib/module/modules/offline/OfflineCreatePackOptions.js.map +0 -1
- package/lib/module/utils/makeNativeBounds.js +0 -7
- package/lib/module/utils/makeNativeBounds.js.map +0 -1
- package/lib/typescript/commonjs/src/modules/offline/OfflineCreatePackOptions.d.ts +0 -20
- package/lib/typescript/commonjs/src/modules/offline/OfflineCreatePackOptions.d.ts.map +0 -1
- package/lib/typescript/commonjs/src/utils/makeNativeBounds.d.ts +0 -2
- package/lib/typescript/commonjs/src/utils/makeNativeBounds.d.ts.map +0 -1
- package/lib/typescript/module/src/modules/offline/OfflineCreatePackOptions.d.ts +0 -20
- package/lib/typescript/module/src/modules/offline/OfflineCreatePackOptions.d.ts.map +0 -1
- package/lib/typescript/module/src/utils/makeNativeBounds.d.ts +0 -2
- package/lib/typescript/module/src/utils/makeNativeBounds.d.ts.map +0 -1
- package/src/modules/offline/OfflineCreatePackOptions.ts +0 -53
- package/src/utils/makeNativeBounds.ts +0 -5
|
@@ -0,0 +1,561 @@
|
|
|
1
|
+
package org.maplibre.reactnative.modules
|
|
2
|
+
|
|
3
|
+
import android.content.Context
|
|
4
|
+
import android.os.Handler
|
|
5
|
+
import android.os.Looper
|
|
6
|
+
import android.util.Log
|
|
7
|
+
import com.facebook.react.bridge.Arguments
|
|
8
|
+
import com.facebook.react.bridge.Promise
|
|
9
|
+
import com.facebook.react.bridge.ReactApplicationContext
|
|
10
|
+
import com.facebook.react.bridge.ReadableMap
|
|
11
|
+
import com.facebook.react.bridge.WritableMap
|
|
12
|
+
import com.facebook.react.bridge.WritableNativeMap
|
|
13
|
+
import org.json.JSONException
|
|
14
|
+
import org.json.JSONObject
|
|
15
|
+
import org.maplibre.android.geometry.LatLngBounds
|
|
16
|
+
import org.maplibre.android.offline.OfflineManager
|
|
17
|
+
import org.maplibre.android.offline.OfflineRegion
|
|
18
|
+
import org.maplibre.android.offline.OfflineRegionError
|
|
19
|
+
import org.maplibre.android.offline.OfflineRegionStatus
|
|
20
|
+
import org.maplibre.android.offline.OfflineTilePyramidRegionDefinition
|
|
21
|
+
import org.maplibre.android.storage.FileSource
|
|
22
|
+
import org.maplibre.reactnative.NativeOfflineModuleSpec
|
|
23
|
+
import org.maplibre.reactnative.utils.GeoJSONUtils
|
|
24
|
+
import java.util.UUID
|
|
25
|
+
|
|
26
|
+
class MLRNOfflineModule(reactContext: ReactApplicationContext) :
|
|
27
|
+
NativeOfflineModuleSpec(reactContext) {
|
|
28
|
+
|
|
29
|
+
companion object {
|
|
30
|
+
const val NAME = "MLRNOfflineModule"
|
|
31
|
+
|
|
32
|
+
const val MIGRATION_KEY = "migrationVersion"
|
|
33
|
+
const val MIGRATION_VERSION = 1
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
private val context: Context = reactContext.applicationContext
|
|
37
|
+
private var progressEventThrottle = 300.0
|
|
38
|
+
|
|
39
|
+
override fun initialize() {
|
|
40
|
+
Handler(Looper.getMainLooper()).post {
|
|
41
|
+
runMigrations()
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
override fun getName(): String = NAME
|
|
46
|
+
|
|
47
|
+
override fun createPack(options: ReadableMap, promise: Promise) {
|
|
48
|
+
val offlineManager = OfflineManager.getInstance(context)
|
|
49
|
+
|
|
50
|
+
val packId = UUID.randomUUID().toString()
|
|
51
|
+
val latLngBounds = getBoundsFromOptions(options)
|
|
52
|
+
val definition = makeDefinition(latLngBounds, options)
|
|
53
|
+
|
|
54
|
+
val metadataJson = JSONObject()
|
|
55
|
+
metadataJson.put(MIGRATION_KEY, MIGRATION_VERSION)
|
|
56
|
+
metadataJson.put("id", packId)
|
|
57
|
+
|
|
58
|
+
val metadataString = options.getString("metadata")
|
|
59
|
+
if (metadataString != null && metadataString.isNotEmpty()) {
|
|
60
|
+
metadataJson.put("metadata", metadataString)
|
|
61
|
+
} else {
|
|
62
|
+
metadataJson.put("metadata", "{}")
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
val metadataBytes = metadataJson.toString().toByteArray(Charsets.UTF_8)
|
|
66
|
+
|
|
67
|
+
offlineManager.createOfflineRegion(
|
|
68
|
+
definition, metadataBytes, object : OfflineManager.CreateOfflineRegionCallback {
|
|
69
|
+
override fun onCreate(offlineRegion: OfflineRegion) {
|
|
70
|
+
val pack = fromOfflineRegion(offlineRegion)
|
|
71
|
+
promise.resolve(pack)
|
|
72
|
+
setOfflineRegionObserver(packId, offlineRegion)
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
override fun onError(error: String) {
|
|
76
|
+
emitOnError(makeErrorPayload(packId, error))
|
|
77
|
+
Log.e(NAME, "createPack error: $error")
|
|
78
|
+
}
|
|
79
|
+
})
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
override fun getPacks(promise: Promise) {
|
|
83
|
+
activateFileSource()
|
|
84
|
+
|
|
85
|
+
val offlineManager = OfflineManager.getInstance(context)
|
|
86
|
+
|
|
87
|
+
offlineManager.listOfflineRegions(object : OfflineManager.ListOfflineRegionsCallback {
|
|
88
|
+
override fun onList(offlineRegions: Array<OfflineRegion>?) {
|
|
89
|
+
val payload = Arguments.createArray()
|
|
90
|
+
offlineRegions?.forEach { region ->
|
|
91
|
+
payload.pushMap(fromOfflineRegion(region))
|
|
92
|
+
}
|
|
93
|
+
promise.resolve(payload)
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
override fun onError(error: String) {
|
|
97
|
+
promise.reject("getRegions", error)
|
|
98
|
+
}
|
|
99
|
+
})
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
override fun invalidateAmbientCache(promise: Promise) {
|
|
103
|
+
activateFileSource()
|
|
104
|
+
val offlineManager = OfflineManager.getInstance(context)
|
|
105
|
+
offlineManager.invalidateAmbientCache(object : OfflineManager.FileSourceCallback {
|
|
106
|
+
override fun onSuccess() {
|
|
107
|
+
promise.resolve(null)
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
override fun onError(message: String) {
|
|
111
|
+
promise.reject("invalidateAmbientCache", message)
|
|
112
|
+
}
|
|
113
|
+
})
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
override fun clearAmbientCache(promise: Promise) {
|
|
117
|
+
activateFileSource()
|
|
118
|
+
val offlineManager = OfflineManager.getInstance(context)
|
|
119
|
+
offlineManager.clearAmbientCache(object : OfflineManager.FileSourceCallback {
|
|
120
|
+
override fun onSuccess() {
|
|
121
|
+
promise.resolve(null)
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
override fun onError(message: String) {
|
|
125
|
+
promise.reject("clearAmbientCache", message)
|
|
126
|
+
}
|
|
127
|
+
})
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
override fun setMaximumAmbientCacheSize(size: Double, promise: Promise) {
|
|
131
|
+
activateFileSource()
|
|
132
|
+
val offlineManager = OfflineManager.getInstance(context)
|
|
133
|
+
offlineManager.setMaximumAmbientCacheSize(
|
|
134
|
+
size.toLong(), object : OfflineManager.FileSourceCallback {
|
|
135
|
+
override fun onSuccess() {
|
|
136
|
+
promise.resolve(null)
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
override fun onError(message: String) {
|
|
140
|
+
promise.reject("setMaximumAmbientCacheSize", message)
|
|
141
|
+
}
|
|
142
|
+
})
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
override fun resetDatabase(promise: Promise) {
|
|
146
|
+
activateFileSource()
|
|
147
|
+
val offlineManager = OfflineManager.getInstance(context)
|
|
148
|
+
offlineManager.resetDatabase(object : OfflineManager.FileSourceCallback {
|
|
149
|
+
override fun onSuccess() {
|
|
150
|
+
promise.resolve(null)
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
override fun onError(message: String) {
|
|
154
|
+
promise.reject("resetDatabase", message)
|
|
155
|
+
}
|
|
156
|
+
})
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
override fun getPackStatus(id: String, promise: Promise) {
|
|
160
|
+
activateFileSource()
|
|
161
|
+
val offlineManager = OfflineManager.getInstance(context)
|
|
162
|
+
|
|
163
|
+
offlineManager.listOfflineRegions(object : OfflineManager.ListOfflineRegionsCallback {
|
|
164
|
+
override fun onList(offlineRegions: Array<OfflineRegion>?) {
|
|
165
|
+
val region = getRegionById(id, offlineRegions)
|
|
166
|
+
|
|
167
|
+
if (region == null) {
|
|
168
|
+
promise.resolve(null)
|
|
169
|
+
Log.w(NAME, "getPackStatus - Unknown offline region")
|
|
170
|
+
return
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
region.getStatus(object : OfflineRegion.OfflineRegionStatusCallback {
|
|
174
|
+
override fun onStatus(status: OfflineRegionStatus?) {
|
|
175
|
+
if (status != null) {
|
|
176
|
+
promise.resolve(makeRegionStatus(id, status))
|
|
177
|
+
} else {
|
|
178
|
+
promise.reject("getPackStatus", "Status is null")
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
override fun onError(error: String?) {
|
|
183
|
+
promise.reject("getPackStatus", error ?: "Unknown error")
|
|
184
|
+
}
|
|
185
|
+
})
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
override fun onError(error: String) {
|
|
189
|
+
promise.reject("getPackStatus", error)
|
|
190
|
+
}
|
|
191
|
+
})
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
override fun setPackObserver(id: String, promise: Promise) {
|
|
195
|
+
activateFileSource()
|
|
196
|
+
val offlineManager = OfflineManager.getInstance(context)
|
|
197
|
+
|
|
198
|
+
offlineManager.listOfflineRegions(object : OfflineManager.ListOfflineRegionsCallback {
|
|
199
|
+
override fun onList(offlineRegions: Array<OfflineRegion>?) {
|
|
200
|
+
val region = getRegionById(id, offlineRegions)
|
|
201
|
+
val hasRegion = region != null
|
|
202
|
+
|
|
203
|
+
if (hasRegion) {
|
|
204
|
+
setOfflineRegionObserver(id, region)
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
promise.resolve(hasRegion)
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
override fun onError(error: String) {
|
|
211
|
+
promise.reject("setPackObserver", error)
|
|
212
|
+
}
|
|
213
|
+
})
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
override fun invalidatePack(id: String, promise: Promise) {
|
|
217
|
+
activateFileSource()
|
|
218
|
+
val offlineManager = OfflineManager.getInstance(context)
|
|
219
|
+
|
|
220
|
+
offlineManager.listOfflineRegions(object : OfflineManager.ListOfflineRegionsCallback {
|
|
221
|
+
override fun onList(offlineRegions: Array<OfflineRegion>?) {
|
|
222
|
+
val region = getRegionById(id, offlineRegions)
|
|
223
|
+
|
|
224
|
+
if (region == null) {
|
|
225
|
+
promise.resolve(null)
|
|
226
|
+
Log.w(NAME, "invalidateRegion - Unknown offline region")
|
|
227
|
+
return
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
region.invalidate(object : OfflineRegion.OfflineRegionInvalidateCallback {
|
|
231
|
+
override fun onInvalidate() {
|
|
232
|
+
promise.resolve(null)
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
override fun onError(error: String) {
|
|
236
|
+
promise.reject("invalidateRegion", error)
|
|
237
|
+
}
|
|
238
|
+
})
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
override fun onError(error: String) {
|
|
242
|
+
promise.reject("invalidateRegion", error)
|
|
243
|
+
}
|
|
244
|
+
})
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
override fun deletePack(id: String, promise: Promise) {
|
|
248
|
+
activateFileSource()
|
|
249
|
+
val offlineManager = OfflineManager.getInstance(context)
|
|
250
|
+
|
|
251
|
+
offlineManager.listOfflineRegions(object : OfflineManager.ListOfflineRegionsCallback {
|
|
252
|
+
override fun onList(offlineRegions: Array<OfflineRegion>?) {
|
|
253
|
+
val region = getRegionById(id, offlineRegions)
|
|
254
|
+
|
|
255
|
+
if (region == null) {
|
|
256
|
+
promise.resolve(null)
|
|
257
|
+
Log.w(NAME, "deleteRegion - Unknown offline region")
|
|
258
|
+
return
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
region.setDownloadState(OfflineRegion.STATE_INACTIVE)
|
|
262
|
+
region.delete(object : OfflineRegion.OfflineRegionDeleteCallback {
|
|
263
|
+
override fun onDelete() {
|
|
264
|
+
promise.resolve(null)
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
override fun onError(error: String) {
|
|
268
|
+
promise.reject("deleteRegion", error)
|
|
269
|
+
}
|
|
270
|
+
})
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
override fun onError(error: String) {
|
|
274
|
+
promise.reject("deleteRegion", error)
|
|
275
|
+
}
|
|
276
|
+
})
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
override fun pausePackDownload(id: String, promise: Promise) {
|
|
280
|
+
activateFileSource()
|
|
281
|
+
val offlineManager = OfflineManager.getInstance(context)
|
|
282
|
+
|
|
283
|
+
offlineManager.listOfflineRegions(object : OfflineManager.ListOfflineRegionsCallback {
|
|
284
|
+
override fun onList(offlineRegions: Array<OfflineRegion>?) {
|
|
285
|
+
val offlineRegion = getRegionById(id, offlineRegions)
|
|
286
|
+
|
|
287
|
+
if (offlineRegion == null) {
|
|
288
|
+
promise.reject("pauseRegionDownload", "Unknown offline region")
|
|
289
|
+
return
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
Handler(Looper.getMainLooper()).post {
|
|
293
|
+
offlineRegion.setDownloadState(OfflineRegion.STATE_INACTIVE)
|
|
294
|
+
promise.resolve(null)
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
override fun onError(error: String) {
|
|
299
|
+
promise.reject("pauseRegionDownload", error)
|
|
300
|
+
}
|
|
301
|
+
})
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
override fun resumePackDownload(id: String, promise: Promise) {
|
|
305
|
+
activateFileSource()
|
|
306
|
+
val offlineManager = OfflineManager.getInstance(context)
|
|
307
|
+
|
|
308
|
+
offlineManager.listOfflineRegions(object : OfflineManager.ListOfflineRegionsCallback {
|
|
309
|
+
override fun onList(offlineRegions: Array<OfflineRegion>?) {
|
|
310
|
+
val offlineRegion = getRegionById(id, offlineRegions)
|
|
311
|
+
|
|
312
|
+
if (offlineRegion == null) {
|
|
313
|
+
promise.reject("resumeRegionDownload", "Unknown offline region")
|
|
314
|
+
return
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
offlineRegion.setDownloadState(OfflineRegion.STATE_ACTIVE)
|
|
318
|
+
promise.resolve(null)
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
override fun onError(error: String) {
|
|
322
|
+
promise.reject("resumeRegionDownload", error)
|
|
323
|
+
}
|
|
324
|
+
})
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
override fun mergeOfflineRegions(path: String, promise: Promise) {
|
|
328
|
+
activateFileSource()
|
|
329
|
+
val offlineManager = OfflineManager.getInstance(context)
|
|
330
|
+
|
|
331
|
+
offlineManager.mergeOfflineRegions(
|
|
332
|
+
path, object : OfflineManager.MergeOfflineRegionsCallback {
|
|
333
|
+
override fun onMerge(offlineRegions: Array<OfflineRegion>?) {
|
|
334
|
+
promise.resolve(null)
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
override fun onError(error: String) {
|
|
338
|
+
promise.reject("mergeOfflineRegions", error)
|
|
339
|
+
}
|
|
340
|
+
})
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
override fun setTileCountLimit(limit: Double) {
|
|
344
|
+
val offlineManager = OfflineManager.getInstance(context)
|
|
345
|
+
offlineManager.setOfflineMapboxTileCountLimit(limit.toLong())
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
override fun setProgressEventThrottle(throttleValue: Double) {
|
|
349
|
+
progressEventThrottle = throttleValue
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
private fun makeDefinition(
|
|
353
|
+
latLngBounds: LatLngBounds, options: ReadableMap
|
|
354
|
+
): OfflineTilePyramidRegionDefinition {
|
|
355
|
+
return OfflineTilePyramidRegionDefinition(
|
|
356
|
+
options.getString("mapStyle"),
|
|
357
|
+
latLngBounds,
|
|
358
|
+
options.getDouble("minZoom"),
|
|
359
|
+
options.getDouble("maxZoom"),
|
|
360
|
+
context.resources.displayMetrics.density
|
|
361
|
+
)
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
private fun parseRegionMetadata(region: OfflineRegion): JSONObject {
|
|
365
|
+
return try {
|
|
366
|
+
JSONObject(String(region.metadata))
|
|
367
|
+
} catch (e: JSONException) {
|
|
368
|
+
Log.w(NAME, "Failed to parse pack metadata: ${e.localizedMessage}")
|
|
369
|
+
JSONObject()
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
private fun runMigrations() {
|
|
374
|
+
activateFileSource()
|
|
375
|
+
val offlineManager = OfflineManager.getInstance(context)
|
|
376
|
+
|
|
377
|
+
offlineManager.listOfflineRegions(object : OfflineManager.ListOfflineRegionsCallback {
|
|
378
|
+
override fun onList(offlineRegions: Array<OfflineRegion>?) {
|
|
379
|
+
if (offlineRegions == null) {
|
|
380
|
+
Log.e(NAME, "No packs found for migration")
|
|
381
|
+
|
|
382
|
+
return
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
val regionsToMigrate = mutableListOf<OfflineRegion>()
|
|
386
|
+
for (region in offlineRegions) {
|
|
387
|
+
val metadata = parseRegionMetadata(region)
|
|
388
|
+
if (!metadata.has(MIGRATION_KEY) || metadata.getInt(MIGRATION_KEY) != MIGRATION_VERSION) {
|
|
389
|
+
regionsToMigrate.add(region)
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
if (regionsToMigrate.isEmpty()) {
|
|
394
|
+
Log.d(NAME, "No packs need migration")
|
|
395
|
+
|
|
396
|
+
return
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
Log.d(NAME, "Migrating ${regionsToMigrate.size} pack(s)")
|
|
400
|
+
|
|
401
|
+
for (region in regionsToMigrate) {
|
|
402
|
+
migrateRegion(region)
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
override fun onError(error: String) {
|
|
407
|
+
Log.e(NAME, "Failed to list packs for migration: $error")
|
|
408
|
+
}
|
|
409
|
+
})
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
private fun migrateRegion(region: OfflineRegion) {
|
|
413
|
+
val oldMetadata = parseRegionMetadata(region)
|
|
414
|
+
|
|
415
|
+
val newMetadata = JSONObject()
|
|
416
|
+
newMetadata.put(MIGRATION_KEY, MIGRATION_VERSION)
|
|
417
|
+
newMetadata.put("id", UUID.randomUUID().toString())
|
|
418
|
+
newMetadata.put("metadata", oldMetadata.toString())
|
|
419
|
+
|
|
420
|
+
region.updateMetadata(
|
|
421
|
+
newMetadata.toString().toByteArray(Charsets.UTF_8),
|
|
422
|
+
object : OfflineRegion.OfflineRegionUpdateMetadataCallback {
|
|
423
|
+
override fun onUpdate(metadata: ByteArray) {
|
|
424
|
+
val id = newMetadata.optString("id", "unknown")
|
|
425
|
+
Log.d(NAME, "Successfully migrated pack: $id")
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
override fun onError(error: String) {
|
|
429
|
+
Log.e(NAME, "Failed to migrate pack: $error")
|
|
430
|
+
}
|
|
431
|
+
})
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
private fun setOfflineRegionObserver(id: String, region: OfflineRegion) {
|
|
435
|
+
region.setObserver(object : OfflineRegion.OfflineRegionObserver {
|
|
436
|
+
var prevStatus: OfflineRegionStatus? = null
|
|
437
|
+
var timestamp = System.currentTimeMillis()
|
|
438
|
+
|
|
439
|
+
override fun onStatusChanged(status: OfflineRegionStatus) {
|
|
440
|
+
if (shouldSendUpdate(System.currentTimeMillis(), status)) {
|
|
441
|
+
emitOnProgress(makeRegionStatus(id, status))
|
|
442
|
+
timestamp = System.currentTimeMillis()
|
|
443
|
+
}
|
|
444
|
+
prevStatus = status
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
override fun onError(error: OfflineRegionError) {
|
|
448
|
+
emitOnError(makeErrorPayload(id, error.message))
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
override fun mapboxTileCountLimitExceeded(limit: Long) {
|
|
452
|
+
val message = "Mapbox tile limit exceeded $limit"
|
|
453
|
+
emitOnError(makeErrorPayload(id, message))
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
private fun shouldSendUpdate(
|
|
457
|
+
currentTimestamp: Long, curStatus: OfflineRegionStatus
|
|
458
|
+
): Boolean {
|
|
459
|
+
val prev = prevStatus ?: return false
|
|
460
|
+
|
|
461
|
+
if (prev.downloadState != curStatus.downloadState) {
|
|
462
|
+
return true
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
if (currentTimestamp - timestamp > progressEventThrottle) {
|
|
466
|
+
return true
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
return false
|
|
470
|
+
}
|
|
471
|
+
})
|
|
472
|
+
|
|
473
|
+
region.setDownloadState(OfflineRegion.STATE_ACTIVE)
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
private fun makeErrorPayload(id: String, message: String): WritableMap {
|
|
477
|
+
val payload = WritableNativeMap()
|
|
478
|
+
payload.putString("id", id)
|
|
479
|
+
payload.putString("message", message)
|
|
480
|
+
|
|
481
|
+
return payload
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
private fun makeRegionStatus(
|
|
485
|
+
id: String, status: OfflineRegionStatus
|
|
486
|
+
): WritableMap {
|
|
487
|
+
val map = Arguments.createMap()
|
|
488
|
+
|
|
489
|
+
var state = "inactive"
|
|
490
|
+
var percentage: Double
|
|
491
|
+
|
|
492
|
+
if (status.isComplete) {
|
|
493
|
+
state = "complete"
|
|
494
|
+
percentage = 100.0
|
|
495
|
+
} else {
|
|
496
|
+
percentage = if (status.requiredResourceCount >= 0) {
|
|
497
|
+
100.0 * status.completedResourceCount / status.requiredResourceCount
|
|
498
|
+
} else {
|
|
499
|
+
0.0
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
if (status.downloadState == OfflineRegion.STATE_ACTIVE) {
|
|
503
|
+
state = "active"
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
map.putString("id", id)
|
|
508
|
+
map.putString("state", state)
|
|
509
|
+
map.putDouble("percentage", percentage)
|
|
510
|
+
map.putInt("completedResourceCount", status.completedResourceCount.toInt())
|
|
511
|
+
map.putInt("completedResourceSize", status.completedResourceSize.toInt())
|
|
512
|
+
map.putInt("completedTileSize", status.completedTileSize.toInt())
|
|
513
|
+
map.putInt("completedTileCount", status.completedTileCount.toInt())
|
|
514
|
+
map.putInt("requiredResourceCount", status.requiredResourceCount.toInt())
|
|
515
|
+
|
|
516
|
+
return map
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
private fun getBoundsFromOptions(options: ReadableMap): LatLngBounds {
|
|
520
|
+
val boundsArray = options.getArray("bounds")
|
|
521
|
+
val bounds = GeoJSONUtils.toLatLngBounds(boundsArray)
|
|
522
|
+
?: throw IllegalArgumentException("bounds must be an array of 4 numbers [west, south, east, north]")
|
|
523
|
+
|
|
524
|
+
return bounds
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
private fun fromOfflineRegion(region: OfflineRegion): WritableMap {
|
|
528
|
+
val map = Arguments.createMap()
|
|
529
|
+
|
|
530
|
+
val metadata = parseRegionMetadata(region)
|
|
531
|
+
|
|
532
|
+
map.putString("id", metadata.optString("id", ""))
|
|
533
|
+
map.putString("metadata", metadata.optString("metadata", "{}"))
|
|
534
|
+
|
|
535
|
+
region.definition.bounds?.let { bounds ->
|
|
536
|
+
map.putArray("bounds", GeoJSONUtils.fromLatLngBounds(bounds))
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
return map
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
private fun getRegionById(id: String?, offlineRegions: Array<OfflineRegion>?): OfflineRegion? {
|
|
543
|
+
if (id.isNullOrEmpty() || offlineRegions == null) {
|
|
544
|
+
return null
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
for (region in offlineRegions) {
|
|
548
|
+
val metadata = parseRegionMetadata(region)
|
|
549
|
+
if (metadata.has("id") && id == metadata.optString("id")) {
|
|
550
|
+
return region
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
return null
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
private fun activateFileSource() {
|
|
558
|
+
val fileSource = FileSource.getInstance(context)
|
|
559
|
+
fileSource.activate()
|
|
560
|
+
}
|
|
561
|
+
}
|
|
@@ -55,6 +55,7 @@ typedef void (^StyleLoadedBlock)(MLNStyle *__nonnull style);
|
|
|
55
55
|
|
|
56
56
|
@property (nonatomic, assign) BOOL reactCompassEnabled;
|
|
57
57
|
@property (nonatomic, strong, nullable) NSDictionary<NSString *, NSNumber *> *reactCompassPosition;
|
|
58
|
+
@property (nonatomic, assign) BOOL reactCompassHiddenFacingNorth;
|
|
58
59
|
|
|
59
60
|
@property (nonatomic, assign) MLNCoordinateBounds maxBounds;
|
|
60
61
|
|
|
@@ -462,6 +462,11 @@ static double const M2PI = M_PI * 2;
|
|
|
462
462
|
}];
|
|
463
463
|
}
|
|
464
464
|
|
|
465
|
+
- (void)setReactCompassHiddenFacingNorth:(BOOL)reactCompassHiddenFacingNorth {
|
|
466
|
+
_reactCompassHiddenFacingNorth = reactCompassHiddenFacingNorth;
|
|
467
|
+
self.compassView.compassVisibility = _reactCompassHiddenFacingNorth ? MLNOrnamentVisibilityAdaptive : MLNOrnamentVisibilityVisible;
|
|
468
|
+
}
|
|
469
|
+
|
|
465
470
|
- (void)setReactShowUserLocation:(BOOL)reactShowUserLocation {
|
|
466
471
|
self.showsUserLocation = reactShowUserLocation;
|
|
467
472
|
}
|
|
@@ -399,6 +399,10 @@ static NSDictionary *convertFollyDynamicToNSDictionary(const folly::dynamic &dyn
|
|
|
399
399
|
[_view setReactCompassPosition:compassPosition];
|
|
400
400
|
}
|
|
401
401
|
|
|
402
|
+
if (oldViewProps.compassHiddenFacingNorth != newViewProps.compassHiddenFacingNorth) {
|
|
403
|
+
[_view setReactCompassHiddenFacingNorth:newViewProps.compassHiddenFacingNorth];
|
|
404
|
+
}
|
|
405
|
+
|
|
402
406
|
[super updateProps:props oldProps:oldProps];
|
|
403
407
|
}
|
|
404
408
|
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
#import "MLRNModule.h"
|
|
2
2
|
#import "MLRNCustomHeaders.h"
|
|
3
3
|
#import "MLRNEventTypes.h"
|
|
4
|
-
#import "MLRNOfflineModule.h"
|
|
5
4
|
#import "MLRNSource.h"
|
|
6
5
|
@import MapLibre;
|
|
7
6
|
|
|
@@ -27,22 +26,10 @@ RCT_EXPORT_MODULE();
|
|
|
27
26
|
NSMutableDictionary *styleSourceConsts = [[NSMutableDictionary alloc] init];
|
|
28
27
|
[styleSourceConsts setObject:DEFAULT_SOURCE_ID forKey:@"DefaultSourceID"];
|
|
29
28
|
|
|
30
|
-
// offline module callback names
|
|
31
|
-
NSMutableDictionary *offlineModuleCallbackNames = [[NSMutableDictionary alloc] init];
|
|
32
|
-
[offlineModuleCallbackNames setObject:RCT_MLRN_OFFLINE_CALLBACK_ERROR forKey:@"Error"];
|
|
33
|
-
[offlineModuleCallbackNames setObject:RCT_MLRN_OFFLINE_CALLBACK_PROGRESS forKey:@"Progress"];
|
|
34
|
-
|
|
35
|
-
NSMutableDictionary *offlinePackDownloadState = [[NSMutableDictionary alloc] init];
|
|
36
|
-
[offlinePackDownloadState setObject:@(MLNOfflinePackStateInactive) forKey:@"Inactive"];
|
|
37
|
-
[offlinePackDownloadState setObject:@(MLNOfflinePackStateActive) forKey:@"Active"];
|
|
38
|
-
[offlinePackDownloadState setObject:@(MLNOfflinePackStateComplete) forKey:@"Complete"];
|
|
39
|
-
|
|
40
29
|
return @{
|
|
41
30
|
@"StyleURL" : styleURLS,
|
|
42
31
|
@"EventTypes" : eventTypes,
|
|
43
32
|
@"StyleSource" : styleSourceConsts,
|
|
44
|
-
@"OfflineCallbackName" : offlineModuleCallbackNames,
|
|
45
|
-
@"OfflinePackDownloadState" : offlinePackDownloadState,
|
|
46
33
|
};
|
|
47
34
|
}
|
|
48
35
|
|
|
@@ -1,11 +1,8 @@
|
|
|
1
|
-
#import <
|
|
2
|
-
#import <React/RCTEventEmitter.h>
|
|
1
|
+
#import <MapLibreReactNativeSpec/MapLibreReactNativeSpec.h>
|
|
3
2
|
|
|
4
|
-
|
|
3
|
+
#import <React/RCTInitializing.h>
|
|
5
4
|
|
|
6
|
-
@interface MLRNOfflineModule
|
|
7
|
-
|
|
8
|
-
extern NSString *const RCT_MLRN_OFFLINE_CALLBACK_PROGRESS;
|
|
9
|
-
extern NSString *const RCT_MLRN_OFFLINE_CALLBACK_ERROR;
|
|
5
|
+
@interface MLRNOfflineModule
|
|
6
|
+
: NativeOfflineModuleSpecBase <NativeOfflineModuleSpec, RCTInitializing>
|
|
10
7
|
|
|
11
8
|
@end
|