Skip to content

Commit

Permalink
feat: TileStore with TileStore.setOption (#3278)
Browse files Browse the repository at this point in the history
  • Loading branch information
mfazekas authored Dec 16, 2023
1 parent 5bd099b commit e30ffba
Show file tree
Hide file tree
Showing 21 changed files with 392 additions and 8 deletions.
1 change: 1 addition & 0 deletions __tests__/interface.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ describe('Public Interface', () => {

// modules
'offlineManager',
'TileStore',
'offlineManagerLegacy',
'OfflineCreatePackOptions',
'snapshotManager',
Expand Down
11 changes: 11 additions & 0 deletions android/src/main/java/com/rnmapbox/rnmbx/RNMBXPackage.kt
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ import com.rnmapbox.rnmbx.modules.RNMBXModule
import com.rnmapbox.rnmbx.modules.RNMBXOfflineModule
import com.rnmapbox.rnmbx.modules.RNMBXOfflineModuleLegacy
import com.rnmapbox.rnmbx.modules.RNMBXSnapshotModule
import com.rnmapbox.rnmbx.modules.RNMBXTileStoreModule
import com.rnmapbox.rnmbx.shape_animators.RNMBXMovePointShapeAnimatorModule
import com.rnmapbox.rnmbx.shape_animators.ShapeAnimatorManager
import com.rnmapbox.rnmbx.utils.ViewTagResolver
Expand Down Expand Up @@ -90,6 +91,7 @@ class RNMBXPackage : TurboReactPackage() {
RNMBXModule.REACT_CLASS -> return RNMBXModule(reactApplicationContext)
RNMBXLocationModule.REACT_CLASS -> return RNMBXLocationModule(reactApplicationContext)
RNMBXOfflineModule.REACT_CLASS -> return RNMBXOfflineModule(reactApplicationContext)
RNMBXTileStoreModule.REACT_CLASS -> return RNMBXTileStoreModule(reactApplicationContext)
RNMBXOfflineModuleLegacy.REACT_CLASS -> return RNMBXOfflineModuleLegacy(reactApplicationContext)
RNMBXSnapshotModule.REACT_CLASS -> return RNMBXSnapshotModule(reactApplicationContext)
RNMBXLogging.REACT_CLASS -> return RNMBXLogging(reactApplicationContext)
Expand Down Expand Up @@ -189,6 +191,15 @@ class RNMBXPackage : TurboReactPackage() {
false, // isCxxModule
false // isTurboModule
)
moduleInfos[RNMBXTileStoreModule.REACT_CLASS] = ReactModuleInfo(
RNMBXTileStoreModule.REACT_CLASS,
RNMBXTileStoreModule.REACT_CLASS,
false, // canOverrideExistingModule
false, // needsEagerInit
true, // hasConstants
false, // isCxxModule
false // isTurboModule
)
moduleInfos[RNMBXOfflineModuleLegacy.REACT_CLASS] = ReactModuleInfo(
RNMBXOfflineModuleLegacy.REACT_CLASS,
RNMBXOfflineModuleLegacy.REACT_CLASS,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package com.rnmapbox.rnmbx.modules

import com.facebook.react.bridge.Promise
import com.facebook.react.bridge.ReactApplicationContext
import com.facebook.react.bridge.ReactContextBaseJavaModule
import com.facebook.react.bridge.ReactMethod
import com.facebook.react.bridge.ReadableMap
import com.facebook.react.module.annotations.ReactModule
import com.mapbox.common.TileDataDomain
import com.mapbox.common.TileStore
import com.rnmapbox.rnmbx.utils.extensions.toValue
import com.rnmapbox.rnmbx.utils.writableMapOf

typealias Tag = Int

@ReactModule(name = RNMBXTileStoreModule.REACT_CLASS)
class RNMBXTileStoreModule(private val mReactContext: ReactApplicationContext) :
ReactContextBaseJavaModule(
mReactContext
) {

fun shared(path: String?): TileStore {
return if (path != null) {
TileStore.create(path)
} else {
TileStore.create()
}
}

@ReactMethod
fun shared(path: String?, promise: Promise) {
val tag = RNMBXTileStoreModule.tileStorePathTags.get(path)
if (tag != null) {
promise.resolve(tag)
} else {
val tileStore = shared(path)
RNMBXTileStoreModule.lastTag += 1
val tag = RNMBXTileStoreModule.lastTag
RNMBXTileStoreModule.tileStores.put(tag, tileStore)
RNMBXTileStoreModule.tileStorePathTags.set(path, tag)
promise.resolve(tag)
}
}

@ReactMethod
fun setOption(tag: Double, key:String, domain: String, value: ReadableMap, promise: Promise) {
val tileStore = RNMBXTileStoreModule.tileStores[tag.toInt()]
if (tileStore == null) {
promise.reject(REACT_CLASS, "No tile store found for tag")
return
}

tileStore.setOption(key, TileDataDomain.valueOf(domain.uppercase()), value.getDynamic("value").toValue());
promise.resolve(null)
}

override fun getName(): String {
return REACT_CLASS
}

companion object {
const val REACT_CLASS = "RNMBXTileStoreModule"

var tileStores = mutableMapOf<Tag, TileStore>()
var tileStorePathTags = mutableMapOf<String?, Tag>()
var lastTag = REACT_CLASS.hashCode() % 1096
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@

/**
* This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen).
*
* Do not edit this file as changes may cause incorrect behavior and will be lost
* once the code is regenerated.
*
* @generated by codegen project: GenerateModuleJavaSpec.js
*
* @nolint
*/

package com.rnmapbox.rnmbx;

import com.facebook.proguard.annotations.DoNotStrip;
import com.facebook.react.bridge.Promise;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.ReactModuleWithSpec;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.turbomodule.core.interfaces.TurboModule;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;

public abstract class NativeRNMBXTileStoreModuleSpec extends ReactContextBaseJavaModule implements ReactModuleWithSpec, TurboModule {
public static final String NAME = "RNMBXTileStoreModule";

public NativeRNMBXTileStoreModuleSpec(ReactApplicationContext reactContext) {
super(reactContext);
}

@Override
public @Nonnull String getName() {
return NAME;
}

@ReactMethod
@DoNotStrip
public abstract void shared(@Nullable String path, Promise promise);

@ReactMethod
@DoNotStrip
public abstract void setOption(double tag, String key, String domain, ReadableMap value, Promise promise);
}
47 changes: 47 additions & 0 deletions docs/docs.json
Original file line number Diff line number Diff line change
Expand Up @@ -8390,5 +8390,52 @@
}
}
]
},
"tileStore": {
"name": "tileStore",
"fileNameWithExt": "TileStore.ts",
"relPath": "src/modules/offline/TileStore.ts",
"description": "TileStore manages downloads and storage for requests to tile-related API endpoints,\nenforcing a disk usage quota: tiles available on disk may be deleted to make room for a new download.\nThis interface can be used by an app developer to set the disk quota.",
"props": [],
"styles": [],
"methods": [
{
"name": "setOption",
"description": "Sets additional options for this instance that are specific to a data type.\nParams:\nkey – The configuration option that should be changed. Valid keys are listed in \\c TileStoreOptions. domain – The data type this setting should be applied for. value – The value for the configuration option, or null if it should be reset.",
"params": [
{
"name": "key",
"description": "",
"type": {
"name": "string"
},
"optional": false
},
{
"name": "domain",
"description": "",
"type": {
"name": "TileDataDomain"
},
"optional": false
},
{
"name": "value",
"description": "",
"type": {
"name": "TileDataValue"
},
"optional": false
}
],
"examples": [],
"returns": {
"description": "",
"type": {
"name": "Promise"
}
}
}
]
}
}
30 changes: 30 additions & 0 deletions docs/tileStore.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<!-- This file was autogenerated from TileStore.ts do not modify -->



```tsx
import { tileStore } from '@rnmapbox/maps';

tileStore

```
TileStore manages downloads and storage for requests to tile-related API endpoints,
enforcing a disk usage quota: tiles available on disk may be deleted to make room for a new download.
This interface can be used by an app developer to set the disk quota.



## methods
### setOption(key, domain, value)

Sets additional options for this instance that are specific to a data type.<br/>Params:<br/>key – The configuration option that should be changed. Valid keys are listed in \c TileStoreOptions. domain – The data type this setting should be applied for. value – The value for the configuration option, or null if it should be reset.

#### arguments
| Name | Type | Required | Description |
| ---- | :--: | :------: | :----------: |
| `key` | `string` | `Yes` | |
| `domain` | `TileDataDomain` | `Yes` | |
| `value` | `TileDataValue` | `Yes` | |



File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -127,32 +127,32 @@ class RNMBXOfflineModule: RCTEventEmitter {
)

@objc override
func startObserving() {
public func startObserving() {
super.startObserving()
hasListeners = true
}

@objc override
func stopObserving() {
public func stopObserving() {
super.stopObserving()
hasListeners = false
}

@objc
override
static func requiresMainQueueSetup() -> Bool {
static public func requiresMainQueueSetup() -> Bool {
return true
}

@objc
override
func constantsToExport() -> [AnyHashable: Any]! {
public func constantsToExport() -> [AnyHashable: Any]! {
return [:]
}

@objc
override
func supportedEvents() -> [String] {
public func supportedEvents() -> [String] {
return [Callbacks.error.rawValue, Callbacks.progress.rawValue]
}

Expand Down
File renamed without changes.
File renamed without changes.
9 changes: 9 additions & 0 deletions ios/RNMBX/Offline/RNMBXTileStoreModule.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#import "React/RCTBridgeModule.h"
#import <React/RCTEventEmitter.h>

@interface RCT_EXTERN_MODULE(RNMBXTileStoreModule, NSObject)

RCT_EXTERN_METHOD(shared:(NSString *) path resolver:(RCTPromiseResolveBlock) resolve rejecter:(RCTPromiseRejectBlock) reject)
RCT_EXTERN_METHOD(setOption:(nonnull NSNumber *) tag key:(NSString*) key domain:(NSString*) domain value:(NSDictionary*) value resolver:(RCTPromiseResolveBlock) resolve rejecter:(RCTPromiseRejectBlock) reject)

@end
69 changes: 69 additions & 0 deletions ios/RNMBX/Offline/RNMBXTileStoreModule.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import Foundation
import MapboxMaps

typealias Tag = Int

@objc(RNMBXTileStoreModule)
class RNMBXTileStoreModule: NSObject {

static var tileStores : [Tag: TileStore] = [:]
static var tileStorePathTags: [String?:Tag] = [:]

static var lastTag: Tag = ("RNMBXOfflineModule".hashValue % 1096)

func shared(path: String?) -> TileStore {
if let path = path {
let url = URL(fileURLWithPath: path)
return TileStore.shared(for: url)
} else {
return TileStore.default
}
}

@objc
public func shared(_ path: String?, resolver: RCTPromiseResolveBlock, rejecter: RCTPromiseRejectBlock) {
if let tag = RNMBXTileStoreModule.tileStorePathTags[path] {
resolver(NSNumber(value: tag))
} else {
let tileStore = shared(path: path)
RNMBXTileStoreModule.lastTag += 1;
let tag = RNMBXTileStoreModule.lastTag
RNMBXTileStoreModule.tileStores[tag] = tileStore
RNMBXTileStoreModule.tileStorePathTags[path] = tag
resolver(NSNumber(value: tag))
}
}

private func tileDataDomain(name: String) -> TileDataDomain? {
switch name {
case "Maps": return .maps
case "Navigation": return .navigation
case "Search": return .search
case "ADAS": return .adas
default:
return nil
}
}

@objc
func setOption(_ tag: NSNumber, key:String, domain: String, value: NSDictionary, resolver: RCTPromiseResolveBlock, rejecter: RCTPromiseRejectBlock) {
guard let tileStore = RNMBXTileStoreModule.tileStores[tag.intValue] else {
rejecter("invalidArgument","No tile store found for tag \(tag)", nil)
return
}


guard let domain = tileDataDomain(name: domain) else {
rejecter("invalidArgument","No domain found for \(domain)", nil)
return
}

tileStore.setOptionForKey(key, domain: domain, value: value.object(forKey: "value"))
resolver(nil)
}

@objc
public static func requiresMainQueueSetup() -> Bool {
return true
}
}
6 changes: 5 additions & 1 deletion ios/RNMBX/RNMBXMapView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,11 @@ open class RNMBXMapView: UIView {
#if RNMBX_11
_mapView = MapView(frame: self.bounds, mapInitOptions: MapInitOptions())
#else
let resourceOptions = ResourceOptions(accessToken: RNMBXModule.accessToken!)
let accessToken = RNMBXModule.accessToken
if accessToken == nil {
Logger.log(level: .error, message: "No accessToken set, please call Mapbox.setAccessToken(...)")
}
let resourceOptions = ResourceOptions(accessToken: accessToken ?? "")
_mapView = MapView(frame: frame, mapInitOptions: MapInitOptions(resourceOptions: resourceOptions))
#endif
_mapView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
Expand Down
3 changes: 3 additions & 0 deletions scripts/autogenHelpers/DocJSONBuilder.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ import * as url from 'url';

import dir from 'node-dir';
import { parse, utils } from 'react-docgen';

import { pascelCase } from './globals.mjs';

const { parseJsDoc } = utils;

import JSDocNodeTree from './JSDocNodeTree.js';
Expand Down
2 changes: 1 addition & 1 deletion scripts/autogenHelpers/JSDocNodeTree.js
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ class JSDocNodeTree {
}

_hasArray(node, propName) {
if (!this._root) {
if (!this._root || !node) {
return false;
}
return Array.isArray(node[propName]) && node[propName].length;
Expand Down
1 change: 0 additions & 1 deletion scripts/autogenerate.mjs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import fs from 'fs';
import path from 'path';
import { execSync } from 'child_process';
import * as url from 'url';
Expand Down
Loading

0 comments on commit e30ffba

Please sign in to comment.