@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.
Files changed (48) hide show
  1. package/android/src/main/java/org/maplibre/reactnative/components/annotations/pointannotation/MLRNPointAnnotation.kt +40 -24
  2. package/android/src/main/java/org/maplibre/reactnative/components/annotations/pointannotation/MLRNPointAnnotationManager.kt +2 -1
  3. package/android/src/main/java/org/maplibre/reactnative/components/mapview/MLRNMapView.kt +23 -73
  4. package/ios/components/annotations/point-annotation/MLRNPointAnnotation.m +23 -2
  5. package/ios/components/images/MLRNImageLoader.h +27 -0
  6. package/ios/components/images/MLRNImageLoader.m +85 -0
  7. package/ios/components/images/MLRNImageQueue.h +2 -2
  8. package/ios/components/images/MLRNImageQueue.m +2 -2
  9. package/ios/components/images/MLRNImageQueueOperation.h +2 -2
  10. package/ios/components/images/MLRNImageQueueOperation.m +3 -3
  11. package/ios/components/images/MLRNImages.h +0 -3
  12. package/ios/components/images/MLRNImages.m +6 -6
  13. package/ios/components/images/MLRNImagesComponentView.mm +0 -3
  14. package/ios/components/images/MLRNImagesModule.h +6 -0
  15. package/ios/components/images/MLRNImagesModule.mm +23 -0
  16. package/ios/components/layer/MLRNLayer.h +0 -3
  17. package/ios/components/layer/MLRNLayer.m +0 -1
  18. package/ios/components/layer/MLRNLayerComponentView.mm +0 -2
  19. package/ios/components/layer/style/MLRNStyle.h +0 -2
  20. package/ios/components/layer/style/MLRNStyle.m +67 -70
  21. package/ios/components/map-view/MLRNMapView.h +2 -0
  22. package/ios/components/map-view/MLRNMapView.m +30 -11
  23. package/ios/components/sources/geojson-source/MLRNGeoJSONSource.h +0 -3
  24. package/ios/utils/MLRNUtils.h +0 -14
  25. package/ios/utils/MLRNUtils.m +0 -71
  26. package/lib/commonjs/components/images/Images.js +1 -0
  27. package/lib/commonjs/components/images/Images.js.map +1 -1
  28. package/lib/commonjs/components/images/NativeImagesModule.js +10 -0
  29. package/lib/commonjs/components/images/NativeImagesModule.js.map +1 -0
  30. package/lib/module/components/images/Images.js +1 -0
  31. package/lib/module/components/images/Images.js.map +1 -1
  32. package/lib/module/components/images/NativeImagesModule.js +7 -0
  33. package/lib/module/components/images/NativeImagesModule.js.map +1 -0
  34. package/lib/typescript/commonjs/src/components/images/Images.d.ts +1 -0
  35. package/lib/typescript/commonjs/src/components/images/Images.d.ts.map +1 -1
  36. package/lib/typescript/commonjs/src/components/images/NativeImagesModule.d.ts +6 -0
  37. package/lib/typescript/commonjs/src/components/images/NativeImagesModule.d.ts.map +1 -0
  38. package/lib/typescript/module/src/components/images/Images.d.ts +1 -0
  39. package/lib/typescript/module/src/components/images/Images.d.ts.map +1 -1
  40. package/lib/typescript/module/src/components/images/NativeImagesModule.d.ts +6 -0
  41. package/lib/typescript/module/src/components/images/NativeImagesModule.d.ts.map +1 -0
  42. package/package.json +6 -5
  43. package/src/components/images/Images.tsx +1 -0
  44. package/src/components/images/NativeImagesModule.ts +11 -0
  45. package/android/src/main/res/layout/annotation.xml +0 -17
  46. /package/android/src/main/res/drawable-xxhdpi/{red_marker.png → default_marker.png} +0 -0
  47. /package/ios/{components/images → utils}/MLRNImageUtils.h +0 -0
  48. /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
