@maydon_tech/react-native-nitro-maps 0.1.4 → 0.2.0
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/LICENSE +1 -1
- package/NitroMap.podspec +1 -1
- package/README.md +82 -9
- package/android/CMakeLists.txt +4 -1
- package/android/gradle.properties +4 -4
- package/android/src/main/cpp/ClusterEngineJNI.cpp +198 -0
- package/android/src/main/kotlin/com/margelo/nitro/nitromap/NitroMap.kt +397 -0
- package/android/src/main/kotlin/com/margelo/nitro/nitromap/NitroMapConfig.kt +53 -0
- package/android/src/main/{java → kotlin}/com/margelo/nitro/nitromap/NitroMapPackage.kt +4 -4
- package/android/src/main/kotlin/com/margelo/nitro/nitromap/NitroMapView.kt +73 -0
- package/android/src/main/kotlin/com/margelo/nitro/nitromap/UserLocationManager.kt +295 -0
- package/android/src/main/kotlin/com/margelo/nitro/nitromap/clustering/ClusterIconRenderer.kt +111 -0
- package/android/src/main/kotlin/com/margelo/nitro/nitromap/clustering/ClusteringManager.kt +104 -0
- package/android/src/main/kotlin/com/margelo/nitro/nitromap/clustering/NitroClusterEngine.kt +166 -0
- package/android/src/main/kotlin/com/margelo/nitro/nitromap/markers/MarkerIconFactory.kt +303 -0
- package/android/src/main/kotlin/com/margelo/nitro/nitromap/markers/MarkerSelectionHandler.kt +72 -0
- package/android/src/main/kotlin/com/margelo/nitro/nitromap/markers/PriceMarkerRenderer.kt +159 -0
- package/android/src/main/kotlin/com/margelo/nitro/nitromap/providers/MapProviderFactory.kt +24 -0
- package/android/src/main/kotlin/com/margelo/nitro/nitromap/providers/MapProviderInterface.kt +128 -0
- package/android/src/main/kotlin/com/margelo/nitro/nitromap/providers/google/GoogleMapDelegate.kt +317 -0
- package/android/src/main/kotlin/com/margelo/nitro/nitromap/providers/google/GoogleMapProvider+Clustering.kt +524 -0
- package/android/src/main/kotlin/com/margelo/nitro/nitromap/providers/google/GoogleMapProvider+Markers.kt +358 -0
- package/android/src/main/kotlin/com/margelo/nitro/nitromap/providers/google/GoogleMapProvider+Overlays.kt +272 -0
- package/android/src/main/kotlin/com/margelo/nitro/nitromap/providers/google/GoogleMapProvider+UserLocation.kt +296 -0
- package/android/src/main/kotlin/com/margelo/nitro/nitromap/providers/google/GoogleMapProvider.kt +815 -0
- package/android/src/main/kotlin/com/margelo/nitro/nitromap/providers/google/MarkerTagData.kt +19 -0
- package/ios/Location/NitroLocationManager.swift +116 -0
- package/ios/MarkerRenderer/MarkerIconFactory.swift +1 -3
- package/ios/MarkerRenderer/PriceMarkerRenderer.swift +10 -6
- package/ios/NitroMap.swift +279 -13
- package/ios/NitroMapConfig/NitroMapConfig.swift +45 -0
- package/ios/Providers/{GoogleMapDelegate.swift → Google/GoogleMapDelegate.swift} +48 -23
- package/ios/Providers/Google/GoogleMapProvider+Camera.swift +180 -0
- package/ios/Providers/Google/GoogleMapProvider+Clustering.swift +541 -0
- package/ios/Providers/Google/GoogleMapProvider+Markers.swift +270 -0
- package/ios/Providers/Google/GoogleMapProvider+Overlays.swift +245 -0
- package/ios/Providers/Google/GoogleMapProvider+UserLocation.swift +180 -0
- package/ios/Providers/Google/GoogleMapProvider.swift +342 -0
- package/ios/Providers/MapProviderFactory.swift +17 -0
- package/ios/Providers/MapProviderProtocol.swift +48 -1
- package/ios/Shared/ClusterConfig+Factory.swift +2 -2
- package/ios/Shared/MapStyleProvider.swift +6 -4
- package/ios/Shared/MarkerSelectionHandler.swift +4 -1
- package/ios/Utils/ColorValueExtension.swift +46 -67
- package/lib/module/components/ImageMarker.js +39 -29
- package/lib/module/components/ImageMarker.js.map +1 -1
- package/lib/module/components/Marker.js +118 -0
- package/lib/module/components/Marker.js.map +1 -0
- package/lib/module/components/NitroCircle.js +92 -0
- package/lib/module/components/NitroCircle.js.map +1 -0
- package/lib/module/components/NitroMap.js +216 -76
- package/lib/module/components/NitroMap.js.map +1 -1
- package/lib/module/components/NitroPolygon.js +135 -0
- package/lib/module/components/NitroPolygon.js.map +1 -0
- package/lib/module/components/NitroPolyline.js +115 -0
- package/lib/module/components/NitroPolyline.js.map +1 -0
- package/lib/module/components/PriceMarker.js +16 -29
- package/lib/module/components/PriceMarker.js.map +1 -1
- package/lib/module/context/NitroMapContext.js.map +1 -1
- package/lib/module/hooks/useNitroCircle.js +18 -0
- package/lib/module/hooks/useNitroCircle.js.map +1 -0
- package/lib/module/hooks/useNitroMarker.js +26 -9
- package/lib/module/hooks/useNitroMarker.js.map +1 -1
- package/lib/module/hooks/useNitroOverlay.js +59 -0
- package/lib/module/hooks/useNitroOverlay.js.map +1 -0
- package/lib/module/hooks/useNitroPolygon.js +18 -0
- package/lib/module/hooks/useNitroPolygon.js.map +1 -0
- package/lib/module/hooks/useNitroPolyline.js +18 -0
- package/lib/module/hooks/useNitroPolyline.js.map +1 -0
- package/lib/module/index.js +5 -0
- package/lib/module/index.js.map +1 -1
- package/lib/module/types/overlay.js +4 -0
- package/lib/module/types/overlay.js.map +1 -0
- package/lib/module/types/theme.js +4 -0
- package/lib/module/types/theme.js.map +1 -0
- package/lib/module/utils/colors.js +41 -13
- package/lib/module/utils/colors.js.map +1 -1
- package/lib/module/utils/validation.js +45 -0
- package/lib/module/utils/validation.js.map +1 -0
- package/lib/typescript/src/components/ImageMarker.d.ts.map +1 -1
- package/lib/typescript/src/components/Marker.d.ts +34 -0
- package/lib/typescript/src/components/Marker.d.ts.map +1 -0
- package/lib/typescript/src/components/NitroCircle.d.ts +70 -0
- package/lib/typescript/src/components/NitroCircle.d.ts.map +1 -0
- package/lib/typescript/src/components/NitroMap.d.ts +60 -3
- package/lib/typescript/src/components/NitroMap.d.ts.map +1 -1
- package/lib/typescript/src/components/NitroPolygon.d.ts +86 -0
- package/lib/typescript/src/components/NitroPolygon.d.ts.map +1 -0
- package/lib/typescript/src/components/NitroPolyline.d.ts +84 -0
- package/lib/typescript/src/components/NitroPolyline.d.ts.map +1 -0
- package/lib/typescript/src/components/PriceMarker.d.ts +0 -5
- package/lib/typescript/src/components/PriceMarker.d.ts.map +1 -1
- package/lib/typescript/src/context/NitroMapContext.d.ts +2 -0
- package/lib/typescript/src/context/NitroMapContext.d.ts.map +1 -1
- package/lib/typescript/src/hooks/useNitroCircle.d.ts +7 -0
- package/lib/typescript/src/hooks/useNitroCircle.d.ts.map +1 -0
- package/lib/typescript/src/hooks/useNitroMarker.d.ts +20 -0
- package/lib/typescript/src/hooks/useNitroMarker.d.ts.map +1 -1
- package/lib/typescript/src/hooks/useNitroOverlay.d.ts +26 -0
- package/lib/typescript/src/hooks/useNitroOverlay.d.ts.map +1 -0
- package/lib/typescript/src/hooks/useNitroPolygon.d.ts +7 -0
- package/lib/typescript/src/hooks/useNitroPolygon.d.ts.map +1 -0
- package/lib/typescript/src/hooks/useNitroPolyline.d.ts +7 -0
- package/lib/typescript/src/hooks/useNitroPolyline.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +15 -2
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/specs/NitroMap.nitro.d.ts +248 -6
- package/lib/typescript/src/specs/NitroMap.nitro.d.ts.map +1 -1
- package/lib/typescript/src/types/map.d.ts +34 -4
- package/lib/typescript/src/types/map.d.ts.map +1 -1
- package/lib/typescript/src/types/marker.d.ts +24 -36
- package/lib/typescript/src/types/marker.d.ts.map +1 -1
- package/lib/typescript/src/types/overlay.d.ts +75 -0
- package/lib/typescript/src/types/overlay.d.ts.map +1 -0
- package/lib/typescript/src/types/theme.d.ts +93 -0
- package/lib/typescript/src/types/theme.d.ts.map +1 -0
- package/lib/typescript/src/utils/colors.d.ts +6 -8
- package/lib/typescript/src/utils/colors.d.ts.map +1 -1
- package/lib/typescript/src/utils/validation.d.ts +12 -0
- package/lib/typescript/src/utils/validation.d.ts.map +1 -0
- package/nitrogen/generated/android/c++/JCircleData.hpp +94 -0
- package/nitrogen/generated/android/c++/JClusterConfig.hpp +5 -7
- package/nitrogen/generated/android/c++/JFunc_void_UserLocationChangeEvent.hpp +79 -0
- package/nitrogen/generated/android/c++/JFunc_void_UserTrackingMode.hpp +77 -0
- package/nitrogen/generated/android/c++/JFunc_void_std__string.hpp +76 -0
- package/nitrogen/generated/android/c++/JHybridNitroMapSpec.cpp +328 -21
- package/nitrogen/generated/android/c++/JHybridNitroMapSpec.hpp +53 -2
- package/nitrogen/generated/android/c++/JMarkerAnimation.hpp +3 -6
- package/nitrogen/generated/android/c++/JMarkerData.hpp +15 -3
- package/nitrogen/generated/android/c++/JPolygonData.hpp +149 -0
- package/nitrogen/generated/android/c++/JPolylineData.hpp +113 -0
- package/nitrogen/generated/android/c++/JUserLocationChangeEvent.hpp +70 -0
- package/nitrogen/generated/android/c++/JUserTrackingMode.hpp +62 -0
- package/nitrogen/generated/android/c++/views/JHybridNitroMapStateUpdater.cpp +72 -4
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromap/CircleData.kt +62 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromap/ClusterConfig.kt +4 -4
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromap/Func_void_UserLocationChangeEvent.kt +80 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromap/Func_void_UserTrackingMode.kt +80 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromap/Func_void_std__string.kt +80 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromap/HybridNitroMapSpec.kt +228 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromap/MarkerAnimation.kt +1 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromap/MarkerData.kt +12 -3
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromap/PolygonData.kt +62 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromap/PolylineData.kt +62 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromap/UserLocationChangeEvent.kt +47 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromap/{ClusterAnimationStyle.kt → UserTrackingMode.kt} +6 -8
- package/nitrogen/generated/android/nitromapOnLoad.cpp +6 -0
- package/nitrogen/generated/ios/NitroMap-Swift-Cxx-Bridge.cpp +24 -0
- package/nitrogen/generated/ios/NitroMap-Swift-Cxx-Bridge.hpp +175 -17
- package/nitrogen/generated/ios/NitroMap-Swift-Cxx-Umbrella.hpp +15 -3
- package/nitrogen/generated/ios/c++/HybridNitroMapSpecSwift.hpp +249 -16
- package/nitrogen/generated/ios/c++/views/HybridNitroMapComponent.mm +90 -5
- package/nitrogen/generated/ios/swift/CircleData.swift +143 -0
- package/nitrogen/generated/ios/swift/ClusterConfig.swift +22 -15
- package/nitrogen/generated/ios/swift/Func_void_UserLocationChangeEvent.swift +47 -0
- package/nitrogen/generated/ios/swift/Func_void_UserTrackingMode.swift +47 -0
- package/nitrogen/generated/ios/swift/Func_void_std__string.swift +47 -0
- package/nitrogen/generated/ios/swift/HybridNitroMapSpec.swift +35 -1
- package/nitrogen/generated/ios/swift/HybridNitroMapSpec_cxx.swift +582 -8
- package/nitrogen/generated/ios/swift/MarkerAnimation.swift +4 -8
- package/nitrogen/generated/ios/swift/MarkerData.swift +54 -2
- package/nitrogen/generated/ios/swift/PolygonData.swift +179 -0
- package/nitrogen/generated/ios/swift/PolylineData.swift +155 -0
- package/nitrogen/generated/ios/swift/UserLocationChangeEvent.swift +69 -0
- package/nitrogen/generated/ios/swift/UserTrackingMode.swift +44 -0
- package/nitrogen/generated/shared/c++/CircleData.hpp +113 -0
- package/nitrogen/generated/shared/c++/ClusterConfig.hpp +5 -8
- package/nitrogen/generated/shared/c++/HybridNitroMapSpec.cpp +53 -2
- package/nitrogen/generated/shared/c++/HybridNitroMapSpec.hpp +75 -6
- package/nitrogen/generated/shared/c++/MarkerAnimation.hpp +4 -8
- package/nitrogen/generated/shared/c++/MarkerData.hpp +14 -2
- package/nitrogen/generated/shared/c++/PolygonData.hpp +114 -0
- package/nitrogen/generated/shared/c++/PolylineData.hpp +114 -0
- package/nitrogen/generated/shared/c++/UserLocationChangeEvent.hpp +88 -0
- package/nitrogen/generated/shared/c++/UserTrackingMode.hpp +80 -0
- package/nitrogen/generated/shared/c++/views/HybridNitroMapComponent.cpp +216 -12
- package/nitrogen/generated/shared/c++/views/HybridNitroMapComponent.hpp +23 -1
- package/nitrogen/generated/shared/json/NitroMapConfig.json +18 -1
- package/package.json +36 -5
- package/src/components/ImageMarker.tsx +58 -42
- package/src/components/Marker.tsx +161 -0
- package/src/components/NitroCircle.tsx +183 -0
- package/src/components/NitroMap.tsx +328 -78
- package/src/components/NitroPolygon.tsx +229 -0
- package/src/components/NitroPolyline.tsx +208 -0
- package/src/components/PriceMarker.tsx +23 -48
- package/src/context/NitroMapContext.tsx +4 -0
- package/src/hooks/useNitroCircle.ts +25 -0
- package/src/hooks/useNitroMarker.ts +49 -10
- package/src/hooks/useNitroOverlay.ts +68 -0
- package/src/hooks/useNitroPolygon.ts +25 -0
- package/src/hooks/useNitroPolyline.ts +25 -0
- package/src/index.tsx +23 -2
- package/src/specs/NitroMap.nitro.ts +294 -5
- package/src/types/map.ts +36 -4
- package/src/types/marker.ts +24 -44
- package/src/types/overlay.ts +77 -0
- package/src/types/theme.ts +101 -0
- package/src/utils/colors.ts +48 -16
- package/src/utils/validation.ts +69 -0
- package/android/src/main/java/com/margelo/nitro/nitromap/ClusterIconGenerator.kt +0 -108
- package/android/src/main/java/com/margelo/nitro/nitromap/ColorUtils.kt +0 -63
- package/android/src/main/java/com/margelo/nitro/nitromap/HybridNitroMap.kt +0 -408
- package/android/src/main/java/com/margelo/nitro/nitromap/HybridNitroMapConfig.kt +0 -68
- package/android/src/main/java/com/margelo/nitro/nitromap/MarkerIconCache.kt +0 -176
- package/android/src/main/java/com/margelo/nitro/nitromap/MarkerIconFactory.kt +0 -252
- package/android/src/main/java/com/margelo/nitro/nitromap/clustering/NitroClusterEngine.kt +0 -252
- package/android/src/main/java/com/margelo/nitro/nitromap/clustering/QuadTree.kt +0 -195
- package/android/src/main/java/com/margelo/nitro/nitromap/providers/GoogleMapProvider.kt +0 -912
- package/android/src/main/java/com/margelo/nitro/nitromap/providers/MapProviderInterface.kt +0 -70
- package/cpp/QuadTree.hpp +0 -246
- package/ios/NitroMapConfig/HybridNitroMapConfig.swift +0 -33
- package/ios/Providers/GoogleMapProvider+Camera.swift +0 -164
- package/ios/Providers/GoogleMapProvider.swift +0 -924
- package/nitrogen/generated/android/c++/JClusterAnimationStyle.hpp +0 -68
- package/nitrogen/generated/ios/swift/ClusterAnimationStyle.swift +0 -52
- package/nitrogen/generated/shared/c++/ClusterAnimationStyle.hpp +0 -88
|
@@ -0,0 +1,397 @@
|
|
|
1
|
+
package com.margelo.nitro.nitromap
|
|
2
|
+
|
|
3
|
+
import android.content.Context
|
|
4
|
+
import android.os.Handler
|
|
5
|
+
import android.os.Looper
|
|
6
|
+
import android.util.Log
|
|
7
|
+
import android.view.View
|
|
8
|
+
import android.widget.FrameLayout
|
|
9
|
+
import com.margelo.nitro.core.Promise
|
|
10
|
+
import com.margelo.nitro.nitromap.providers.MapProviderFactory
|
|
11
|
+
import com.margelo.nitro.nitromap.providers.MapProviderInterface
|
|
12
|
+
import java.util.concurrent.CountDownLatch
|
|
13
|
+
import java.util.concurrent.TimeUnit
|
|
14
|
+
import java.util.concurrent.atomic.AtomicReference
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* HybridNitroMap — Android map implementation for Nitro Modules.
|
|
18
|
+
*
|
|
19
|
+
* Provider-agnostic facade: delegates all map operations to a MapProviderInterface
|
|
20
|
+
* implementation created via MapProviderFactory. Currently supports Google Maps,
|
|
21
|
+
* with Apple Maps (N/A on Android) and Yandex Maps planned.
|
|
22
|
+
*
|
|
23
|
+
* Lifecycle:
|
|
24
|
+
* onViewAttachedToWindow → create provider MapView + init
|
|
25
|
+
* onViewDetachedFromWindow → pause MapView (DO NOT destroy — preserves state for navigation)
|
|
26
|
+
* dispose() → destroy MapView + full cleanup (only on actual unmount)
|
|
27
|
+
*
|
|
28
|
+
* Threading:
|
|
29
|
+
* Props from React render → UI Thread (safe)
|
|
30
|
+
* Props from hybridRef → may be JS Thread (dispatch to main)
|
|
31
|
+
* Methods from hybridRef → JS Thread (dispatch to main)
|
|
32
|
+
*/
|
|
33
|
+
class HybridNitroMap(context: Context) : HybridNitroMapSpec() {
|
|
34
|
+
|
|
35
|
+
companion object {
|
|
36
|
+
private const val TAG = "NitroMap"
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// MARK: - View
|
|
40
|
+
|
|
41
|
+
private val mapContext: Context = context
|
|
42
|
+
private val container = FrameLayout(context).apply {
|
|
43
|
+
clipChildren = false
|
|
44
|
+
clipToPadding = false
|
|
45
|
+
}
|
|
46
|
+
private val mainHandler = Handler(Looper.getMainLooper())
|
|
47
|
+
|
|
48
|
+
override val view: View get() = container
|
|
49
|
+
|
|
50
|
+
// MARK: - Provider + Lifecycle State
|
|
51
|
+
|
|
52
|
+
private val mapProvider: MapProviderInterface by lazy {
|
|
53
|
+
MapProviderFactory.create(provider ?: MapProvider.GOOGLE, mapContext)
|
|
54
|
+
}
|
|
55
|
+
private val locationManager = UserLocationManager(mapContext)
|
|
56
|
+
private var currentMapView: View? = null
|
|
57
|
+
@Volatile
|
|
58
|
+
private var isDisposed = false
|
|
59
|
+
|
|
60
|
+
init {
|
|
61
|
+
container.addOnAttachStateChangeListener(object : View.OnAttachStateChangeListener {
|
|
62
|
+
override fun onViewAttachedToWindow(v: View) {
|
|
63
|
+
if (!isDisposed) {
|
|
64
|
+
attachMapView()
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
override fun onViewDetachedFromWindow(v: View) {
|
|
69
|
+
detachMapView()
|
|
70
|
+
}
|
|
71
|
+
})
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
private fun attachMapView() {
|
|
75
|
+
if (currentMapView != null) return // already attached
|
|
76
|
+
|
|
77
|
+
val mv = mapProvider.createMapView(mapContext)
|
|
78
|
+
container.addView(mv, FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT)
|
|
79
|
+
|
|
80
|
+
if (!isDisposed) {
|
|
81
|
+
mapProvider.onViewAttached(mv)
|
|
82
|
+
}
|
|
83
|
+
currentMapView = mv
|
|
84
|
+
Log.d(TAG, "MapView attached")
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
private fun detachMapView() {
|
|
88
|
+
currentMapView?.let { mv ->
|
|
89
|
+
mapProvider.onViewDetaching()
|
|
90
|
+
container.removeView(mv)
|
|
91
|
+
}
|
|
92
|
+
currentMapView = null
|
|
93
|
+
Log.d(TAG, "MapView detached (paused, state saved)")
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
override fun dispose() {
|
|
97
|
+
isDisposed = true
|
|
98
|
+
locationManager.destroy()
|
|
99
|
+
currentMapView?.let { mv ->
|
|
100
|
+
mapProvider.onViewDestroying()
|
|
101
|
+
container.removeView(mv)
|
|
102
|
+
}
|
|
103
|
+
currentMapView = null
|
|
104
|
+
Log.d(TAG, "MapView disposed (destroyed)")
|
|
105
|
+
super.dispose()
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// MARK: - Properties (dispatch to mapProvider)
|
|
109
|
+
|
|
110
|
+
override var provider: MapProvider? = null
|
|
111
|
+
|
|
112
|
+
override var initialRegion: Region? = null
|
|
113
|
+
set(value) {
|
|
114
|
+
// Negative deltas = JS sentinel meaning "unset/cleared" (Fabric null workaround)
|
|
115
|
+
if (value != null && (value.latitudeDelta < 0 || value.longitudeDelta < 0)) return
|
|
116
|
+
field = value
|
|
117
|
+
mapProvider.initialRegion = value
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
override var region: Region? = null
|
|
121
|
+
set(value) {
|
|
122
|
+
// Negative deltas = JS sentinel meaning "unset/cleared" (Fabric null workaround)
|
|
123
|
+
if (value != null && (value.latitudeDelta < 0 || value.longitudeDelta < 0)) {
|
|
124
|
+
if (field == null) return // already cleared
|
|
125
|
+
field = null
|
|
126
|
+
mapProvider.region = null
|
|
127
|
+
return
|
|
128
|
+
}
|
|
129
|
+
// Skip if same value re-applied (Fabric re-commits all props on every
|
|
130
|
+
// cycle, unlike iOS which only calls didSet for changed props — without
|
|
131
|
+
// this guard, panning away from a controlled region snaps back)
|
|
132
|
+
if (field == value) return
|
|
133
|
+
field = value
|
|
134
|
+
mapProvider.region = value
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
override var showsUserLocation: Boolean? = null
|
|
138
|
+
set(value) {
|
|
139
|
+
val changed = field != value
|
|
140
|
+
field = value
|
|
141
|
+
mapProvider.showsUserLocation = value
|
|
142
|
+
if (value == true) {
|
|
143
|
+
locationManager.onLocationUpdate = { location, heading ->
|
|
144
|
+
mapProvider.updateUserLocation(location, heading)
|
|
145
|
+
onUserLocationChange?.invoke(
|
|
146
|
+
UserLocationChangeEvent(
|
|
147
|
+
Coordinate(location.latitude, location.longitude),
|
|
148
|
+
location.accuracy.toDouble(),
|
|
149
|
+
heading?.toDouble() ?: -1.0,
|
|
150
|
+
location.speed.toDouble()
|
|
151
|
+
)
|
|
152
|
+
)
|
|
153
|
+
}
|
|
154
|
+
locationManager.onLocationError = { code, message ->
|
|
155
|
+
onUserLocationError?.invoke(MapError(code, message))
|
|
156
|
+
}
|
|
157
|
+
locationManager.startUpdating()
|
|
158
|
+
// Only create the marker on actual change (not re-renders),
|
|
159
|
+
// otherwise it resets rotation to 0 and heading is lost on idle
|
|
160
|
+
if (changed) {
|
|
161
|
+
mapProvider.setupCustomUserLocationMarker(mapContext)
|
|
162
|
+
}
|
|
163
|
+
} else {
|
|
164
|
+
locationManager.stopUpdating()
|
|
165
|
+
mapProvider.disableUserLocation()
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
override var zoomEnabled: Boolean? = null
|
|
170
|
+
set(value) { field = value; mapProvider.zoomEnabled = value }
|
|
171
|
+
|
|
172
|
+
override var scrollEnabled: Boolean? = null
|
|
173
|
+
set(value) { field = value; mapProvider.scrollEnabled = value }
|
|
174
|
+
|
|
175
|
+
override var rotateEnabled: Boolean? = null
|
|
176
|
+
set(value) { field = value; mapProvider.rotateEnabled = value }
|
|
177
|
+
|
|
178
|
+
override var pitchEnabled: Boolean? = null
|
|
179
|
+
set(value) { field = value; mapProvider.pitchEnabled = value }
|
|
180
|
+
|
|
181
|
+
override var mapType: MapType? = null
|
|
182
|
+
set(value) { field = value; mapProvider.mapType = value }
|
|
183
|
+
|
|
184
|
+
override var customMapStyle: Array<MapStyleElement>? = null
|
|
185
|
+
set(value) { field = value; mapProvider.customMapStyle = value }
|
|
186
|
+
|
|
187
|
+
override var clusterConfig: ClusterConfig? = null
|
|
188
|
+
set(value) { field = value; mapProvider.clusterConfig = value }
|
|
189
|
+
|
|
190
|
+
override var mapPadding: EdgePadding = EdgePadding(0.0, 0.0, 0.0, 0.0)
|
|
191
|
+
set(value) { field = value; mapProvider.mapPadding = value }
|
|
192
|
+
|
|
193
|
+
override var showsTraffic: Boolean? = null
|
|
194
|
+
set(value) { field = value; mapProvider.showsTraffic = value }
|
|
195
|
+
|
|
196
|
+
override var showsBuildings: Boolean? = null
|
|
197
|
+
set(value) { field = value; mapProvider.showsBuildings = value }
|
|
198
|
+
|
|
199
|
+
override var showsCompass: Boolean? = null
|
|
200
|
+
set(value) { field = value; mapProvider.showsCompass = value }
|
|
201
|
+
|
|
202
|
+
// L-2: Align with iOS default (1.0, not 0.0)
|
|
203
|
+
override var minZoom: Double = 1.0
|
|
204
|
+
set(value) { field = value; mapProvider.minZoom = value }
|
|
205
|
+
|
|
206
|
+
override var maxZoom: Double = 22.0
|
|
207
|
+
set(value) { field = value; mapProvider.maxZoom = value }
|
|
208
|
+
|
|
209
|
+
override var darkMode: Boolean? = null
|
|
210
|
+
set(value) { field = value; mapProvider.darkMode = value }
|
|
211
|
+
|
|
212
|
+
override var userTrackingMode: UserTrackingMode? = null
|
|
213
|
+
set(value) { field = value; mapProvider.userTrackingMode = value }
|
|
214
|
+
|
|
215
|
+
override var userLocationImage: String = ""
|
|
216
|
+
set(value) {
|
|
217
|
+
if (field == value) return
|
|
218
|
+
field = value
|
|
219
|
+
mapProvider.userLocationImage = value
|
|
220
|
+
if (showsUserLocation == true) {
|
|
221
|
+
mapProvider.setupCustomUserLocationMarker(mapContext)
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
override var userLocationSize: Double = 0.0
|
|
226
|
+
set(value) {
|
|
227
|
+
if (field == value) return
|
|
228
|
+
field = value
|
|
229
|
+
mapProvider.userLocationSize = value
|
|
230
|
+
if (showsUserLocation == true) {
|
|
231
|
+
mapProvider.setupCustomUserLocationMarker(mapContext)
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
override var userLocationAnchor: Point? = null
|
|
236
|
+
set(value) { field = value; mapProvider.userLocationAnchor = value }
|
|
237
|
+
|
|
238
|
+
// MARK: - Callback Properties (wire directly to mapProvider)
|
|
239
|
+
|
|
240
|
+
override var onPress: ((event: MapPressEvent) -> Unit)? = null
|
|
241
|
+
set(value) { field = value; mapProvider.onPress = value }
|
|
242
|
+
|
|
243
|
+
override var onLongPress: ((event: MapPressEvent) -> Unit)? = null
|
|
244
|
+
set(value) { field = value; mapProvider.onLongPress = value }
|
|
245
|
+
|
|
246
|
+
override var onMapReady: (() -> Unit)? = null
|
|
247
|
+
set(value) { field = value; mapProvider.onMapReadyCallback = value }
|
|
248
|
+
|
|
249
|
+
override var onRegionChange: ((region: RegionChangeEvent) -> Unit)? = null
|
|
250
|
+
set(value) { field = value; mapProvider.onRegionChange = value }
|
|
251
|
+
|
|
252
|
+
override var onRegionChangeComplete: ((region: RegionChangeEvent) -> Unit)? = null
|
|
253
|
+
set(value) { field = value; mapProvider.onRegionChangeComplete = value }
|
|
254
|
+
|
|
255
|
+
override var onMarkerPress: ((event: MarkerPressEvent) -> Unit)? = null
|
|
256
|
+
set(value) { field = value; mapProvider.onMarkerPress = value }
|
|
257
|
+
|
|
258
|
+
override var onMarkerDragStart: ((event: MarkerDragEvent) -> Unit)? = null
|
|
259
|
+
set(value) { field = value; mapProvider.onMarkerDragStart = value }
|
|
260
|
+
|
|
261
|
+
override var onMarkerDrag: ((event: MarkerDragEvent) -> Unit)? = null
|
|
262
|
+
set(value) { field = value; mapProvider.onMarkerDrag = value }
|
|
263
|
+
|
|
264
|
+
override var onMarkerDragEnd: ((event: MarkerDragEvent) -> Unit)? = null
|
|
265
|
+
set(value) { field = value; mapProvider.onMarkerDragEnd = value }
|
|
266
|
+
|
|
267
|
+
override var onClusterPress: ((event: ClusterPressEvent) -> Unit)? = null
|
|
268
|
+
set(value) { field = value; mapProvider.onClusterPress = value }
|
|
269
|
+
|
|
270
|
+
override var onPolylinePress: ((id: String) -> Unit)? = null
|
|
271
|
+
set(value) { field = value; mapProvider.onPolylinePress = value }
|
|
272
|
+
|
|
273
|
+
override var onPolygonPress: ((id: String) -> Unit)? = null
|
|
274
|
+
set(value) { field = value; mapProvider.onPolygonPress = value }
|
|
275
|
+
|
|
276
|
+
override var onCirclePress: ((id: String) -> Unit)? = null
|
|
277
|
+
set(value) { field = value; mapProvider.onCirclePress = value }
|
|
278
|
+
|
|
279
|
+
override var onError: ((error: MapError) -> Unit)? = null
|
|
280
|
+
set(value) { field = value; mapProvider.onError = value }
|
|
281
|
+
|
|
282
|
+
override var onUserLocationChange: ((event: UserLocationChangeEvent) -> Unit)? = null
|
|
283
|
+
set(value) { field = value; mapProvider.onUserLocationChange = value }
|
|
284
|
+
|
|
285
|
+
override var onUserTrackingModeChange: ((mode: UserTrackingMode) -> Unit)? = null
|
|
286
|
+
set(value) { field = value; mapProvider.onUserTrackingModeChange = value }
|
|
287
|
+
|
|
288
|
+
override var onUserLocationError: ((error: MapError) -> Unit)? = null
|
|
289
|
+
set(value) { field = value; mapProvider.onUserLocationError = value }
|
|
290
|
+
|
|
291
|
+
override var onMapIdle: (() -> Unit)? = null
|
|
292
|
+
set(value) { field = value; mapProvider.onMapIdle = value }
|
|
293
|
+
|
|
294
|
+
// MARK: - Thread Dispatch Helper
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* Run a block on the main thread and return the result.
|
|
298
|
+
* If already on the main thread, executes directly.
|
|
299
|
+
* Otherwise, posts to mainHandler and waits with CountDownLatch.
|
|
300
|
+
*/
|
|
301
|
+
// C-2: Increased timeout to 10s and added graceful handling.
|
|
302
|
+
// Using indefinite await risks permanent JS thread block if main thread is dead.
|
|
303
|
+
// 10s is generous enough to survive heavy main-thread load without ANR (5s threshold).
|
|
304
|
+
private fun <T> runOnMainThread(caller: String = "unknown", block: () -> T): T {
|
|
305
|
+
if (Looper.myLooper() == Looper.getMainLooper()) return block()
|
|
306
|
+
val ref = AtomicReference<T>()
|
|
307
|
+
val errorRef = AtomicReference<Throwable>()
|
|
308
|
+
val latch = CountDownLatch(1)
|
|
309
|
+
mainHandler.post {
|
|
310
|
+
try {
|
|
311
|
+
ref.set(block())
|
|
312
|
+
} catch (e: Throwable) {
|
|
313
|
+
errorRef.set(e)
|
|
314
|
+
} finally {
|
|
315
|
+
latch.countDown()
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
val completed = latch.await(10, TimeUnit.SECONDS)
|
|
319
|
+
if (!completed) {
|
|
320
|
+
Log.w(TAG, "$caller: main thread dispatch timed out after 10s")
|
|
321
|
+
throw RuntimeException("NitroMap.$caller: main thread dispatch timed out after 10s")
|
|
322
|
+
}
|
|
323
|
+
errorRef.get()?.let { throw it }
|
|
324
|
+
return ref.get()
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
// MARK: - Methods (dispatch to mapProvider)
|
|
328
|
+
|
|
329
|
+
override fun animateToRegion(region: Region, duration: Double?) =
|
|
330
|
+
mapProvider.animateToRegion(region, duration)
|
|
331
|
+
|
|
332
|
+
override fun fitToCoordinates(coordinates: Array<Coordinate>, edgePadding: EdgePadding?, animated: Boolean?) =
|
|
333
|
+
mapProvider.fitToCoordinates(coordinates, edgePadding, animated)
|
|
334
|
+
|
|
335
|
+
override fun fitToSuppliedMarkers(markerIds: Array<String>, edgePadding: EdgePadding?, animated: Boolean?) =
|
|
336
|
+
mapProvider.fitToSuppliedMarkers(markerIds, edgePadding, animated)
|
|
337
|
+
|
|
338
|
+
override fun animateCamera(camera: Camera, duration: Double?) =
|
|
339
|
+
mapProvider.animateCamera(camera, duration)
|
|
340
|
+
|
|
341
|
+
override fun getCamera(): Promise<Camera> = Promise.async {
|
|
342
|
+
runOnMainThread("getCamera") { mapProvider.getCamera() }
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
override fun setCamera(camera: Camera) = mapProvider.setCamera(camera)
|
|
346
|
+
|
|
347
|
+
override fun setMapStyle(style: Array<MapStyleElement>?) { customMapStyle = style }
|
|
348
|
+
|
|
349
|
+
override fun getMapBoundaries(): Promise<MapBoundaries> = Promise.async {
|
|
350
|
+
runOnMainThread("getMapBoundaries") {
|
|
351
|
+
mapProvider.getMapBoundaries() ?: MapBoundaries(Coordinate(0.0, 0.0), Coordinate(0.0, 0.0))
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
override fun centerOnUserLocation() = mapProvider.centerOnUserLocation()
|
|
356
|
+
|
|
357
|
+
override fun pointForCoordinate(coordinate: Coordinate): Point =
|
|
358
|
+
runOnMainThread("pointForCoordinate") { mapProvider.pointForCoordinate(coordinate) }
|
|
359
|
+
|
|
360
|
+
override fun coordinateForPoint(point: Point): Coordinate =
|
|
361
|
+
runOnMainThread("coordinateForPoint") { mapProvider.coordinateForPoint(point) }
|
|
362
|
+
|
|
363
|
+
override fun setIsDarkMode(enabled: Boolean) { darkMode = enabled }
|
|
364
|
+
|
|
365
|
+
// MARK: - Marker Methods (Batch 5)
|
|
366
|
+
// C-1/C-2: All mutating methods dispatch to main thread to match iOS DispatchQueue.main.async.
|
|
367
|
+
// These methods return Unit so fire-and-forget via mainHandler.post is safe.
|
|
368
|
+
override fun addMarker(marker: MarkerData) { mainHandler.post { mapProvider.addMarker(marker) } }
|
|
369
|
+
override fun addMarkers(markers: Array<MarkerData>) { mainHandler.post { mapProvider.addMarkers(markers) } }
|
|
370
|
+
override fun updateMarker(marker: MarkerData) { mainHandler.post { mapProvider.updateMarker(marker) } }
|
|
371
|
+
override fun removeMarker(id: String) { mainHandler.post { mapProvider.removeMarker(id) } }
|
|
372
|
+
override fun selectMarker(id: String) { mainHandler.post { mapProvider.selectMarker(id) } }
|
|
373
|
+
override fun deselectMarker() { mainHandler.post { mapProvider.deselectMarker() } }
|
|
374
|
+
override fun clearMarkers() { mainHandler.post { mapProvider.clearMarkers() } }
|
|
375
|
+
|
|
376
|
+
|
|
377
|
+
// MARK: - Clustering Methods
|
|
378
|
+
override fun setClusteringEnabled(enabled: Boolean) { mainHandler.post { mapProvider.setClusteringEnabled(enabled) } }
|
|
379
|
+
override fun refreshClusters() { mainHandler.post { mapProvider.refreshClusters() } }
|
|
380
|
+
|
|
381
|
+
// MARK: - Overlay Methods (Polyline, Polygon, Circle)
|
|
382
|
+
override fun addPolyline(polyline: PolylineData) { mainHandler.post { mapProvider.addPolyline(polyline) } }
|
|
383
|
+
override fun updatePolyline(polyline: PolylineData) { mainHandler.post { mapProvider.updatePolyline(polyline) } }
|
|
384
|
+
override fun removePolyline(id: String) { mainHandler.post { mapProvider.removePolyline(id) } }
|
|
385
|
+
override fun clearPolylines() { mainHandler.post { mapProvider.clearPolylines() } }
|
|
386
|
+
override fun addPolygon(polygon: PolygonData) { mainHandler.post { mapProvider.addPolygon(polygon) } }
|
|
387
|
+
override fun updatePolygon(polygon: PolygonData) { mainHandler.post { mapProvider.updatePolygon(polygon) } }
|
|
388
|
+
override fun removePolygon(id: String) { mainHandler.post { mapProvider.removePolygon(id) } }
|
|
389
|
+
override fun clearPolygons() { mainHandler.post { mapProvider.clearPolygons() } }
|
|
390
|
+
override fun addCircle(circle: CircleData) { mainHandler.post { mapProvider.addCircle(circle) } }
|
|
391
|
+
override fun updateCircle(circle: CircleData) { mainHandler.post { mapProvider.updateCircle(circle) } }
|
|
392
|
+
override fun removeCircle(id: String) { mainHandler.post { mapProvider.removeCircle(id) } }
|
|
393
|
+
override fun clearCircles() { mainHandler.post { mapProvider.clearCircles() } }
|
|
394
|
+
|
|
395
|
+
override val memorySize: Long
|
|
396
|
+
get() = 0L
|
|
397
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
package com.margelo.nitro.nitromap
|
|
2
|
+
|
|
3
|
+
import android.util.Log
|
|
4
|
+
import com.google.android.gms.maps.MapsInitializer
|
|
5
|
+
import com.margelo.nitro.NitroModules
|
|
6
|
+
|
|
7
|
+
class HybridNitroMapConfig : HybridNitroMapConfigSpec() {
|
|
8
|
+
|
|
9
|
+
companion object {
|
|
10
|
+
private var isInitialized = false
|
|
11
|
+
/** The provider that was initialized. Used for consistency validation. */
|
|
12
|
+
var initializedProvider: MapProvider? = null
|
|
13
|
+
private set
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
override fun NitroMapInitialize(apiKey: String, provider: MapProvider) {
|
|
17
|
+
if (isInitialized) {
|
|
18
|
+
Log.d("NitroMap", "Already initialized, skipping...")
|
|
19
|
+
return
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
when (provider) {
|
|
23
|
+
MapProvider.GOOGLE -> {
|
|
24
|
+
try {
|
|
25
|
+
// On Android, the API key is read from AndroidManifest.xml <meta-data>
|
|
26
|
+
// at build time — not passed at runtime like iOS.
|
|
27
|
+
val context = NitroModules.applicationContext
|
|
28
|
+
?: throw IllegalStateException("Application context not available")
|
|
29
|
+
MapsInitializer.initialize(context)
|
|
30
|
+
isInitialized = true
|
|
31
|
+
initializedProvider = provider
|
|
32
|
+
Log.d("NitroMap", "Google Maps initialized")
|
|
33
|
+
} catch (e: Exception) {
|
|
34
|
+
Log.e("NitroMap", "Failed to initialize Google Maps: ${e.message}")
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
MapProvider.APPLE -> {
|
|
38
|
+
Log.e("NitroMap", "Apple Maps is not available on Android")
|
|
39
|
+
}
|
|
40
|
+
MapProvider.YANDEX -> {
|
|
41
|
+
// Future: YandexMapKit initialization with apiKey
|
|
42
|
+
Log.e("NitroMap", "Yandex Maps is not yet implemented")
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
override fun IsNitroMapInitialized(): Boolean {
|
|
48
|
+
return isInitialized
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
override val memorySize: Long
|
|
52
|
+
get() = 0L
|
|
53
|
+
}
|
|
@@ -8,10 +8,12 @@ import com.facebook.react.uimanager.ViewManager
|
|
|
8
8
|
|
|
9
9
|
import com.margelo.nitro.nitromap.views.HybridNitroMapManager
|
|
10
10
|
|
|
11
|
+
/**
|
|
12
|
+
* React Native Package for NitroMap.
|
|
13
|
+
* Registers the ViewManager and loads the native C++ library.
|
|
14
|
+
*/
|
|
11
15
|
class NitroMapPackage : BaseReactPackage() {
|
|
12
16
|
override fun getModule(name: String, reactContext: ReactApplicationContext): NativeModule? {
|
|
13
|
-
// Set context for HybridNitroMapConfig on first module access
|
|
14
|
-
HybridNitroMapConfig.setContext(reactContext)
|
|
15
17
|
return null
|
|
16
18
|
}
|
|
17
19
|
|
|
@@ -20,8 +22,6 @@ class NitroMapPackage : BaseReactPackage() {
|
|
|
20
22
|
}
|
|
21
23
|
|
|
22
24
|
override fun createViewManagers(reactContext: ReactApplicationContext): List<ViewManager<*, *>> {
|
|
23
|
-
// Set context for HybridNitroMapConfig
|
|
24
|
-
HybridNitroMapConfig.setContext(reactContext)
|
|
25
25
|
return listOf(HybridNitroMapManager())
|
|
26
26
|
}
|
|
27
27
|
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
package com.margelo.nitro.nitromap
|
|
2
|
+
|
|
3
|
+
import android.content.Context
|
|
4
|
+
import android.view.Choreographer
|
|
5
|
+
import android.view.View
|
|
6
|
+
import android.view.ViewGroup
|
|
7
|
+
import com.google.android.gms.maps.MapView
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Custom MapView subclass that fixes two Fabric layout issues:
|
|
11
|
+
*
|
|
12
|
+
* 1. **Viewport clipping**: When GoogleMap.setPadding() is called, the SDK internally
|
|
13
|
+
* calls View.setPadding() on this MapView. In Fabric, that View-level padding
|
|
14
|
+
* causes the viewport to shrink/clip. We block it here.
|
|
15
|
+
*
|
|
16
|
+
* 2. **Controls not measured**: In Fabric, requestLayout() is intercepted by Yoga,
|
|
17
|
+
* so when the compass transitions INVISIBLE→VISIBLE, it never gets re-measured
|
|
18
|
+
* (stays 0x0). We use Choreographer to force a manual layout pass whenever
|
|
19
|
+
* requestLayout is called, ensuring all internal SDK views get measured.
|
|
20
|
+
*/
|
|
21
|
+
class NitroMapView(context: Context) : MapView(context) {
|
|
22
|
+
|
|
23
|
+
// Flag to track if construction is complete (requestLayout is called
|
|
24
|
+
// during super constructor before our fields are initialized)
|
|
25
|
+
private var isConstructed = false
|
|
26
|
+
|
|
27
|
+
private var layoutRequested = false
|
|
28
|
+
|
|
29
|
+
private val layoutCallback = Choreographer.FrameCallback {
|
|
30
|
+
layoutRequested = false
|
|
31
|
+
// Manually measure and layout this view and all children.
|
|
32
|
+
// Fabric's Yoga sets our dimensions, so we use them as-is.
|
|
33
|
+
if (width > 0 && height > 0) {
|
|
34
|
+
measure(
|
|
35
|
+
MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
|
|
36
|
+
MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY)
|
|
37
|
+
)
|
|
38
|
+
layout(left, top, right, bottom)
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
init {
|
|
43
|
+
isConstructed = true
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Block View-level padding changes.
|
|
48
|
+
* GoogleMap.setPadding() internally calls this, which in Fabric causes
|
|
49
|
+
* the viewport to shrink. The SDK still positions controls (compass, logo)
|
|
50
|
+
* via their own LayoutParams using the stored GoogleMap padding values.
|
|
51
|
+
*/
|
|
52
|
+
override fun setPadding(left: Int, top: Int, right: Int, bottom: Int) {
|
|
53
|
+
// Intentionally blocked — prevents Fabric viewport shrinking
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Override requestLayout to schedule a manual layout pass via Choreographer.
|
|
58
|
+
* In Fabric, the default requestLayout() is intercepted by Yoga and may not
|
|
59
|
+
* trigger a real measure/layout pass for this view's children. By using
|
|
60
|
+
* Choreographer, we ensure internal SDK views (compass, logo, etc.) get
|
|
61
|
+
* measured when they change visibility or position.
|
|
62
|
+
*/
|
|
63
|
+
override fun requestLayout() {
|
|
64
|
+
super.requestLayout()
|
|
65
|
+
// Guard: skip during super constructor (fields not yet initialized)
|
|
66
|
+
if (!isConstructed) return
|
|
67
|
+
// Avoid scheduling multiple callbacks per frame
|
|
68
|
+
if (!layoutRequested) {
|
|
69
|
+
layoutRequested = true
|
|
70
|
+
Choreographer.getInstance().postFrameCallback(layoutCallback)
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|