@rnmapbox/maps 10.0.0-rc.1 → 10.0.0-rc.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/README.md +2 -2
  2. package/android/rctmgl/build.gradle +1 -1
  3. package/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/AbstractEventEmitter.kt +75 -0
  4. package/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/annotation/RCTMGLMarkerViewManager.kt +1 -1
  5. package/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/camera/RCTMGLCamera.kt +92 -9
  6. package/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/images/RCTMGLImagesManager.kt +2 -2
  7. package/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/location/LocationComponentManager.kt +3 -2
  8. package/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/mapview/RCTMGLAndroidTextureMapViewManager.kt +23 -0
  9. package/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/mapview/RCTMGLMapView.kt +86 -17
  10. package/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/mapview/RCTMGLMapViewManager.kt +24 -8
  11. package/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/sources/RCTMGLRasterSourceManager.kt +1 -1
  12. package/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/sources/RCTMGLTileSourceManager.kt +1 -1
  13. package/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/sources/RCTMGLVectorSourceManager.kt +1 -1
  14. package/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/events/AbstractEvent.kt +49 -0
  15. package/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/events/IEvent.kt +17 -0
  16. package/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/events/LocationEvent.kt +11 -16
  17. package/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/events/MapUserTrackingModeEvent.kt +10 -10
  18. package/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/events/constants/EventTypes.kt +44 -0
  19. package/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/modules/RCTMGLLocationModule.kt +36 -1
  20. package/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/modules/RCTMGLModule.kt +4 -3
  21. package/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/modules/RCTMGLOfflineModule.kt +464 -428
  22. package/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/utils/extensions/FeatureCollection.kt +10 -0
  23. package/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/utils/extensions/Geometry.kt +22 -0
  24. package/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/utils/extensions/JSONObject.kt +78 -0
  25. package/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/utils/extensions/ReadableArray.kt +1 -1
  26. package/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/utils/extensions/Value.kt +9 -0
  27. package/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/utils/writeableMapArrayOf.kt +41 -0
  28. package/ios/RCTMGL-v10/RCTMGLCamera.swift +1 -6
  29. package/ios/RCTMGL-v10/RCTMGLEvent.swift +4 -5
  30. package/ios/RCTMGL-v10/RCTMGLLocationModule.m +2 -2
  31. package/ios/RCTMGL-v10/RCTMGLOfflineModule.swift +299 -312
  32. package/ios/install.md +7 -0
  33. package/lib/commonjs/components/MapView.js +12 -2
  34. package/lib/commonjs/components/MapView.js.map +1 -1
  35. package/lib/commonjs/components/NativeUserLocation.js.map +1 -1
  36. package/lib/commonjs/components/Terrain.js +1 -2
  37. package/lib/commonjs/components/Terrain.js.map +1 -1
  38. package/lib/commonjs/components/VectorSource.js +2 -0
  39. package/lib/commonjs/components/VectorSource.js.map +1 -1
  40. package/lib/commonjs/modules/location/locationManager.js +4 -0
  41. package/lib/commonjs/modules/location/locationManager.js.map +1 -1
  42. package/lib/module/components/MapView.js +12 -2
  43. package/lib/module/components/MapView.js.map +1 -1
  44. package/lib/module/components/NativeUserLocation.js.map +1 -1
  45. package/lib/module/components/Terrain.js +1 -2
  46. package/lib/module/components/Terrain.js.map +1 -1
  47. package/lib/module/components/VectorSource.js +3 -0
  48. package/lib/module/components/VectorSource.js.map +1 -1
  49. package/lib/module/modules/location/locationManager.js +4 -0
  50. package/lib/module/modules/location/locationManager.js.map +1 -1
  51. package/lib/typescript/components/MapView.d.ts +6 -0
  52. package/lib/typescript/components/MapView.d.ts.map +1 -1
  53. package/lib/typescript/components/NativeUserLocation.d.ts.map +1 -1
  54. package/lib/typescript/components/Terrain.d.ts.map +1 -1
  55. package/package.json +1 -1
  56. package/plugin/install.md +17 -0
  57. package/rnmapbox-maps.podspec +1 -1
  58. package/src/components/MapView.tsx +10 -2
  59. package/src/components/NativeUserLocation.tsx +5 -3
  60. package/src/components/Terrain.tsx +3 -5
  61. package/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/AbstractEventEmitter.java +0 -82
  62. package/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/mapview/RCTMGLAndroidTextureMapView.java +0 -16
  63. package/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/mapview/RCTMGLAndroidTextureMapViewManager.java +0 -31
  64. package/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/events/AbstractEvent.java +0 -62
  65. package/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/events/IEvent.java +0 -18
  66. package/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/events/constants/EventTypes.java +0 -51