- public var mapLibreId: String? = null
34
- public var title: String? = null
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 MARKER_IMAGE_ID: String = "MARKER_IMAGE_ID"
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 && mChildView == null && mCalloutView != null -> mCalloutView
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 getMarker(): Symbol? = mAnnotation
264
-
265
- fun onSelect(shouldSendEvent: Boolean) {
266
- if (mCalloutView != null) {
267
- makeCallout()
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
- if (shouldSendEvent) {
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
- emitEvent("onDeselected")
276
- if (mCalloutSymbol != null) {
277
- mMapView?.getSymbolManager()?.delete(mCalloutSymbol)
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 = MARKER_IMAGE_ID
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?.x?.div(density) ?: 0f
422
- screenPos?.y = screenPos?.y?.div(density) ?: 0f
437
+ screenPos?.x = screenPos.x.div(density)
438
+ screenPos?.y = screenPos.y.div(density)
423
439
  return screenPos
424
440
  }
425
441
 
@@ -82,7 +82,8 @@ class MLRNPointAnnotationManager(
82
82
  annotation: MLRNPointAnnotation,
83
83
  selected: Boolean,
84
84
  ) {
85
- // Selection is handled by the map view
85
+ annotation
86
+ .setSelectedAnnotation(selected)
86
87
  }
87
88
 
88
89
  @ReactProp(name = "lngLat")
@@ -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 getPointAnnotationByMarkerID(markerID: Long): MLRNPointAnnotation? {
328
- for (key in pointAnnotations.keys) {
329
- val annotation = pointAnnotations[key]
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
- onMarkerClick(symbol)
454
+ onPointAnnotationClick(symbol)
469
455
  true
470
456
  }
471
457
  symbolManager!!.addDragListener(
472
458
  object : OnSymbolDragListener {
473
459
  override fun onAnnotationDragStarted(symbol: Symbol) {
474
- pointAnnotationClicked = true
475
- val selectedMarkerID = symbol.id
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 selectedMarkerID = symbol.id
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
- pointAnnotationClicked = false
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
- if (pointAnnotationClicked) {
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 onMarkerClick(symbol: Symbol) {
630
- pointAnnotationClicked = true
631
- val selectedMarkerID = symbol.id
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
- if (activePointAnnotationAnnotationId == currentAnnotationId) {
641
- activeAnnotation = pointAnnotation
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(annotation: MLRNPointAnnotation) {
659
- activePointAnnotationAnnotationId = annotation.annotationId
660
- annotation.onSelect(true)
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 == null || sources.isEmpty()) {
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
- "MARKER_IMAGE_ID",
1365
+ MLRNPointAnnotation.DEFAULT_MARKER,
1416
1366
  BitmapFactory.decodeResource(
1417
1367
  this.resources,
1418
- R.drawable.red_marker,
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
- // default pin view
124
- return nil;
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/RCTImageLoader.h>
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
- bridge:(RCTBridge *)bridge
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
- bridge:(RCTBridge *)bridge
37
+ imageLoader:(id<RCTImageLoaderProtocol>)imageLoader
38
38
  completionHandler:(RCTImageLoaderCompletionBlock)handler {
39
39
  MLRNImageQueueOperation *operation = [[MLRNImageQueueOperation alloc] init];
40
- operation.bridge = bridge;
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/RCTImageLoader.h>
1
+ #import <React/RCTImageLoaderProtocol.h>
2
2
 
3
3
  @interface MLRNImageQueueOperation : NSBlockOperation
4
4
 
5
- @property (nonatomic, weak) RCTBridge *bridge;
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:[[weakSelf.bridge moduleForName:@"ImageLoader"
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
- [MLRNUtils fetchImages:_bridge
173
- style:self.map.style
174
- objects:missingImages
175
- forceUpdate:true
176
- callback:^{
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,6 @@
1
+ #import <MapLibreReactNativeSpec/MapLibreReactNativeSpec.h>
2
+
3
+ #import <React/RCTInitializing.h>
4
+
5
+ @interface MLRNImagesModule : NSObject <NativeImagesModuleSpec, RCTInitializing>
6
+ @end
@@ -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;
@@ -211,7 +211,6 @@
211
211
 
212
212
  - (void)addStyles {
213
213
  MLRNStyle *style = [[MLRNStyle alloc] initWithMLNStyle:self.style];
214
- style.bridge = self.bridge;
215
214
 
216
215
  BOOL (^isValid)(void) = ^{
217
216
  return [self isAddedToMap];