@maydon_tech/react-native-nitro-maps 0.1.3 → 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/Clustering/ClusterIconRenderer.swift +3 -3
- 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
package/android/src/main/kotlin/com/margelo/nitro/nitromap/providers/google/GoogleMapDelegate.kt
ADDED
|
@@ -0,0 +1,317 @@
|
|
|
1
|
+
package com.margelo.nitro.nitromap.providers.google
|
|
2
|
+
|
|
3
|
+
import android.util.Log
|
|
4
|
+
import com.google.android.gms.maps.GoogleMap
|
|
5
|
+
import com.google.android.gms.maps.model.LatLng
|
|
6
|
+
import com.margelo.nitro.nitromap.*
|
|
7
|
+
import kotlin.math.sqrt
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Sets up all GoogleMap listeners and routes events to the provider's callbacks.
|
|
11
|
+
*
|
|
12
|
+
* Uses SDK's OnCameraMoveStartedListener.REASON_* constants to distinguish
|
|
13
|
+
* user gestures from programmatic camera moves — prevents region prop infinite loops.
|
|
14
|
+
*/
|
|
15
|
+
class GoogleMapDelegate(private val provider: GoogleMapProvider) {
|
|
16
|
+
|
|
17
|
+
companion object {
|
|
18
|
+
private const val TAG = "NitroMap"
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
private var cameraMoveReason = -1
|
|
22
|
+
private var isGesture = false
|
|
23
|
+
|
|
24
|
+
fun setupListeners(map: GoogleMap) {
|
|
25
|
+
setupCameraListeners(map)
|
|
26
|
+
setupTapListeners(map)
|
|
27
|
+
setupMarkerListeners(map)
|
|
28
|
+
setupOverlayListeners(map)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// MARK: - Camera Listeners
|
|
32
|
+
|
|
33
|
+
private fun setupCameraListeners(map: GoogleMap) {
|
|
34
|
+
map.setOnCameraMoveStartedListener { reason ->
|
|
35
|
+
cameraMoveReason = reason
|
|
36
|
+
isGesture = reason == GoogleMap.OnCameraMoveStartedListener.REASON_GESTURE
|
|
37
|
+
|
|
38
|
+
val reasonStr = when (reason) {
|
|
39
|
+
GoogleMap.OnCameraMoveStartedListener.REASON_GESTURE -> "GESTURE"
|
|
40
|
+
GoogleMap.OnCameraMoveStartedListener.REASON_API_ANIMATION -> "API_ANIMATION"
|
|
41
|
+
GoogleMap.OnCameraMoveStartedListener.REASON_DEVELOPER_ANIMATION -> "DEVELOPER_ANIMATION"
|
|
42
|
+
else -> "UNKNOWN($reason)"
|
|
43
|
+
}
|
|
44
|
+
Log.d(TAG, "onCameraMoveStarted reason=$reasonStr isGesture=$isGesture")
|
|
45
|
+
|
|
46
|
+
// Auto-break tracking mode on user gesture
|
|
47
|
+
if (isGesture) {
|
|
48
|
+
val mode = provider.userTrackingMode
|
|
49
|
+
if (mode != null && mode != UserTrackingMode.NONE) {
|
|
50
|
+
provider.userTrackingMode = UserTrackingMode.NONE
|
|
51
|
+
provider.onUserTrackingModeChange?.invoke(UserTrackingMode.NONE)
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Fire onRegionChange (live, during movement)
|
|
56
|
+
val event = RegionChangeEvent(
|
|
57
|
+
region = provider.getCurrentRegion(),
|
|
58
|
+
isGesture = isGesture
|
|
59
|
+
)
|
|
60
|
+
provider.onRegionChange?.invoke(event)
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Continuous camera updates — throttled clustering for realtime mode
|
|
64
|
+
// M-7: Also fire onRegionChange continuously (matching iOS didChange position)
|
|
65
|
+
map.setOnCameraMoveListener {
|
|
66
|
+
if (provider.clusterConfig?.realtimeClustering == true) {
|
|
67
|
+
provider.performClusteringThrottled()
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// M-7: Fire onRegionChange during movement (not just at start)
|
|
71
|
+
val event = RegionChangeEvent(
|
|
72
|
+
region = provider.getCurrentRegion(),
|
|
73
|
+
isGesture = isGesture
|
|
74
|
+
)
|
|
75
|
+
provider.onRegionChange?.invoke(event)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
map.setOnCameraIdleListener {
|
|
79
|
+
val region = provider.getCurrentRegion()
|
|
80
|
+
val event = RegionChangeEvent(
|
|
81
|
+
region = region,
|
|
82
|
+
isGesture = isGesture
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
Log.d(TAG, "onCameraIdle lat=${String.format("%.4f", region.latitude)} lng=${String.format("%.4f", region.longitude)} isGesture=$isGesture")
|
|
86
|
+
|
|
87
|
+
// Fire onRegionChangeComplete (with isGesture for consumer filtering)
|
|
88
|
+
provider.onRegionChangeComplete?.invoke(event)
|
|
89
|
+
|
|
90
|
+
// Skip clustering when the camera was moved programmatically for
|
|
91
|
+
// user location following — zoom hasn't changed so cluster results
|
|
92
|
+
// are identical. This prevents a performance cascade with 3000+ markers
|
|
93
|
+
// where heading updates → camera animation → onCameraIdle → performClustering
|
|
94
|
+
// would saturate the main thread.
|
|
95
|
+
// M-3: Only skip if markers haven't changed since last cluster run.
|
|
96
|
+
if (provider.isFollowingUserCamera && !provider.clusteringDirty) {
|
|
97
|
+
provider.isFollowingUserCamera = false
|
|
98
|
+
} else {
|
|
99
|
+
provider.isFollowingUserCamera = false
|
|
100
|
+
provider.performClustering()
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Always fire onMapIdle
|
|
104
|
+
provider.onMapIdle?.invoke()
|
|
105
|
+
|
|
106
|
+
// Reset gesture tracking
|
|
107
|
+
isGesture = false
|
|
108
|
+
cameraMoveReason = -1
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// MARK: - Proximity Cluster Detection
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* H-4: Check if a tap coordinate is near any rendered cluster marker.
|
|
116
|
+
* Mirrors iOS findNearbyCluster(at:in:).
|
|
117
|
+
* Returns the closest cluster marker within 60dp, or null.
|
|
118
|
+
*/
|
|
119
|
+
private fun findNearbyCluster(latLng: LatLng, map: GoogleMap): com.google.android.gms.maps.model.Marker? {
|
|
120
|
+
val tapPoint = map.projection.toScreenLocation(latLng)
|
|
121
|
+
val proximityThreshold = 60.0
|
|
122
|
+
|
|
123
|
+
var closestMarker: com.google.android.gms.maps.model.Marker? = null
|
|
124
|
+
var closestDistance = Double.MAX_VALUE
|
|
125
|
+
|
|
126
|
+
for (clusterMarker in provider.renderedClusterMarkers) {
|
|
127
|
+
val markerPoint = map.projection.toScreenLocation(clusterMarker.position)
|
|
128
|
+
val dx = (tapPoint.x - markerPoint.x).toDouble()
|
|
129
|
+
val dy = (tapPoint.y - markerPoint.y).toDouble()
|
|
130
|
+
val distance = sqrt(dx * dx + dy * dy)
|
|
131
|
+
|
|
132
|
+
if (distance < proximityThreshold && distance < closestDistance) {
|
|
133
|
+
closestDistance = distance
|
|
134
|
+
closestMarker = clusterMarker
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
return closestMarker
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* H-4: Fire onClusterPress for a cluster marker.
|
|
143
|
+
*/
|
|
144
|
+
private fun fireClusterPress(marker: com.google.android.gms.maps.model.Marker) {
|
|
145
|
+
val tag = marker.tag as? MarkerTagData.Cluster ?: return
|
|
146
|
+
provider.onClusterPress?.invoke(
|
|
147
|
+
ClusterPressEvent(
|
|
148
|
+
coordinate = Coordinate(
|
|
149
|
+
latitude = marker.position.latitude,
|
|
150
|
+
longitude = marker.position.longitude
|
|
151
|
+
),
|
|
152
|
+
markerIds = tag.markerIds.toTypedArray(),
|
|
153
|
+
count = tag.count.toDouble()
|
|
154
|
+
)
|
|
155
|
+
)
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// MARK: - Tap Listeners
|
|
159
|
+
|
|
160
|
+
private fun setupTapListeners(map: GoogleMap) {
|
|
161
|
+
map.setOnMapClickListener { latLng ->
|
|
162
|
+
// H-4: Proximity-based cluster tap fallback (matches iOS)
|
|
163
|
+
val nearbyCluster = findNearbyCluster(latLng, map)
|
|
164
|
+
if (nearbyCluster != null) {
|
|
165
|
+
fireClusterPress(nearbyCluster)
|
|
166
|
+
return@setOnMapClickListener
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
Log.d(TAG, "onPress lat=${String.format("%.4f", latLng.latitude)} lng=${String.format("%.4f", latLng.longitude)}")
|
|
170
|
+
val point = map.projection.toScreenLocation(latLng)
|
|
171
|
+
val event = MapPressEvent(
|
|
172
|
+
coordinate = Coordinate(
|
|
173
|
+
latitude = latLng.latitude,
|
|
174
|
+
longitude = latLng.longitude
|
|
175
|
+
),
|
|
176
|
+
position = com.margelo.nitro.nitromap.Point(
|
|
177
|
+
x = point.x.toDouble(),
|
|
178
|
+
y = point.y.toDouble()
|
|
179
|
+
)
|
|
180
|
+
)
|
|
181
|
+
provider.onPress?.invoke(event)
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
map.setOnMapLongClickListener { latLng ->
|
|
185
|
+
Log.d(TAG, "onLongPress lat=${String.format("%.4f", latLng.latitude)} lng=${String.format("%.4f", latLng.longitude)}")
|
|
186
|
+
val point = map.projection.toScreenLocation(latLng)
|
|
187
|
+
val event = MapPressEvent(
|
|
188
|
+
coordinate = Coordinate(
|
|
189
|
+
latitude = latLng.latitude,
|
|
190
|
+
longitude = latLng.longitude
|
|
191
|
+
),
|
|
192
|
+
position = com.margelo.nitro.nitromap.Point(
|
|
193
|
+
x = point.x.toDouble(),
|
|
194
|
+
y = point.y.toDouble()
|
|
195
|
+
)
|
|
196
|
+
)
|
|
197
|
+
provider.onLongPress?.invoke(event)
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// POI tap — fire onPress (matches iOS didTapPOI behavior)
|
|
201
|
+
map.setOnPoiClickListener { poi ->
|
|
202
|
+
Log.d(TAG, "onPoiClick name=${poi.name}")
|
|
203
|
+
val point = map.projection.toScreenLocation(poi.latLng)
|
|
204
|
+
val event = MapPressEvent(
|
|
205
|
+
coordinate = Coordinate(
|
|
206
|
+
latitude = poi.latLng.latitude,
|
|
207
|
+
longitude = poi.latLng.longitude
|
|
208
|
+
),
|
|
209
|
+
position = com.margelo.nitro.nitromap.Point(
|
|
210
|
+
x = point.x.toDouble(),
|
|
211
|
+
y = point.y.toDouble()
|
|
212
|
+
)
|
|
213
|
+
)
|
|
214
|
+
provider.onPress?.invoke(event)
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// MARK: - Marker Listeners
|
|
219
|
+
|
|
220
|
+
private fun setupMarkerListeners(map: GoogleMap) {
|
|
221
|
+
map.setOnMarkerClickListener { marker ->
|
|
222
|
+
when (val tag = marker.tag as? MarkerTagData) {
|
|
223
|
+
is MarkerTagData.Cluster -> {
|
|
224
|
+
provider.onClusterPress?.invoke(
|
|
225
|
+
ClusterPressEvent(
|
|
226
|
+
coordinate = Coordinate(
|
|
227
|
+
latitude = marker.position.latitude,
|
|
228
|
+
longitude = marker.position.longitude
|
|
229
|
+
),
|
|
230
|
+
markerIds = tag.markerIds.toTypedArray(),
|
|
231
|
+
count = tag.count.toDouble()
|
|
232
|
+
)
|
|
233
|
+
)
|
|
234
|
+
true
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
is MarkerTagData.Regular -> {
|
|
238
|
+
provider.onMarkerPress?.invoke(
|
|
239
|
+
MarkerPressEvent(
|
|
240
|
+
id = tag.markerId,
|
|
241
|
+
coordinate = Coordinate(
|
|
242
|
+
latitude = marker.position.latitude,
|
|
243
|
+
longitude = marker.position.longitude
|
|
244
|
+
)
|
|
245
|
+
)
|
|
246
|
+
)
|
|
247
|
+
true
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
is MarkerTagData.UserLocation, null -> false
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
map.setOnMarkerDragListener(object : GoogleMap.OnMarkerDragListener {
|
|
255
|
+
override fun onMarkerDragStart(marker: com.google.android.gms.maps.model.Marker) {
|
|
256
|
+
val tag = marker.tag as? MarkerTagData.Regular ?: return
|
|
257
|
+
provider.onMarkerDragStart?.invoke(
|
|
258
|
+
MarkerDragEvent(
|
|
259
|
+
id = tag.markerId,
|
|
260
|
+
coordinate = Coordinate(marker.position.latitude, marker.position.longitude)
|
|
261
|
+
)
|
|
262
|
+
)
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
override fun onMarkerDrag(marker: com.google.android.gms.maps.model.Marker) {
|
|
266
|
+
val tag = marker.tag as? MarkerTagData.Regular ?: return
|
|
267
|
+
provider.onMarkerDrag?.invoke(
|
|
268
|
+
MarkerDragEvent(
|
|
269
|
+
id = tag.markerId,
|
|
270
|
+
coordinate = Coordinate(marker.position.latitude, marker.position.longitude)
|
|
271
|
+
)
|
|
272
|
+
)
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
override fun onMarkerDragEnd(marker: com.google.android.gms.maps.model.Marker) {
|
|
276
|
+
val tag = marker.tag as? MarkerTagData.Regular ?: return
|
|
277
|
+
provider.onMarkerDragEnd?.invoke(
|
|
278
|
+
MarkerDragEvent(
|
|
279
|
+
id = tag.markerId,
|
|
280
|
+
coordinate = Coordinate(marker.position.latitude, marker.position.longitude)
|
|
281
|
+
)
|
|
282
|
+
)
|
|
283
|
+
}
|
|
284
|
+
})
|
|
285
|
+
|
|
286
|
+
// Info window close — fully revert marker visual state
|
|
287
|
+
// When the info window is closed (user tap on map, SDK auto-close, etc.),
|
|
288
|
+
// we must revert the icon — not just clear selectedMarkerId.
|
|
289
|
+
// If deselectCurrentMarker() already ran (programmatic deselect),
|
|
290
|
+
// selectedMarkerId is already null and this is a no-op.
|
|
291
|
+
map.setOnInfoWindowCloseListener { marker ->
|
|
292
|
+
val tag = marker.tag as? MarkerTagData.Regular ?: return@setOnInfoWindowCloseListener
|
|
293
|
+
if (provider.selectedMarkerId == tag.markerId) {
|
|
294
|
+
provider.deselectCurrentMarker()
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
// MARK: - Overlay Listeners
|
|
300
|
+
|
|
301
|
+
private fun setupOverlayListeners(map: GoogleMap) {
|
|
302
|
+
map.setOnPolylineClickListener { polyline ->
|
|
303
|
+
val id = polyline.tag as? String ?: return@setOnPolylineClickListener
|
|
304
|
+
provider.onPolylinePress?.invoke(id)
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
map.setOnPolygonClickListener { polygon ->
|
|
308
|
+
val id = polygon.tag as? String ?: return@setOnPolygonClickListener
|
|
309
|
+
provider.onPolygonPress?.invoke(id)
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
map.setOnCircleClickListener { circle ->
|
|
313
|
+
val id = circle.tag as? String ?: return@setOnCircleClickListener
|
|
314
|
+
provider.onCirclePress?.invoke(id)
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
}
|