@@ -98,9 +98,9 @@ class RCTMGLOfflineModule: RCTEventEmitter {
98
98
  var cancelable: Cancelable? = nil
99
99
  var progress : TileRegionLoadProgress? = nil
100
100
  var state : State = .inactive
101
- var metadata : [String:Any]? = nil
101
+ var metadata : [String:Any]
102
102
 
103
- // Stored in metadata for resume functionality:
103
+ // Stored in metadata for resume functionality:
104
104
  var bounds: Geometry? = nil
105
105
  var zoomRange: ClosedRange<UInt8>? = nil
106
106
  var styleURI: StyleURI? = nil
@@ -133,7 +133,7 @@ class RCTMGLOfflineModule: RCTEventEmitter {
133
133
  @objc
134
134
  override
135
135
  static func requiresMainQueueSetup() -> Bool {
136
- return true
136
+ return true
137
137
  }
138
138
 
139
139
  @objc
@@ -141,56 +141,251 @@ class RCTMGLOfflineModule: RCTEventEmitter {
141
141
  func constantsToExport() -> [AnyHashable: Any]! {
142
142
  return [:]
143
143
  }
144
-
145
-
144
+
146
145
  @objc
147
146
  override
148
147
  func supportedEvents() -> [String] {
149
148
  return [Callbacks.error.rawValue, Callbacks.progress.rawValue]
150
149
  }
151
150
 
152
- func convertRegionToJSON(region: TileRegion, geometry: Geometry, metadata: [String:Any]?) -> [String:Any] {
153
- let bb = RCTMGLFeatureUtils.boundingBox(geometry: geometry)
151
+ // MARK: react methods
152
+
153
+ @objc
154
+ func createPack(_ options: NSDictionary, resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock) {
155
+ DispatchQueue.main.async {
156
+ do {
157
+ let metadataStr = options["metadata"] as! String
158
+ var metadata = try JSONSerialization.jsonObject(with: metadataStr.data(using: .utf8)!, options: []) as! [String:Any]
159
+ metadata["styleURI"] = options["styleURL"]
160
+ let id = metadata["name"] as! String
161
+
162
+ let boundsStr = options["bounds"] as! String
163
+ let boundsData = boundsStr.data(using: .utf8)
164
+ var boundsFC = try JSONDecoder().decode(FeatureCollection.self, from: boundsData!)
165
+
166
+ var bounds = self.convertPointPairToBounds(RCTMGLFeatureUtils.fcToGeomtry(boundsFC))
167
+
168
+ let actPack = RCTMGLOfflineModule.TileRegionPack(
169
+ name: id,
170
+ styleURI: StyleURI(rawValue: options["styleURL"] as! String)!,
171
+ bounds: bounds,
172
+ zoomRange: (options["minZoom"] as! NSNumber).uint8Value...(options["maxZoom"] as! NSNumber).uint8Value,
173
+ metadata: metadata
174
+ )
175
+ self.tileRegionPacks[id] = actPack
176
+ self.startLoading(pack: actPack)
177
+
178
+ resolver([
179
+ "bounds": boundsStr,
180
+ "metadata": String(data:try! JSONSerialization.data(withJSONObject: metadata, options: [.prettyPrinted]), encoding: .utf8)
181
+ ])
182
+ } catch {
183
+ rejecter("createPack", error.localizedDescription, error)
184
+ }
185
+ }
186
+ }
187
+
188
+ @objc
189
+ func getPackStatus(_ name: String,
190
+ resolver: @escaping RCTPromiseResolveBlock,
191
+ rejecter: @escaping RCTPromiseRejectBlock) {
192
+ guard let pack = tileRegionPacks[name] else {
193
+ rejecter("RCTMGLOfflineModule.getPackStatus", "pack \(name) not found", nil)
194
+ return
195
+ }
154
196
 
155
- var result : [String:Any] = [:]
156
- if let bb = bb {
157
- let jsonBounds = [
158
- bb.northEast.longitude, bb.northEast.latitude,
159
- bb.southWest.longitude, bb.southWest.latitude
160
- ]
161
-
162
- let completed = (region.completedResourceCount == region.requiredResourceCount)
163
-
164
- result["requiredResourceCount"] = region.requiredResourceCount
165
- result["completedResourceCount"] = region.completedResourceCount
166
- result["completedResourceSize"] = region.completedResourceSize
167
- result["state"] = completed ? State.complete.rawValue : State.unknown.rawValue
168
-
169
- var metadata : [String:Any] = metadata ?? [:]
170
- metadata["name"] = region.id
171
-
172
- if region.requiredResourceCount > 0 {
173
- let percentage = Float(100.0) * Float(region.completedResourceCount) / Float(region.requiredResourceCount)
174
- result["percentage"] = percentage
197
+ tileStore.tileRegionMetadata(forId: name) { result in
198
+ switch result {
199
+ case .success(let metadata):
200
+ var pack = TileRegionPack(
201
+ name: name,
202
+ metadata: logged("RCTMGLOfflineModule.getPackStatus") { metadata as? [String:Any] } ?? [:]
203
+ )
204
+ self.tileRegionPacks[name] = pack
205
+ resolver(self._makeRegionStatusPayload(pack: pack))
206
+ case .failure(let error):
207
+ Logger.log(level:.error, message: "Unable to fetch metadata for \(name)")
208
+ rejecter("RCTMGLOfflineModule.getPackStatus", error.localizedDescription, error)
209
+ }
210
+ }
211
+ }
212
+
213
+ @objc
214
+ func resumePackDownload(_ name: String, resolver: RCTPromiseResolveBlock, rejecter: RCTPromiseRejectBlock)
215
+ {
216
+ if let pack = tileRegionPacks[name] {
217
+ startLoading(pack: pack)
218
+ resolver(nil)
219
+ } else {
220
+ rejecter("resumePackDownload", "Unknown offline pack: \(name)", nil)
221
+ }
222
+ }
223
+
224
+ @objc
225
+ func pausePackDownload(_ name: String, resolver: RCTPromiseResolveBlock, rejecter: RCTPromiseRejectBlock)
226
+ {
227
+ if let pack = tileRegionPacks[name] {
228
+ if let cancelable = pack.cancelable {
229
+ cancelable.cancel()
230
+ tileRegionPacks[name]?.cancelable = nil
231
+ resolver(nil)
175
232
  } else {
176
- result["percentage"] = nil
233
+ rejecter("pausePackDownload", "Offline pack: \(name) already cancelled", nil)
177
234
  }
178
- if let expires = region.expires {
179
- result["expires"] = expires.toJSONString()
235
+ } else {
236
+ rejecter("pausePackDownload", "Unknown offline region: \(name)", nil)
237
+ }
238
+ }
239
+
240
+ @objc
241
+ func setTileCountLimit(_ limit: NSNumber) {
242
+ self.offlineRegionManager.setOfflineMapboxTileCountLimitForLimit(limit.uint64Value)
243
+ }
244
+
245
+
246
+ @objc
247
+ func deletePack(_ name: String,
248
+ resolver: RCTPromiseResolveBlock,
249
+ rejecter: RCTPromiseRejectBlock)
250
+ {
251
+ guard let pack = tileRegionPacks[name] else {
252
+ return resolver(nil)
253
+ }
254
+
255
+ guard pack.state != .invalid else {
256
+ return rejecter("deletePack", "Pack: \(name) has already been deleted", nil)
257
+ }
258
+
259
+ tileStore.removeTileRegion(forId: name)
260
+ tileRegionPacks[name]!.state = .invalid
261
+ resolver(nil)
262
+ }
263
+
264
+ @objc
265
+ func migrateOfflineCache(_ resolve : @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
266
+ // Old and new cache file paths
267
+ let srcURL = URL(fileURLWithPath: NSHomeDirectory()).appendingPathComponent("/Library/Application Support/com.mapbox.examples/.mapbox/cache.db")
268
+
269
+ let destURL = URL(fileURLWithPath: NSHomeDirectory()).appendingPathComponent("/Library/Application Support/.mapbox/map_data/map_data.db")
270
+
271
+ let fileManager = FileManager.default
272
+
273
+ do {
274
+ try fileManager.createDirectory(at: destURL.deletingLastPathComponent(), withIntermediateDirectories: true, attributes: nil)
275
+ try fileManager.moveItem(at: srcURL, to: destURL)
276
+ resolve(nil)
277
+ } catch {
278
+ reject("migrateOfflineCache", error.localizedDescription, error)
279
+ }
280
+ }
281
+
282
+ @objc
283
+ func resetDatabase(_ resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
284
+ self.tileStore.allTileRegions { result in
285
+ switch result {
286
+ case .success(let regions):
287
+ regions.forEach { region in
288
+ self.tileStore.removeTileRegion(forId: region.id)
289
+ }
290
+ self.offlineManager.allStylePacks { result in
291
+ switch result {
292
+ case .success(let packs):
293
+ packs.forEach { pack in
294
+ if let url = logged("RCTMGLOfflineModule.resetDatabase invalid styleURI",fn: { return URL(string: pack.styleURI) }),
295
+ let styleUri = logged("RCTMGLOfflineModule.resetDatabase invalid styleURI2", fn: { return StyleURI(url: url) }) {
296
+ self.offlineManager.removeStylePack(for: styleUri)
297
+ }
298
+ }
299
+ resolve(nil)
300
+ case .failure(let error):
301
+ Logger.log(level:.error, message: "RCTMGLOfflineModule.resetDatabase/allStylePacks \(error.localizedDescription) \(error)")
302
+ reject("RCTMGLOfflineModule.resetDatabase/allStylePacks", error.localizedDescription, error)
303
+ }
304
+ }
305
+ case .failure(let error):
306
+ Logger.log(level:.error, message: "RCTMGLOfflineModule.resetDatabase/allTileRegions \(error.localizedDescription) \(error)")
307
+ reject("RCTMGLOfflineModule.resetDatabase/allTileRegions", error.localizedDescription, error)
180
308
  }
181
-
182
- result["metadata"] = String(data:try! JSONSerialization.data(withJSONObject: metadata, options: [.prettyPrinted]), encoding: .utf8)
183
-
184
- result["bounds"] = jsonBounds
185
309
  }
186
- return result
187
310
  }
188
311
 
189
- func toProgress(region: TileRegion) -> TileRegionLoadProgress? {
190
- return TileRegionLoadProgress(completedResourceCount: region.completedResourceCount, completedResourceSize: region.completedResourceSize, erroredResourceCount: 0, requiredResourceCount: region.requiredResourceCount, loadedResourceCount: 0, loadedResourceSize: 0)
312
+ @objc
313
+ func getPacks(_ resolve : @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock) {
314
+ DispatchQueue.main.async {
315
+ self.tileStore.allTileRegions { result in
316
+ switch result {
317
+ case .success(let regions):
318
+ self.convertRegionsToJSON(regions: regions, resolve: resolve, rejecter: rejecter)
319
+ case .failure(let error):
320
+ rejecter("TileStoreError", error.localizedDescription, error)
321
+ }
322
+ }
323
+ }
191
324
  }
192
325
 
193
- func convertRegionToJson(regions: [TileRegion], resolve: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock) {
326
+ func startLoading(pack: TileRegionPack) {
327
+ let id = pack.name
328
+ let metadata = pack.metadata
329
+ guard let bounds = pack.bounds else {
330
+ RCTMGLLogError("RCTMGLOfflineModule.startLoading failed as there are no bounds in pack")
331
+ return
332
+ }
333
+ guard let zoomRange = pack.zoomRange else {
334
+ RCTMGLLogError("RCTMGLOfflineModule.startLoading failed as there is no zoom range in pack")
335
+ return
336
+ }
337
+ guard let styleURI = pack.styleURI else {
338
+ RCTMGLLogError("RCTMGLOfflineModule.startLoading failed as there is no styleURI in pack")
339
+ return
340
+ }
341
+
342
+ let stylePackLoadOptions = StylePackLoadOptions(glyphsRasterizationMode: .ideographsRasterizedLocally, metadata: pack.metadata)
343
+
344
+ let descriptorOptions = TilesetDescriptorOptions(
345
+ styleURI: styleURI,
346
+ zoomRange: zoomRange,
347
+ stylePackOptions: stylePackLoadOptions
348
+ )
349
+ let tilesetDescriptor = self.offlineManager.createTilesetDescriptor(for: descriptorOptions)
350
+
351
+ let loadOptions = TileRegionLoadOptions(
352
+ geometry: bounds, // RCTMGLFeatureUtils.geometryToGeometry(bounds),
353
+ descriptors: [tilesetDescriptor],
354
+ metadata: metadata,
355
+ acceptExpired: true,
356
+ networkRestriction: .none,
357
+ averageBytesPerSecond: nil)
358
+
359
+ var lastProgress : TileRegionLoadProgress? = nil
360
+ let task = self.tileStore.loadTileRegion(forId: id, loadOptions: loadOptions!, progress: {
361
+ progress in
362
+ lastProgress = progress
363
+ self.tileRegionPacks[id]!.progress = progress
364
+ self.tileRegionPacks[id]!.state = .active
365
+ self.offlinePackProgressDidChange(progress: progress, metadata: metadata, state: .active)
366
+ }) { result in
367
+ switch result {
368
+ case .success(let _):
369
+ DispatchQueue.main.async {
370
+ if let progess = lastProgress {
371
+ self.offlinePackProgressDidChange(progress: progess, metadata: metadata, state: .complete)
372
+ } else {
373
+ Logger.log(level: .warn,
374
+ message: "RCTMGLOfflineModule: startLoading: tile region completed, but got no progress information")
375
+ }
376
+ self.tileRegionPacks[id]!.state = .complete
377
+ }
378
+ case .failure(let error):
379
+ DispatchQueue.main.async {
380
+ self.tileRegionPacks[id]!.state = .inactive
381
+ self.offlinePackDidReceiveError(name: id, error: error)
382
+ }
383
+ }
384
+ }
385
+ self.tileRegionPacks[id]!.cancelable = task
386
+ }
387
+
388
+ func convertRegionsToJSON(regions: [TileRegion], resolve: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock) {
194
389
  let taskGroup = DispatchGroup()
195
390
 
196
391
  var geomteryResults : [String: (Result<Geometry,Error>,TileRegion)] = [:]
@@ -219,21 +414,21 @@ class RCTMGLOfflineModule: RCTEventEmitter {
219
414
  return false
220
415
  }
221
416
  }
222
-
417
+
223
418
  if let firstError = firstError {
224
419
  switch firstError.value.0 {
225
420
  case .failure(let error):
226
- rejecter("Error", error.localizedDescription, error)
421
+ rejecter("convertRegionsToJSON", error.localizedDescription, error)
227
422
  return
228
423
  case .success:
229
- fatalError("Expected failure but was success")
424
+ fatalError("convertRegionsToJson:Expected failure but was success")
230
425
  }
231
426
  }
232
-
427
+
233
428
  let results = geomteryResults.map { (id, result) -> (String, (Geometry,TileRegion, [String:Any]?)) in
234
429
  switch result.0 {
235
430
  case .failure(_):
236
- fatalError("Expected failuer but was success")
431
+ fatalError("convertRegionsToJson:Expected success but was failure")
237
432
  case .success(let geometry):
238
433
  return (id, (geometry,result.1,(try? metadataResults[id]?.get()) as? [String:Any]))
239
434
  }
@@ -248,60 +443,58 @@ class RCTMGLOfflineModule: RCTEventEmitter {
248
443
  progress: self.toProgress(region: region),
249
444
  metadata: logged("RCTMGLOfflineModule.getPacks metadata is null") { metadata } ?? [:]
250
445
  )
251
-
252
- if ((region.completedResourceCount == region.completedResourceSize)) {
446
+
447
+ if ((region.hasCompleted())) {
253
448
  pack.state = .complete
254
449
  }
255
-
450
+
256
451
  self.tileRegionPacks[region.id] = pack
257
-
452
+
258
453
  return ret
259
454
  })
260
455
  }
261
456
  }
262
457
 
263
- @objc
264
- func getPacks(_ resolve : @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock) {
265
- DispatchQueue.main.async {
266
- self.tileStore.allTileRegions { result in
267
- switch result {
268
- case .success(let regions):
269
- self.convertRegionToJson(regions: regions, resolve: resolve, rejecter: rejecter)
270
- // self.convertRegionToJson(regions: regions, resolve: resolve)
271
- // resolve(self.convertRegionToJson(regions: regions))
272
- case .failure(let error):
273
- rejecter("TileStoreError", error.localizedDescription, error)
274
- }
458
+ func convertRegionToJSON(region: TileRegion, geometry: Geometry, metadata: [String:Any]?) -> [String:Any] {
459
+ let bb = RCTMGLFeatureUtils.boundingBox(geometry: geometry)
460
+
461
+ if let bb = bb {
462
+ let jsonBounds = [
463
+ bb.northEast.longitude, bb.northEast.latitude,
464
+ bb.southWest.longitude, bb.southWest.latitude
465
+ ]
466
+
467
+ let completed = (region.completedResourceCount == region.requiredResourceCount)
468
+
469
+ var metadata : [String:Any] = metadata ?? [:]
470
+ metadata["name"] = region.id
471
+
472
+ var result : [String:Any] = [
473
+ "requiredResourceCount": region.requiredResourceCount,
474
+ "completedResourceCount": region.completedResourceCount,
475
+ "completedResourceSize": region.completedResourceSize,
476
+ "state": completed ? State.complete.rawValue : State.unknown.rawValue,
477
+ "metadata": String(data:try! JSONSerialization.data(withJSONObject: metadata, options: [.prettyPrinted]), encoding: .utf8),
478
+ "bounds": jsonBounds
479
+ ]
480
+
481
+ if region.requiredResourceCount > 0 {
482
+ result["percentage"] = region.toPercentage()
483
+ } else {
484
+ result["percentage"] = nil
485
+ }
486
+ if let expires = region.expires {
487
+ result["expires"] = expires.toJSONString()
275
488
  }
276
489
 
277
- /*
278
- self.offlineManager.allStylePacks { (result) in
279
- switch result {
280
- case .success(let packs):
281
- resolve(self.convertPacksToJson(packs: packs))
282
- case .failure(let error):
283
- rejecter(error.localizedDescription, error.localizedDescription, error)
284
- }
285
- }*/
286
490
  }
491
+ return [:]
492
+ }
287
493
 
288
-
289
-
290
- // dispatch_async(dispatch_get_main_queue(), ^{
291
- /*
292
- NSArray<MGLOfflinePack *> *packs = [[MGLOfflineStorage sharedOfflineStorage] packs];
293
-
294
- if (packs == nil) {
295
- // packs have not loaded yet
296
- [self->packRequestQueue addObject:resolve];
297
- return;
298
- }
299
-
300
- resolve([self _convertPacksToJson:packs]);
301
- });*/
494
+ func toProgress(region: TileRegion) -> TileRegionLoadProgress? {
495
+ return TileRegionLoadProgress(completedResourceCount: region.completedResourceCount, completedResourceSize: region.completedResourceSize, erroredResourceCount: 0, requiredResourceCount: region.requiredResourceCount, loadedResourceCount: 0, loadedResourceSize: 0)
302
496
  }
303
497
 
304
-
305
498
  func convertPointPairToBounds(_ bounds: Geometry) -> Geometry {
306
499
  guard case .geometryCollection(let gc) = bounds else {
307
500
  return bounds
@@ -320,10 +513,10 @@ class RCTMGLOfflineModule: RCTEventEmitter {
320
513
  let pt1 = g1.coordinates
321
514
  return .polygon(Polygon([
322
515
  [
323
- pt0,
324
- CLLocationCoordinate2D(latitude: pt0.latitude, longitude: pt1.longitude),
325
- pt1,
326
- CLLocationCoordinate2D(latitude: pt1.latitude, longitude: pt0.longitude)
516
+ pt0,
517
+ CLLocationCoordinate2D(latitude: pt0.latitude, longitude: pt1.longitude),
518
+ pt1,
519
+ CLLocationCoordinate2D(latitude: pt1.latitude, longitude: pt0.longitude)
327
520
  ]
328
521
  ]))
329
522
  }
@@ -338,12 +531,10 @@ class RCTMGLOfflineModule: RCTEventEmitter {
338
531
  func _makeRegionStatusPayload(_ name:String, progress: TileRegionLoadProgress?, state: State, metadata:[String:Any]?) -> [String:Any?] {
339
532
  var result : [String:Any?] = [:]
340
533
  if let progress = progress {
341
- let progressPercentage = Float(progress.completedResourceCount) / Float(progress.requiredResourceCount)
342
-
343
534
  result = [
344
- "state": (progress.completedResourceCount == progress.requiredResourceCount) ? State.complete.rawValue : state.rawValue,
535
+ "state": (progress.hasCompleted()) ? State.complete.rawValue : state.rawValue,
345
536
  "name": name,
346
- "percentage": progressPercentage * 100.0,
537
+ "percentage": progress.toPercentage(),
347
538
  "completedResourceCount": progress.completedResourceCount,
348
539
  "completedResourceSize": progress.completedResourceSize,
349
540
  "erroredResourceCount": progress.erroredResourceCount,
@@ -383,228 +574,7 @@ class RCTMGLOfflineModule: RCTEventEmitter {
383
574
  let event = RCTMGLEvent(type: .offlineError, payload: ["name": name, "message": error.localizedDescription])
384
575
  self._sendEvent(Callbacks.error.rawValue, event: event)
385
576
  }
386
-
387
- @objc
388
- func createPack(_ options: NSDictionary, resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock) {
389
- DispatchQueue.main.async {
390
- do {
391
- let metadataStr = options["metadata"] as! String
392
- var metadata = try JSONSerialization.jsonObject(with: metadataStr.data(using: .utf8)!, options: []) as! [String:Any]
393
- metadata["styleURI"] = options["styleURL"]
394
- let id = metadata["name"] as! String
395
-
396
- let boundsStr = options["bounds"] as! String
397
- let boundsData = boundsStr.data(using: .utf8)
398
- var boundsFC = try JSONDecoder().decode(FeatureCollection.self, from: boundsData!)
399
-
400
- var bounds = self.convertPointPairToBounds(RCTMGLFeatureUtils.fcToGeomtry(boundsFC))
401
-
402
- let actPack = RCTMGLOfflineModule.TileRegionPack(
403
- name: id,
404
- styleURI: StyleURI(rawValue: options["styleURL"] as! String)!,
405
- bounds: bounds,
406
- zoomRange: (options["minZoom"] as! NSNumber).uint8Value...(options["maxZoom"] as! NSNumber).uint8Value,
407
- metadata: metadata
408
- )
409
- self.tileRegionPacks[id] = actPack
410
- self.startLoading(pack: actPack)
411
-
412
- resolver([
413
- "bounds": boundsStr,
414
- "metadata": String(data:try! JSONSerialization.data(withJSONObject: metadata, options: [.prettyPrinted]), encoding: .utf8)
415
- ])
416
- } catch {
417
- rejecter("createPack", error.localizedDescription, error)
418
- }
419
- }
420
- }
421
-
422
- func startLoading(pack: TileRegionPack) {
423
- let id = pack.name
424
- guard let bounds = pack.bounds else {
425
- RCTMGLLogError("RCTMGLOfflineModule.startLoading failed as there are no bounds in pack")
426
- return
427
- }
428
- guard let zoomRange = pack.zoomRange else {
429
- RCTMGLLogError("RCTMGLOfflineModule.startLoading failed as there is no zoom range in pack")
430
- return
431
- }
432
- guard let styleURI = pack.styleURI else {
433
- RCTMGLLogError("RCTMGLOfflineModule.startLoading failed as there is no styleURI in pack")
434
- return
435
- }
436
- guard let metadata = pack.metadata else {
437
- RCTMGLLogError("RCTMGLOfflineModule.startLoading failed as there is no metadata in pack")
438
- return
439
- }
440
-
441
- let stylePackLoadOptions = StylePackLoadOptions(glyphsRasterizationMode: .ideographsRasterizedLocally, metadata: pack.metadata)
442
-
443
- let descriptorOptions = TilesetDescriptorOptions(
444
- styleURI: styleURI,
445
- zoomRange: zoomRange,
446
- stylePackOptions: stylePackLoadOptions
447
- )
448
- let tilesetDescriptor = self.offlineManager.createTilesetDescriptor(for: descriptorOptions)
449
-
450
- let loadOptions = TileRegionLoadOptions(
451
- geometry: bounds, // RCTMGLFeatureUtils.geometryToGeometry(bounds),
452
- descriptors: [tilesetDescriptor],
453
- metadata: metadata,
454
- acceptExpired: true,
455
- networkRestriction: .none,
456
- averageBytesPerSecond: nil)
457
-
458
- var lastProgress : TileRegionLoadProgress? = nil
459
- let task = self.tileStore.loadTileRegion(forId: id, loadOptions: loadOptions!, progress: {
460
- progress in
461
- lastProgress = progress
462
- self.tileRegionPacks[id]!.progress = progress
463
- self.tileRegionPacks[id]!.state = .active
464
- self.offlinePackProgressDidChange(progress: progress, metadata: metadata, state: .active)
465
- }) { result in
466
- switch result {
467
- case .success(let value):
468
- DispatchQueue.main.async {
469
- if let progess = lastProgress {
470
- self.offlinePackProgressDidChange(progress: progess, metadata: metadata, state: .complete)
471
- }
472
- self.tileRegionPacks[id]!.state = .complete
473
- }
474
- case .failure(let error):
475
- DispatchQueue.main.async {
476
- self.tileRegionPacks[id]!.state = .inactive
477
- self.offlinePackDidReceiveError(name: id, error: error)
478
- }
479
- }
480
- }
481
- self.tileRegionPacks[id]!.cancelable = task
482
- }
483
-
484
- func _getPack(fromName: String) -> TileRegionPack? {
485
- return self.tileRegionPacks[fromName]
486
- }
487
-
488
- @objc
489
- func getPackStatus(_ name: String,
490
- resolver: @escaping RCTPromiseResolveBlock,
491
- rejecter: @escaping RCTPromiseRejectBlock) {
492
- guard let pack = self._getPack(fromName: name) else {
493
- resolver(nil)
494
- return
495
- }
496
-
497
- tileStore.tileRegionMetadata(forId: name) { result in
498
- switch result {
499
- case .failure(let error):
500
- Logger.log(level:.error, message: "Unable to fetch metadata for \(name)")
501
- rejecter("RCTMGLOfflineModule.getPackStatus", error.localizedDescription, error)
502
- case .success(let metadata):
503
- var pack = self.tileRegionPacks[name] ?? TileRegionPack(
504
- name: name,
505
- metadata: logged("RCTMGLOfflineModule.getPackStatus") { metadata as? [String:Any] } ?? [:]
506
- )
507
- self.tileRegionPacks[name] = pack
508
- resolver(self._makeRegionStatusPayload(pack: pack))
509
- }
510
- }
511
- }
512
-
513
-
514
- @objc
515
- func resumePackDownload(_ name: String, resolver: RCTPromiseResolveBlock, rejecter: RCTPromiseRejectBlock)
516
- {
517
- if let pack = _getPack(fromName: name) {
518
- self.startLoading(pack: pack)
519
- }
520
- }
521
-
522
- @objc
523
- func pausePackDownload(_ name: String, resolver: RCTPromiseResolveBlock, rejecter: RCTPromiseRejectBlock)
524
- {
525
- if let pack = _getPack(fromName: name) {
526
- pack.cancelable?.cancel()
527
- resolver(nil)
528
- } else {
529
- rejecter("pausePackDownload", "Unknown offline region: \(name)", nil)
530
- }
531
- }
532
-
533
- @objc
534
- func setTileCountLimit(_ limit: NSNumber) {
535
- self.offlineRegionManager.setOfflineMapboxTileCountLimitForLimit(limit.uint64Value)
536
- }
537
-
538
-
539
- @objc
540
- func deletePack(_ name: String,
541
- resolver: RCTPromiseResolveBlock,
542
- rejecter: RCTPromiseRejectBlock)
543
- {
544
- guard let pack = _getPack(fromName: name) else {
545
- return resolver(nil)
546
- }
547
-
548
- guard pack.state != .invalid else {
549
- let error = NSError(domain:"RCTMGLErororDomain", code: 1, userInfo: [NSLocalizedDescriptionKey: "Pack has already beend deleted"])
550
- return rejecter("deletePack", error.description, error)
551
- }
552
-
553
- self.tileStore.removeTileRegion(forId: name)
554
- self.tileRegionPacks[name]!.state = .invalid
555
- resolver(nil)
556
- }
557
-
558
- @objc
559
- func migrateOfflineCache(_ resolve : @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
560
- // Old and new cache file paths
561
- let srcURL = URL(fileURLWithPath: NSHomeDirectory()).appendingPathComponent("/Library/Application Support/com.mapbox.examples/.mapbox/cache.db")
562
-
563
- let destURL = URL(fileURLWithPath: NSHomeDirectory()).appendingPathComponent("/Library/Application Support/.mapbox/map_data/map_data.db")
564
-
565
- let fileManager = FileManager.default
566
-
567
- do {
568
- try fileManager.createDirectory(at: destURL.deletingLastPathComponent(), withIntermediateDirectories: true, attributes: nil)
569
- try fileManager.moveItem(at: srcURL, to: destURL)
570
- resolve(nil)
571
- } catch {
572
- reject("migrateOfflineCache", error.localizedDescription, error)
573
- }
574
- }
575
-
576
- @objc
577
- func resetDatabase(_ resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
578
- self.tileStore.allTileRegions { result in
579
- switch result {
580
- case .success(let regions):
581
- regions.forEach { region in
582
- self.tileStore.removeTileRegion(forId: region.id)
583
- }
584
- self.offlineManager.allStylePacks { result in
585
- switch result {
586
- case .success(let packs):
587
- packs.forEach { pack in
588
- if let url = logged("RCTMGLOfflineModule.resetDatabase invalid styleURI",fn: { return URL(string: pack.styleURI) }),
589
- let styleUri = logged("RCTMGLOfflineModule.resetDatabase invalid styleURI2", fn: { return StyleURI(url: url) }) {
590
- self.offlineManager.removeStylePack(for: styleUri)
591
- }
592
- }
593
- resolve(nil)
594
- case .failure(let error):
595
- Logger.log(level:.error, message: "RCTMGLOfflineModule.resetDatabase/allStylePacks \(error.localizedDescription) \(error)")
596
- reject("RCTMGLOfflineModule.resetDatabase/allStylePacks", error.localizedDescription, error)
597
- }
598
- }
599
- case .failure(let error):
600
- Logger.log(level:.error, message: "RCTMGLOfflineModule.resetDatabase/allTileRegions \(error.localizedDescription) \(error)")
601
- reject("RCTMGLOfflineModule.resetDatabase/allTileRegions", error.localizedDescription, error)
602
- }
603
-
604
- }
605
- }
606
577
  }
607
-
608
578
  // MARK: progress throttle
609
579
 
610
580
  extension RCTMGLOfflineModule {
@@ -639,3 +609,20 @@ extension RCTMGLOfflineModule {
639
609
  }
640
610
  }
641
611
 
612
+ extension TileRegionLoadProgress {
613
+ func toPercentage() -> Float {
614
+ return Float(100.0) * Float(completedResourceCount) / Float(requiredResourceCount);
615
+ }
616
+ func hasCompleted() -> Bool {
617
+ return (completedResourceCount == requiredResourceCount)
618
+ }
619
+ }
620
+
621
+ extension TileRegion {
622
+ func toPercentage() -> Float {
623
+ return Float(100.0) * Float(completedResourceCount) / Float(requiredResourceCount)
624
+ }
625
+ func hasCompleted() -> Bool {
626
+ return (completedResourceCount == requiredResourceCount)
627
+ }
628
+ }