@maplibre/maplibre-react-native 11.0.0-beta.10 → 11.0.0-beta.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/android/src/main/java/org/maplibre/reactnative/components/annotations/pointannotation/MLRNPointAnnotation.kt +40 -24
- package/android/src/main/java/org/maplibre/reactnative/components/annotations/pointannotation/MLRNPointAnnotationManager.kt +2 -1
- package/android/src/main/java/org/maplibre/reactnative/components/mapview/MLRNMapView.kt +23 -73
- package/ios/components/annotations/point-annotation/MLRNPointAnnotation.m +23 -2
- package/ios/components/images/MLRNImageLoader.h +27 -0
- package/ios/components/images/MLRNImageLoader.m +85 -0
- package/ios/components/images/MLRNImageQueue.h +2 -2
- package/ios/components/images/MLRNImageQueue.m +2 -2
- package/ios/components/images/MLRNImageQueueOperation.h +2 -2
- package/ios/components/images/MLRNImageQueueOperation.m +3 -3
- package/ios/components/images/MLRNImages.h +0 -3
- package/ios/components/images/MLRNImages.m +6 -6
- package/ios/components/images/MLRNImagesComponentView.mm +0 -3
- package/ios/components/images/MLRNImagesModule.h +6 -0
- package/ios/components/images/MLRNImagesModule.mm +23 -0
- package/ios/components/layer/MLRNLayer.h +0 -3
- package/ios/components/layer/MLRNLayer.m +0 -1
- package/ios/components/layer/MLRNLayerComponentView.mm +0 -2
- package/ios/components/layer/style/MLRNStyle.h +0 -2
- package/ios/components/layer/style/MLRNStyle.m +67 -70
- package/ios/components/map-view/MLRNMapView.h +2 -0
- package/ios/components/map-view/MLRNMapView.m +30 -11
- package/ios/components/sources/geojson-source/MLRNGeoJSONSource.h +0 -3
- package/ios/utils/MLRNUtils.h +0 -14
- package/ios/utils/MLRNUtils.m +0 -71
- package/lib/commonjs/components/images/Images.js +1 -0
- package/lib/commonjs/components/images/Images.js.map +1 -1
- package/lib/commonjs/components/images/NativeImagesModule.js +10 -0
- package/lib/commonjs/components/images/NativeImagesModule.js.map +1 -0
- package/lib/module/components/images/Images.js +1 -0
- package/lib/module/components/images/Images.js.map +1 -1
- package/lib/module/components/images/NativeImagesModule.js +7 -0
- package/lib/module/components/images/NativeImagesModule.js.map +1 -0
- package/lib/typescript/commonjs/src/components/images/Images.d.ts +1 -0
- package/lib/typescript/commonjs/src/components/images/Images.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/components/images/NativeImagesModule.d.ts +6 -0
- package/lib/typescript/commonjs/src/components/images/NativeImagesModule.d.ts.map +1 -0
- package/lib/typescript/module/src/components/images/Images.d.ts +1 -0
- package/lib/typescript/module/src/components/images/Images.d.ts.map +1 -1
- package/lib/typescript/module/src/components/images/NativeImagesModule.d.ts +6 -0
- package/lib/typescript/module/src/components/images/NativeImagesModule.d.ts.map +1 -0
- package/package.json +6 -5
- package/src/components/images/Images.tsx +1 -0
- package/src/components/images/NativeImagesModule.ts +11 -0
- package/android/src/main/res/layout/annotation.xml +0 -17
- /package/android/src/main/res/drawable-xxhdpi/{red_marker.png → default_marker.png} +0 -0
- /package/ios/{components/images → utils}/MLRNImageUtils.h +0 -0
- /package/ios/{components/images → utils}/MLRNImageUtils.m +0 -0
|
@@ -4,6 +4,7 @@ import android.content.Context
|
|
|
4
4
|
import android.graphics.Bitmap
|
|
5
5
|
import android.graphics.PointF
|
|
6
6
|
import android.view.View
|
|
7
|
+
import android.view.ViewGroup
|
|
7
8
|
import com.facebook.react.bridge.ReactContext
|
|
8
9
|
import com.facebook.react.uimanager.UIManagerHelper
|
|
9
10
|
import org.maplibre.android.geometry.LatLng
|
|
@@ -26,18 +27,17 @@ class MLRNPointAnnotation(
|
|
|
26
27
|
private var mMap: MapLibreMap? = null
|
|
27
28
|
private var mMapView: MLRNMapView? = null
|
|
28
29
|
|
|
29
|
-
private val mHasChildren = false
|
|
30
|
-
|
|
31
30
|
private var mCoordinate: Point? = null
|
|
32
31
|
|
|
33
|
-
|
|
34
|
-
|
|
32
|
+
var mapLibreId: String? = null
|
|
33
|
+
var title: String? = null
|
|
35
34
|
private var mSnippet: String? = null
|
|
36
35
|
|
|
37
36
|
private var mAnchor: FloatArray? = null
|
|
38
37
|
private var mOffset: FloatArray? = null
|
|
39
|
-
private val mIsSelected = false
|
|
40
38
|
private var mDraggable = false
|
|
39
|
+
var selected = false
|
|
40
|
+
private set
|
|
41
41
|
|
|
42
42
|
private var mChildView: View? = null
|
|
43
43
|
private var mChildBitmap: Bitmap? = null
|
|
@@ -49,7 +49,7 @@ class MLRNPointAnnotation(
|
|
|
49
49
|
private var mCalloutBitmapId: String? = null
|
|
50
50
|
|
|
51
51
|
companion object {
|
|
52
|
-
const val
|
|
52
|
+
const val DEFAULT_MARKER: String = "DEFAULT_MARKER"
|
|
53
53
|
}
|
|
54
54
|
|
|
55
55
|
private val surfaceId: Int
|
|
@@ -115,7 +115,7 @@ class MLRNPointAnnotation(
|
|
|
115
115
|
// Return children in consistent order: child view first, then callout
|
|
116
116
|
return when {
|
|
117
117
|
index == 0 && mChildView != null -> mChildView
|
|
118
|
-
index == 0 &&
|
|
118
|
+
index == 0 && mCalloutView != null -> mCalloutView
|
|
119
119
|
index == 1 && mChildView != null && mCalloutView != null -> mCalloutView
|
|
120
120
|
else -> null
|
|
121
121
|
}
|
|
@@ -139,6 +139,10 @@ class MLRNPointAnnotation(
|
|
|
139
139
|
}
|
|
140
140
|
addBitmapToStyle(mCalloutBitmap, mCalloutBitmapId)
|
|
141
141
|
}
|
|
142
|
+
|
|
143
|
+
if (selected) {
|
|
144
|
+
mMapView?.selectAnnotation(this)
|
|
145
|
+
}
|
|
142
146
|
}
|
|
143
147
|
|
|
144
148
|
override fun removeFromMap(mapView: MLRNMapView) {
|
|
@@ -201,16 +205,12 @@ class MLRNPointAnnotation(
|
|
|
201
205
|
refreshBitmap(v, v.left, v.top, v.right, v.bottom)
|
|
202
206
|
}
|
|
203
207
|
|
|
204
|
-
fun getLatLng(): LatLng? = GeoJSONUtils.toLatLng(mCoordinate)
|
|
205
|
-
|
|
206
208
|
val annotationId: Long? get() = mAnnotation?.id
|
|
207
209
|
|
|
208
210
|
fun setSnippet(snippet: String?) {
|
|
209
211
|
mSnippet = snippet
|
|
210
212
|
}
|
|
211
213
|
|
|
212
|
-
fun getCalloutView(): View? = mCalloutView
|
|
213
|
-
|
|
214
214
|
fun setLngLat(lngLat: DoubleArray?) {
|
|
215
215
|
if (lngLat == null || lngLat.size < 2) {
|
|
216
216
|
return
|
|
@@ -260,21 +260,37 @@ class MLRNPointAnnotation(
|
|
|
260
260
|
}
|
|
261
261
|
}
|
|
262
262
|
|
|
263
|
-
fun
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
263
|
+
fun setSelectedAnnotation(selected: Boolean) {
|
|
264
|
+
if (mMapView != null && mAnnotation != null) {
|
|
265
|
+
if (selected) {
|
|
266
|
+
mMapView?.selectAnnotation(this)
|
|
267
|
+
} else {
|
|
268
|
+
mMapView?.deselectAnnotation(this)
|
|
269
|
+
}
|
|
270
|
+
} else {
|
|
271
|
+
this.selected = selected
|
|
268
272
|
}
|
|
269
|
-
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
fun onSelect() {
|
|
276
|
+
if (!selected) {
|
|
277
|
+
selected = true
|
|
278
|
+
if (mCalloutView != null) {
|
|
279
|
+
makeCallout()
|
|
280
|
+
}
|
|
281
|
+
|
|
270
282
|
emitEvent("onSelected")
|
|
271
283
|
}
|
|
272
284
|
}
|
|
273
285
|
|
|
274
286
|
fun onDeselect() {
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
287
|
+
if (selected) {
|
|
288
|
+
selected = false
|
|
289
|
+
if (mCalloutSymbol != null) {
|
|
290
|
+
mMapView?.getSymbolManager()?.delete(mCalloutSymbol)
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
emitEvent("onDeselected")
|
|
278
294
|
}
|
|
279
295
|
}
|
|
280
296
|
|
|
@@ -325,12 +341,12 @@ class MLRNPointAnnotation(
|
|
|
325
341
|
}
|
|
326
342
|
|
|
327
343
|
private fun updateIconImage() {
|
|
328
|
-
if (mChildView != null) {
|
|
344
|
+
if (mChildView != null && ((mChildView as? ViewGroup)?.childCount ?: 0) > 0) {
|
|
329
345
|
if (mChildBitmapId != null) {
|
|
330
346
|
mAnnotation?.iconImage = mChildBitmapId
|
|
331
347
|
}
|
|
332
348
|
} else {
|
|
333
|
-
mAnnotation?.iconImage =
|
|
349
|
+
mAnnotation?.iconImage = DEFAULT_MARKER
|
|
334
350
|
mAnnotation?.iconAnchor = "bottom"
|
|
335
351
|
}
|
|
336
352
|
}
|
|
@@ -418,8 +434,8 @@ class MLRNPointAnnotation(
|
|
|
418
434
|
private fun getScreenPosition(latLng: LatLng): PointF? {
|
|
419
435
|
val screenPos = mMap?.projection?.toScreenLocation(latLng)
|
|
420
436
|
val density = getDisplayDensity()
|
|
421
|
-
screenPos?.x = screenPos
|
|
422
|
-
screenPos?.y = screenPos
|
|
437
|
+
screenPos?.x = screenPos.x.div(density)
|
|
438
|
+
screenPos?.y = screenPos.y.div(density)
|
|
423
439
|
return screenPos
|
|
424
440
|
}
|
|
425
441
|
|
|
@@ -156,9 +156,6 @@ open class MLRNMapView(
|
|
|
156
156
|
|
|
157
157
|
private var symbolManager: SymbolManager? = null
|
|
158
158
|
|
|
159
|
-
private var activePointAnnotationAnnotationId: Long? = null
|
|
160
|
-
private var pointAnnotationClicked = false
|
|
161
|
-
|
|
162
159
|
private var markerViewManager: MarkerViewManager? = null
|
|
163
160
|
private var offscreenAnnotationViewContainer: ViewGroup? = null
|
|
164
161
|
|
|
@@ -264,10 +261,6 @@ open class MLRNMapView(
|
|
|
264
261
|
}
|
|
265
262
|
|
|
266
263
|
is MLRNPointAnnotation -> {
|
|
267
|
-
if (child.feature.annotationId == activePointAnnotationAnnotationId) {
|
|
268
|
-
activePointAnnotationAnnotationId = null
|
|
269
|
-
}
|
|
270
|
-
|
|
271
264
|
child.feature.mapLibreId?.let { pointAnnotations.remove(it) }
|
|
272
265
|
}
|
|
273
266
|
|
|
@@ -324,18 +317,11 @@ open class MLRNMapView(
|
|
|
324
317
|
mapLibreMap!!.moveCamera(cameraUpdate, callback)
|
|
325
318
|
}
|
|
326
319
|
|
|
327
|
-
fun
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
if (annotation != null && markerID == annotation.annotationId) {
|
|
332
|
-
return annotation
|
|
333
|
-
}
|
|
320
|
+
fun getPointAnnotationByAnnotationId(annotationId: Long): MLRNPointAnnotation? =
|
|
321
|
+
pointAnnotations.values.find {
|
|
322
|
+
it.annotationId == annotationId
|
|
334
323
|
}
|
|
335
324
|
|
|
336
|
-
return null
|
|
337
|
-
}
|
|
338
|
-
|
|
339
325
|
fun getSymbolManager(): SymbolManager = symbolManager!!
|
|
340
326
|
|
|
341
327
|
interface FoundLayerCallback {
|
|
@@ -465,28 +451,24 @@ open class MLRNMapView(
|
|
|
465
451
|
symbolManager = SymbolManager(this, this.mapLibreMap!!, style)
|
|
466
452
|
symbolManager!!.setIconAllowOverlap(true)
|
|
467
453
|
symbolManager!!.addClickListener { symbol ->
|
|
468
|
-
|
|
454
|
+
onPointAnnotationClick(symbol)
|
|
469
455
|
true
|
|
470
456
|
}
|
|
471
457
|
symbolManager!!.addDragListener(
|
|
472
458
|
object : OnSymbolDragListener {
|
|
473
459
|
override fun onAnnotationDragStarted(symbol: Symbol) {
|
|
474
|
-
|
|
475
|
-
val
|
|
476
|
-
val annotation = getPointAnnotationByMarkerID(selectedMarkerID)
|
|
460
|
+
val selectedPointAnnotationID = symbol.id
|
|
461
|
+
val annotation = getPointAnnotationByAnnotationId(selectedPointAnnotationID)
|
|
477
462
|
annotation?.onDragStart()
|
|
478
463
|
}
|
|
479
464
|
|
|
480
465
|
override fun onAnnotationDrag(symbol: Symbol) {
|
|
481
|
-
val
|
|
482
|
-
val annotation = getPointAnnotationByMarkerID(selectedMarkerID)
|
|
466
|
+
val annotation = getPointAnnotationByAnnotationId(symbol.id)
|
|
483
467
|
annotation?.onDrag()
|
|
484
468
|
}
|
|
485
469
|
|
|
486
470
|
override fun onAnnotationDragFinished(symbol: Symbol) {
|
|
487
|
-
|
|
488
|
-
val selectedMarkerID = symbol.id
|
|
489
|
-
val annotation = getPointAnnotationByMarkerID(selectedMarkerID)
|
|
471
|
+
val annotation = getPointAnnotationByAnnotationId(symbol.id)
|
|
490
472
|
annotation?.onDragEnd()
|
|
491
473
|
}
|
|
492
474
|
},
|
|
@@ -547,17 +529,7 @@ open class MLRNMapView(
|
|
|
547
529
|
}
|
|
548
530
|
|
|
549
531
|
override fun onMapClick(latLng: LatLng): Boolean {
|
|
550
|
-
|
|
551
|
-
pointAnnotationClicked = false
|
|
552
|
-
}
|
|
553
|
-
|
|
554
|
-
if (activePointAnnotationAnnotationId != null) {
|
|
555
|
-
val active =
|
|
556
|
-
pointAnnotations.values.find { it.annotationId == activePointAnnotationAnnotationId }
|
|
557
|
-
if (active != null) {
|
|
558
|
-
deselectAnnotation(active)
|
|
559
|
-
}
|
|
560
|
-
}
|
|
532
|
+
pointAnnotations.values.find { it.selected }?.let { deselectAnnotation(it) }
|
|
561
533
|
|
|
562
534
|
val screenPoint = mapLibreMap!!.projection.toScreenLocation(latLng)
|
|
563
535
|
|
|
@@ -607,10 +579,6 @@ open class MLRNMapView(
|
|
|
607
579
|
}
|
|
608
580
|
|
|
609
581
|
override fun onMapLongClick(latLng: LatLng): Boolean {
|
|
610
|
-
if (pointAnnotationClicked) {
|
|
611
|
-
pointAnnotationClicked = false
|
|
612
|
-
}
|
|
613
|
-
|
|
614
582
|
val screenPoint = mapLibreMap!!.projection.toScreenLocation(latLng)
|
|
615
583
|
|
|
616
584
|
if (markerViewManager?.isPointInsideMarker(screenPoint) == true) {
|
|
@@ -626,42 +594,24 @@ open class MLRNMapView(
|
|
|
626
594
|
return false
|
|
627
595
|
}
|
|
628
596
|
|
|
629
|
-
fun
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
var activeAnnotation: MLRNPointAnnotation? = null
|
|
634
|
-
var nextActiveAnnotation: MLRNPointAnnotation? = null
|
|
635
|
-
|
|
636
|
-
for (key in pointAnnotations.keys) {
|
|
637
|
-
val pointAnnotation = pointAnnotations[key]
|
|
638
|
-
val currentAnnotationId = pointAnnotation!!.annotationId
|
|
597
|
+
fun onPointAnnotationClick(nextSymbol: Symbol) {
|
|
598
|
+
val nextSelectedPointAnnotation =
|
|
599
|
+
getPointAnnotationByAnnotationId(nextSymbol.id) ?: return
|
|
639
600
|
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
}
|
|
643
|
-
|
|
644
|
-
if (selectedMarkerID == currentAnnotationId && activePointAnnotationAnnotationId != currentAnnotationId) {
|
|
645
|
-
nextActiveAnnotation = pointAnnotation
|
|
646
|
-
}
|
|
647
|
-
}
|
|
648
|
-
|
|
649
|
-
if (activeAnnotation != null) {
|
|
650
|
-
deselectAnnotation(activeAnnotation)
|
|
651
|
-
}
|
|
652
|
-
|
|
653
|
-
if (nextActiveAnnotation != null) {
|
|
654
|
-
selectAnnotation(nextActiveAnnotation)
|
|
601
|
+
if (!nextSelectedPointAnnotation.selected) {
|
|
602
|
+
selectAnnotation(nextSelectedPointAnnotation)
|
|
655
603
|
}
|
|
656
604
|
}
|
|
657
605
|
|
|
658
|
-
fun selectAnnotation(
|
|
659
|
-
|
|
660
|
-
|
|
606
|
+
fun selectAnnotation(nextSelectedPointAnnotation: MLRNPointAnnotation) {
|
|
607
|
+
pointAnnotations.values
|
|
608
|
+
.filter { it.selected && it !== nextSelectedPointAnnotation }
|
|
609
|
+
.forEach { it.onDeselect() }
|
|
610
|
+
|
|
611
|
+
nextSelectedPointAnnotation.onSelect()
|
|
661
612
|
}
|
|
662
613
|
|
|
663
614
|
fun deselectAnnotation(annotation: MLRNPointAnnotation) {
|
|
664
|
-
activePointAnnotationAnnotationId = null
|
|
665
615
|
annotation.onDeselect()
|
|
666
616
|
}
|
|
667
617
|
|
|
@@ -1359,7 +1309,7 @@ open class MLRNMapView(
|
|
|
1359
1309
|
}
|
|
1360
1310
|
|
|
1361
1311
|
private fun getPressableSourceWithHighestZIndex(sources: MutableList<MLRNPressableSource<*>>?): MLRNPressableSource<*>? {
|
|
1362
|
-
if (sources
|
|
1312
|
+
if (sources.isNullOrEmpty()) {
|
|
1363
1313
|
return null
|
|
1364
1314
|
}
|
|
1365
1315
|
|
|
@@ -1412,10 +1362,10 @@ open class MLRNMapView(
|
|
|
1412
1362
|
*/
|
|
1413
1363
|
private fun setUpImage(loadedStyle: Style) {
|
|
1414
1364
|
loadedStyle.addImage(
|
|
1415
|
-
|
|
1365
|
+
MLRNPointAnnotation.DEFAULT_MARKER,
|
|
1416
1366
|
BitmapFactory.decodeResource(
|
|
1417
1367
|
this.resources,
|
|
1418
|
-
R.drawable.
|
|
1368
|
+
R.drawable.default_marker,
|
|
1419
1369
|
),
|
|
1420
1370
|
)
|
|
1421
1371
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#import "MLRNPointAnnotation.h"
|
|
2
2
|
#import <React/UIView+React.h>
|
|
3
3
|
#import "MLRNMapTouchEvent.h"
|
|
4
|
+
#import "MLRNMapView.h"
|
|
4
5
|
#import "MLRNUtils.h"
|
|
5
6
|
|
|
6
7
|
const float CENTER_X_OFFSET_BASE = -0.5f;
|
|
@@ -75,6 +76,9 @@ const float CENTER_Y_OFFSET_BASE = -0.5f;
|
|
|
75
76
|
_reactSelected = reactSelected;
|
|
76
77
|
|
|
77
78
|
if (_map != nil) {
|
|
79
|
+
if ([_map isKindOfClass:[MLRNMapView class]]) {
|
|
80
|
+
((MLRNMapView *)_map).annotationSelected = YES;
|
|
81
|
+
}
|
|
78
82
|
if (_reactSelected) {
|
|
79
83
|
[_map selectAnnotation:self animated:NO completionHandler:nil];
|
|
80
84
|
} else {
|
|
@@ -120,8 +124,22 @@ const float CENTER_Y_OFFSET_BASE = -0.5f;
|
|
|
120
124
|
BOOL hasCustomChildren = (self.reactSubviews.count > 0) || (self.customChildCount > 0);
|
|
121
125
|
|
|
122
126
|
if (!hasCustomChildren) {
|
|
123
|
-
//
|
|
124
|
-
|
|
127
|
+
// Replicate MLNMapView's to allow unified tap/selection behavior.
|
|
128
|
+
NSBundle *mapLibreBundle = [NSBundle bundleForClass:[MLNMapView class]];
|
|
129
|
+
UIImage *pinImage = [UIImage imageNamed:@"default_marker"
|
|
130
|
+
inBundle:mapLibreBundle
|
|
131
|
+
compatibleWithTraitCollection:nil];
|
|
132
|
+
|
|
133
|
+
UIImageView *pinImageView = [[UIImageView alloc] initWithImage:pinImage];
|
|
134
|
+
[pinImageView sizeToFit];
|
|
135
|
+
|
|
136
|
+
MLNAnnotationView *defaultView = [[MLNAnnotationView alloc] initWithReuseIdentifier:nil];
|
|
137
|
+
defaultView.bounds = pinImageView.bounds;
|
|
138
|
+
[defaultView addSubview:pinImageView];
|
|
139
|
+
defaultView.centerOffset = CGVectorMake(0, 0);
|
|
140
|
+
defaultView.enabled = YES;
|
|
141
|
+
[defaultView addGestureRecognizer:customViewTap];
|
|
142
|
+
return defaultView;
|
|
125
143
|
} else {
|
|
126
144
|
// custom view
|
|
127
145
|
self.enabled = YES;
|
|
@@ -143,6 +161,9 @@ const float CENTER_Y_OFFSET_BASE = -0.5f;
|
|
|
143
161
|
}
|
|
144
162
|
|
|
145
163
|
- (void)_handleTap:(UITapGestureRecognizer *)recognizer {
|
|
164
|
+
if ([_map isKindOfClass:[MLRNMapView class]]) {
|
|
165
|
+
((MLRNMapView *)_map).annotationSelected = YES;
|
|
166
|
+
}
|
|
146
167
|
[_map selectAnnotation:self animated:NO completionHandler:nil];
|
|
147
168
|
}
|
|
148
169
|
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
#import <MapLibre/MapLibre.h>
|
|
2
|
+
#import <React/RCTImageLoaderProtocol.h>
|
|
3
|
+
|
|
4
|
+
NS_ASSUME_NONNULL_BEGIN
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Singleton that exposes the image loader obtained from the TurboModule registry.
|
|
8
|
+
*/
|
|
9
|
+
@interface MLRNImageLoader : NSObject
|
|
10
|
+
|
|
11
|
+
+ (instancetype)sharedInstance;
|
|
12
|
+
|
|
13
|
+
@property (nonatomic, strong, nullable) id<RCTImageLoaderProtocol> imageLoader;
|
|
14
|
+
|
|
15
|
+
+ (void)fetchImage:(NSString *)url
|
|
16
|
+
scale:(double)scale
|
|
17
|
+
sdf:(BOOL)sdf
|
|
18
|
+
callback:(RCTImageLoaderCompletionBlock)callback;
|
|
19
|
+
|
|
20
|
+
+ (void)fetchImages:(MLNStyle *)style
|
|
21
|
+
objects:(NSDictionary<NSString *, id> *)objects
|
|
22
|
+
forceUpdate:(BOOL)forceUpdate
|
|
23
|
+
callback:(void (^)(void))callback;
|
|
24
|
+
|
|
25
|
+
@end
|
|
26
|
+
|
|
27
|
+
NS_ASSUME_NONNULL_END
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
#import "MLRNImageLoader.h"
|
|
2
|
+
#import "MLRNImageQueue.h"
|
|
3
|
+
|
|
4
|
+
#import <React/RCTLog.h>
|
|
5
|
+
|
|
6
|
+
@implementation MLRNImageLoader
|
|
7
|
+
|
|
8
|
+
+ (instancetype)sharedInstance {
|
|
9
|
+
static MLRNImageLoader *_instance = nil;
|
|
10
|
+
static dispatch_once_t onceToken;
|
|
11
|
+
dispatch_once(&onceToken, ^{
|
|
12
|
+
_instance = [[MLRNImageLoader alloc] init];
|
|
13
|
+
});
|
|
14
|
+
return _instance;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
+ (void)fetchImage:(NSString *)url
|
|
18
|
+
scale:(double)scale
|
|
19
|
+
sdf:(BOOL)sdf
|
|
20
|
+
callback:(RCTImageLoaderCompletionBlock)callback {
|
|
21
|
+
[MLRNImageQueue.sharedInstance addImage:url
|
|
22
|
+
scale:scale
|
|
23
|
+
sdf:sdf
|
|
24
|
+
imageLoader:[MLRNImageLoader sharedInstance].imageLoader
|
|
25
|
+
completionHandler:callback];
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
+ (void)fetchImages:(MLNStyle *)style
|
|
29
|
+
objects:(NSDictionary<NSString *, id> *)objects
|
|
30
|
+
forceUpdate:(BOOL)forceUpdate
|
|
31
|
+
callback:(void (^)(void))callback {
|
|
32
|
+
if (objects == nil) {
|
|
33
|
+
callback();
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
NSArray<NSString *> *imageNames = objects.allKeys;
|
|
38
|
+
if (imageNames.count == 0) {
|
|
39
|
+
callback();
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
__block NSUInteger imagesLeftToLoad = imageNames.count;
|
|
44
|
+
__weak MLNStyle *weakStyle = style;
|
|
45
|
+
|
|
46
|
+
void (^imageLoadedBlock)(void) = ^{
|
|
47
|
+
imagesLeftToLoad--;
|
|
48
|
+
|
|
49
|
+
if (imagesLeftToLoad == 0) {
|
|
50
|
+
callback();
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
for (NSString *imageName in imageNames) {
|
|
55
|
+
UIImage *foundImage = forceUpdate ? nil : [style imageForName:imageName];
|
|
56
|
+
|
|
57
|
+
if (forceUpdate || foundImage == nil) {
|
|
58
|
+
NSDictionary *image = objects[imageName];
|
|
59
|
+
BOOL hasScale =
|
|
60
|
+
[image isKindOfClass:[NSDictionary class]] && ([image objectForKey:@"scale"] != nil);
|
|
61
|
+
BOOL hasSdf =
|
|
62
|
+
[image isKindOfClass:[NSDictionary class]] && ([image objectForKey:@"sdf"] != nil);
|
|
63
|
+
double scale = hasScale ? [[image objectForKey:@"scale"] doubleValue] : 1.0;
|
|
64
|
+
BOOL sdf = hasSdf ? [[image objectForKey:@"sdf"] boolValue] : NO;
|
|
65
|
+
[MLRNImageQueue.sharedInstance addImage:objects[imageName]
|
|
66
|
+
scale:scale
|
|
67
|
+
sdf:sdf
|
|
68
|
+
imageLoader:[MLRNImageLoader sharedInstance].imageLoader
|
|
69
|
+
completionHandler:^(NSError *error, UIImage *img) {
|
|
70
|
+
if (!img) {
|
|
71
|
+
RCTLogWarn(@"Failed to fetch image: %@ error:%@", imageName, error);
|
|
72
|
+
} else {
|
|
73
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
74
|
+
[weakStyle setImage:img forName:imageName];
|
|
75
|
+
imageLoadedBlock();
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
}];
|
|
79
|
+
} else {
|
|
80
|
+
imageLoadedBlock();
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
@end
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#import <Foundation/Foundation.h>
|
|
2
|
-
#import <React/
|
|
2
|
+
#import <React/RCTImageLoaderProtocol.h>
|
|
3
3
|
|
|
4
4
|
@interface MLRNImageQueue : NSObject
|
|
5
5
|
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
- (void)addImage:(NSString *)imageURL
|
|
10
10
|
scale:(double)scale
|
|
11
11
|
sdf:(Boolean)sdf
|
|
12
|
-
|
|
12
|
+
imageLoader:(id<RCTImageLoaderProtocol>)imageLoader
|
|
13
13
|
completionHandler:(RCTImageLoaderCompletionBlock)handler;
|
|
14
14
|
|
|
15
15
|
@end
|
|
@@ -34,10 +34,10 @@
|
|
|
34
34
|
- (void)addImage:(NSString *)imageURL
|
|
35
35
|
scale:(double)scale
|
|
36
36
|
sdf:(Boolean)sdf
|
|
37
|
-
|
|
37
|
+
imageLoader:(id<RCTImageLoaderProtocol>)imageLoader
|
|
38
38
|
completionHandler:(RCTImageLoaderCompletionBlock)handler {
|
|
39
39
|
MLRNImageQueueOperation *operation = [[MLRNImageQueueOperation alloc] init];
|
|
40
|
-
operation.
|
|
40
|
+
operation.imageLoader = imageLoader;
|
|
41
41
|
operation.urlRequest = [RCTConvert NSURLRequest:imageURL];
|
|
42
42
|
operation.sdf = sdf;
|
|
43
43
|
operation.completionHandler = handler;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
#import <React/
|
|
1
|
+
#import <React/RCTImageLoaderProtocol.h>
|
|
2
2
|
|
|
3
3
|
@interface MLRNImageQueueOperation : NSBlockOperation
|
|
4
4
|
|
|
5
|
-
@property (nonatomic, weak)
|
|
5
|
+
@property (nonatomic, weak) id<RCTImageLoaderProtocol> imageLoader;
|
|
6
6
|
@property (nonatomic, copy) RCTImageLoaderCompletionBlock completionHandler;
|
|
7
7
|
@property (nonatomic, copy) NSURLRequest *urlRequest;
|
|
8
8
|
@property (nonatomic) Boolean sdf;
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
#import "MLRNImageQueueOperation.h"
|
|
2
2
|
|
|
3
|
+
#import <React/RCTImageLoader.h>
|
|
4
|
+
|
|
3
5
|
typedef NS_ENUM(NSInteger, MLRNImageQueueOperationState) {
|
|
4
6
|
IOState_Initial,
|
|
5
7
|
IOState_CancelledDoNotExecute,
|
|
@@ -101,9 +103,7 @@ typedef NS_ENUM(NSInteger, MLRNImageQueueOperationState) {
|
|
|
101
103
|
__weak MLRNImageQueueOperation *weakSelf = self;
|
|
102
104
|
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
|
103
105
|
[weakSelf
|
|
104
|
-
setCancellationBlock:[
|
|
105
|
-
lazilyLoadIfNecessary:YES]
|
|
106
|
-
loadImageWithURLRequest:weakSelf.urlRequest
|
|
106
|
+
setCancellationBlock:[weakSelf.imageLoader loadImageWithURLRequest:weakSelf.urlRequest
|
|
107
107
|
size:CGSizeZero
|
|
108
108
|
scale:weakSelf.scale
|
|
109
109
|
clipped:YES
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
#import <React/RCTBridge.h>
|
|
2
1
|
#import <React/RCTComponent.h>
|
|
3
2
|
#import <UIKit/UIKit.h>
|
|
4
3
|
|
|
@@ -8,8 +7,6 @@
|
|
|
8
7
|
|
|
9
8
|
@interface MLRNImages : UIView
|
|
10
9
|
|
|
11
|
-
@property (nonatomic, weak) RCTBridge *bridge;
|
|
12
|
-
|
|
13
10
|
@property (nonatomic, strong) MLRNMapView *_Nullable map;
|
|
14
11
|
@property (nonatomic, strong, nonnull) NSMutableArray<id<RCTComponent>> *reactSubviews;
|
|
15
12
|
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
#import <React/UIView+React.h>
|
|
3
3
|
#import "MLRNEvent.h"
|
|
4
4
|
#import "MLRNEventTypes.h"
|
|
5
|
+
#import "MLRNImageLoader.h"
|
|
5
6
|
#import "MLRNMapView.h"
|
|
6
7
|
#import "MLRNUtils.h"
|
|
7
8
|
|
|
@@ -169,12 +170,11 @@ static UIImage *_placeHolderImage;
|
|
|
169
170
|
|
|
170
171
|
if (missingImages.count > 0) {
|
|
171
172
|
// forceUpdate to ensure the placeholder images are updated
|
|
172
|
-
[
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
}];
|
|
173
|
+
[MLRNImageLoader fetchImages:self.map.style
|
|
174
|
+
objects:missingImages
|
|
175
|
+
forceUpdate:true
|
|
176
|
+
callback:^{
|
|
177
|
+
}];
|
|
178
178
|
}
|
|
179
179
|
}
|
|
180
180
|
|
|
@@ -7,7 +7,6 @@
|
|
|
7
7
|
|
|
8
8
|
#import "RCTFabricComponentsPlugins.h"
|
|
9
9
|
|
|
10
|
-
#import <React/RCTBridge+Private.h>
|
|
11
10
|
#import <React/RCTConversions.h>
|
|
12
11
|
#import "MLRNFollyConvert.h"
|
|
13
12
|
#import "MLRNImages.h"
|
|
@@ -37,8 +36,6 @@ using namespace facebook::react;
|
|
|
37
36
|
- (void)prepareView {
|
|
38
37
|
_view = [[MLRNImages alloc] init];
|
|
39
38
|
|
|
40
|
-
_view.bridge = [RCTBridge currentBridge];
|
|
41
|
-
|
|
42
39
|
// Capture weak self reference to prevent retain cycle
|
|
43
40
|
__weak __typeof__(self) weakSelf = self;
|
|
44
41
|
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
#import "MLRNImagesModule.h"
|
|
2
|
+
#import "MLRNImageLoader.h"
|
|
3
|
+
|
|
4
|
+
#import <MapLibreReactNativeSpec/MapLibreReactNativeSpec.h>
|
|
5
|
+
|
|
6
|
+
@implementation MLRNImagesModule
|
|
7
|
+
|
|
8
|
+
@synthesize moduleRegistry = _moduleRegistry;
|
|
9
|
+
|
|
10
|
+
+ (NSString *)moduleName {
|
|
11
|
+
return @"MLRNImagesModule";
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:
|
|
15
|
+
(const facebook::react::ObjCTurboModule::InitParams &)params {
|
|
16
|
+
return std::make_shared<facebook::react::NativeImagesModuleSpecJSI>(params);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
- (void)initialize {
|
|
20
|
+
[MLRNImageLoader sharedInstance].imageLoader = [_moduleRegistry moduleForName:"ImageLoader"];
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
@end
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
#import <React/RCTBridge.h>
|
|
2
1
|
#import <UIKit/UIKit.h>
|
|
3
2
|
|
|
4
3
|
@class MLRNMapView;
|
|
@@ -7,8 +6,6 @@
|
|
|
7
6
|
|
|
8
7
|
@interface MLRNLayer : UIView
|
|
9
8
|
|
|
10
|
-
@property (nonatomic, weak, nullable) RCTBridge *bridge;
|
|
11
|
-
|
|
12
9
|
@property (nonatomic, strong, nullable) MLNStyleLayer *styleLayer;
|
|
13
10
|
@property (nonatomic, strong, nullable) MLNStyle *style;
|
|
14
11
|
@property (nonatomic, weak, nullable) MLRNMapView *map;
|