Skip to content

Commit

Permalink
fix: fixed issue when multiple marker managers have been added, for i…
Browse files Browse the repository at this point in the history
…nstance in multiple clustering (#396)

* fix: fixed issue when multiple marker managers have been added, for instance in multiple clustering
  • Loading branch information
kikoso authored Sep 14, 2023
1 parent dc743a2 commit ff3f98b
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 21 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,7 @@ fun GoogleMapView(
onClick = markerClick
)
MarkerComposable(
title = "Marker Composable",
keys = arrayOf("singapore4"),
state = singapore4State,
onClick = markerClick,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import kotlinx.coroutines.launch
* @param clusterContent an optional Composable that is rendered for each [Cluster].
* @param clusterItemContent an optional Composable that is rendered for each non-clustered item.
*/

@Composable
@GoogleMapComposable
@MapsComposeExperimentalApi
Expand All @@ -52,8 +53,8 @@ public fun <T : ClusterItem> Clustering(
clusterContent: @[UiComposable Composable] ((Cluster<T>) -> Unit)? = null,
clusterItemContent: @[UiComposable Composable] ((T) -> Unit)? = null,
) {
val clusterManager = rememberClusterManager(clusterContent, clusterItemContent) ?: return

val clusterManager = rememberClusterManager(clusterContent, clusterItemContent) ?: return
ResetMapListeners(clusterManager)
SideEffect {
clusterManager.setOnClusterClickListener(onClusterClick)
Expand All @@ -62,8 +63,8 @@ public fun <T : ClusterItem> Clustering(
clusterManager.setOnClusterItemInfoWindowLongClickListener(onClusterItemInfoWindowLongClick)
}
InputHandler(
onMarkerClick = clusterManager::onMarkerClick,
onInfoWindowClick = clusterManager::onInfoWindowClick,
onMarkerClick = clusterManager.markerManager::onMarkerClick,
onInfoWindowClick = clusterManager.markerManager::onInfoWindowClick,
onInfoWindowLongClick = clusterManager.markerManager::onInfoWindowLongClick,
onMarkerDrag = clusterManager.markerManager::onMarkerDrag,
onMarkerDragEnd = clusterManager.markerManager::onMarkerDragEnd,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,61 +72,69 @@ internal class MapApplier(
map.setOnCircleClickListener { circle ->
decorations.findInputCallback<CircleNode, Circle, Unit>(
nodeMatchPredicate = { it.circle == circle },
marker = circle,
nodeInputCallback = { onCircleClick },
inputHandlerCallback = { onCircleClick }
)?.invoke(circle)
)
}
map.setOnGroundOverlayClickListener { groundOverlay ->
decorations.findInputCallback<GroundOverlayNode, GroundOverlay, Unit>(
nodeMatchPredicate = { it.groundOverlay == groundOverlay },
nodeInputCallback = { onGroundOverlayClick },
marker = groundOverlay,
inputHandlerCallback = { onGroundOverlayClick }
)?.invoke(groundOverlay)
)
}
map.setOnPolygonClickListener { polygon ->
decorations.findInputCallback<PolygonNode, Polygon, Unit>(
nodeMatchPredicate = { it.polygon == polygon },
nodeInputCallback = { onPolygonClick },
marker = polygon,
inputHandlerCallback = { onPolygonClick }
)?.invoke(polygon)
)
}
map.setOnPolylineClickListener { polyline ->
decorations.findInputCallback<PolylineNode, Polyline, Unit>(
nodeMatchPredicate = { it.polyline == polyline },
nodeInputCallback = { onPolylineClick },
marker = polyline,
inputHandlerCallback = { onPolylineClick }
)?.invoke(polyline)
)
}

// Marker
map.setOnMarkerClickListener { marker ->
decorations.findInputCallback<MarkerNode, Marker, Boolean>(
nodeMatchPredicate = { it.marker == marker },
marker = marker,
nodeInputCallback = { onMarkerClick },
inputHandlerCallback = { onMarkerClick }
)?.invoke(marker)
)
?: false
}
map.setOnInfoWindowClickListener { marker ->
decorations.findInputCallback<MarkerNode, Marker, Unit>(
nodeMatchPredicate = { it.marker == marker },
marker = marker,
nodeInputCallback = { onInfoWindowClick },
inputHandlerCallback = { onInfoWindowClick }
)?.invoke(marker)
)
}
map.setOnInfoWindowCloseListener { marker ->
decorations.findInputCallback<MarkerNode, Marker, Unit>(
nodeMatchPredicate = { it.marker == marker },
marker = marker,
nodeInputCallback = { onInfoWindowClose },
inputHandlerCallback = { onInfoWindowClose }
)?.invoke(marker)
)
}
map.setOnInfoWindowLongClickListener { marker ->
decorations.findInputCallback<MarkerNode, Marker, Unit>(
nodeMatchPredicate = { it.marker == marker },
marker = marker,
nodeInputCallback = { onInfoWindowLongClick },
inputHandlerCallback = { onInfoWindowLongClick }
)?.invoke(marker)
)
}
map.setOnMarkerDragListener(object : GoogleMap.OnMarkerDragListener {
override fun onMarkerDrag(marker: Marker) {
Expand All @@ -138,34 +146,37 @@ internal class MapApplier(
markerState.dragState = DragState.DRAG
}
},
marker = marker,
inputHandlerCallback = { onMarkerDrag }
)?.invoke(marker)
)
}

override fun onMarkerDragEnd(marker: Marker) {
decorations.findInputCallback<MarkerNode, Marker, Unit>(
nodeMatchPredicate = { it.marker == marker },
marker = marker,
nodeInputCallback = {
{
markerState.position = it.position
markerState.dragState = DragState.END
}
},
inputHandlerCallback = { onMarkerDragEnd }
)?.invoke(marker)
)
}

override fun onMarkerDragStart(marker: Marker) {
decorations.findInputCallback<MarkerNode, Marker, Unit>(
nodeMatchPredicate = { it.marker == marker },
marker = marker,
nodeInputCallback = {
{
markerState.position = it.position
markerState.dragState = DragState.START
}
},
inputHandlerCallback = { onMarkerDragStart }
)?.invoke(marker)
)
}
})
map.setInfoWindowAdapter(
Expand All @@ -181,25 +192,29 @@ internal class MapApplier(
}

/**
* General pattern for handling input:
* Find the node that belongs to the clicked item.
* If there is none, default to the first InputHandlerNode.
* General pattern for handling input. This finds the node that belongs to the clicked item, and executes the callback.
*
* If there is none, don't handle.
*/
private inline fun <reified NodeT : MapNode, I, O> Iterable<MapNode>.findInputCallback(
nodeMatchPredicate: (NodeT) -> Boolean,
nodeInputCallback: NodeT.() -> ((I) -> O)?,
marker : I,
inputHandlerCallback: InputHandlerNode.() -> ((I) -> O)?,
): ((I) -> O)? {
var callback: ((I) -> O)? = null
): Boolean {
var callback: ((I) -> O)?
for (item in this) {
if (item is NodeT && nodeMatchPredicate(item)) {
// Found a matching node
return nodeInputCallback(item)
nodeInputCallback(item)?.invoke(marker)
return true
} else if (item is InputHandlerNode) {
// Found an input handler, but keep looking for matching nodes
callback = inputHandlerCallback(item)
if (callback?.invoke(marker) == true) {
return true
}
}
}
return callback
return false
}

0 comments on commit ff3f98b

Please sign in to comment.