From 302697d03342ef97d7e153b3a6c749cc4786aa28 Mon Sep 17 00:00:00 2001 From: Newton Scavazzini Date: Mon, 14 Feb 2022 23:09:05 -0300 Subject: [PATCH 1/2] Add MarkerInfoWindowState parameter to Marker composables --- .../google/maps/android/compose/MapApplier.kt | 8 +- .../com/google/maps/android/compose/Marker.kt | 84 +++++++++++++++---- 2 files changed, 74 insertions(+), 18 deletions(-) diff --git a/maps-compose/src/main/java/com/google/maps/android/compose/MapApplier.kt b/maps-compose/src/main/java/com/google/maps/android/compose/MapApplier.kt index cacc5c49..3f6bb626 100644 --- a/maps-compose/src/main/java/com/google/maps/android/compose/MapApplier.kt +++ b/maps-compose/src/main/java/com/google/maps/android/compose/MapApplier.kt @@ -90,8 +90,9 @@ internal class MapApplier( // Marker map.setOnMarkerClickListener { marker -> - decorations.nodeForMarker(marker) - ?.onMarkerClick + val node = decorations.nodeForMarker(marker) + node?.infoWindowState?.state = InfoWindowState.SHOWN + node?.onMarkerClick ?.invoke(marker) ?: false } @@ -102,8 +103,7 @@ internal class MapApplier( } map.setOnInfoWindowCloseListener { marker -> decorations.nodeForMarker(marker) - ?.onInfoWindowClose - ?.invoke(marker) + ?.infoWindowState?.state = InfoWindowState.HIDDEN } map.setOnInfoWindowLongClickListener { marker -> decorations.nodeForMarker(marker) diff --git a/maps-compose/src/main/java/com/google/maps/android/compose/Marker.kt b/maps-compose/src/main/java/com/google/maps/android/compose/Marker.kt index 722d22c9..f1df0015 100644 --- a/maps-compose/src/main/java/com/google/maps/android/compose/Marker.kt +++ b/maps-compose/src/main/java/com/google/maps/android/compose/Marker.kt @@ -36,16 +36,68 @@ internal class MarkerNode( var markerDragState: MarkerDragState?, var onMarkerClick: (Marker) -> Boolean, var onInfoWindowClick: (Marker) -> Unit, - var onInfoWindowClose: (Marker) -> Unit, var onInfoWindowLongClick: (Marker) -> Unit, var infoWindow: (@Composable (Marker) -> Unit)?, var infoContent: (@Composable (Marker) -> Unit)?, + var infoWindowState: MarkerInfoWindowState?, ) : MapNode { + + init { + infoWindowState?.marker = marker + } + + override fun onAttached() { + if (this.infoWindowState?.state == InfoWindowState.SHOWN) { + this.marker.showInfoWindow() + } else { + this.marker.hideInfoWindow() + } + } + override fun onRemoved() { marker.remove() } } +@Immutable +enum class InfoWindowState { + SHOWN, HIDDEN +} + +class MarkerInfoWindowState( + initialValue: InfoWindowState = InfoWindowState.HIDDEN +) { + var marker: Marker? = null + + private var _state: InfoWindowState by mutableStateOf(initialValue) + + var state: InfoWindowState + get() = _state + set(value) { + _state = value + if (value == InfoWindowState.SHOWN) { + this.marker?.showInfoWindow() + } else { + this.marker?.hideInfoWindow() + } + } + + fun show() { + this.state = InfoWindowState.SHOWN + } + + fun hide() { + this.state = InfoWindowState.HIDDEN + } +} + +@Composable +fun rememberMarkerInfoWindowState( + initialValue: InfoWindowState = InfoWindowState.HIDDEN +): MarkerInfoWindowState = remember { + MarkerInfoWindowState(initialValue) +} + @Immutable enum class DragState { START, DRAG, END @@ -80,6 +132,8 @@ fun rememberMarkerDragState(): MarkerDragState = remember { * @param flat sets if the marker should be flat against the map * @param icon sets the icon for the marker * @param infoWindowAnchor the anchor point of the info window on the marker image + * @param infoWindowState a [MarkerInfoWindowState] to be used for controlling and observing info + * window visibility * @param rotation the rotation of the marker in degrees clockwise about the marker's anchor point * @param snippet the snippet for the marker * @param tag optional tag to associate with the marker @@ -89,7 +143,6 @@ fun rememberMarkerDragState(): MarkerDragState = remember { * @param markerDragState a [MarkerDragState] to be used for observing marker drag events * @param onClick a lambda invoked when the marker is clicked * @param onInfoWindowClick a lambda invoked when the marker's info window is clicked - * @param onInfoWindowClose a lambda invoked when the marker's info window is closed * @param onInfoWindowLongClick a lambda invoked when the marker's info window is long clicked */ @Composable @@ -101,6 +154,7 @@ fun Marker( flat: Boolean = false, icon: BitmapDescriptor? = null, infoWindowAnchor: Offset = Offset(0.5f, 0.0f), + infoWindowState: MarkerInfoWindowState = rememberMarkerInfoWindowState(), rotation: Float = 0.0f, snippet: String? = null, tag: Any? = null, @@ -110,7 +164,6 @@ fun Marker( markerDragState: MarkerDragState? = null, onClick: (Marker) -> Boolean = { false }, onInfoWindowClick: (Marker) -> Unit = {}, - onInfoWindowClose: (Marker) -> Unit = {}, onInfoWindowLongClick: (Marker) -> Unit = {}, ) { MarkerImpl( @@ -130,8 +183,8 @@ fun Marker( markerDragState = markerDragState, onClick = onClick, onInfoWindowClick = onInfoWindowClick, - onInfoWindowClose = onInfoWindowClose, onInfoWindowLongClick = onInfoWindowLongClick, + infoWindowState = infoWindowState, ) } @@ -147,6 +200,8 @@ fun Marker( * @param flat sets if the marker should be flat against the map * @param icon sets the icon for the marker * @param infoWindowAnchor the anchor point of the info window on the marker image + * @param infoWindowState a [MarkerInfoWindowState] to be used for controlling and observing info + * window visibility * @param rotation the rotation of the marker in degrees clockwise about the marker's anchor point * @param snippet the snippet for the marker * @param tag optional tag to associate with the marker @@ -156,7 +211,6 @@ fun Marker( * @param markerDragState a [MarkerDragState] to be used for observing marker drag events * @param onClick a lambda invoked when the marker is clicked * @param onInfoWindowClick a lambda invoked when the marker's info window is clicked - * @param onInfoWindowClose a lambda invoked when the marker's info window is closed * @param onInfoWindowLongClick a lambda invoked when the marker's info window is long clicked * @param content optional composable lambda expression for customizing the * info window's content @@ -170,6 +224,7 @@ fun MarkerInfoWindow( flat: Boolean = false, icon: BitmapDescriptor? = null, infoWindowAnchor: Offset = Offset(0.5f, 0.0f), + infoWindowState: MarkerInfoWindowState = rememberMarkerInfoWindowState(), rotation: Float = 0.0f, snippet: String? = null, tag: Any? = null, @@ -179,7 +234,6 @@ fun MarkerInfoWindow( markerDragState: MarkerDragState? = null, onClick: (Marker) -> Boolean = { false }, onInfoWindowClick: (Marker) -> Unit = {}, - onInfoWindowClose: (Marker) -> Unit = {}, onInfoWindowLongClick: (Marker) -> Unit = {}, content: (@Composable (Marker) -> Unit)? = null ) { @@ -200,9 +254,9 @@ fun MarkerInfoWindow( markerDragState = markerDragState, onClick = onClick, onInfoWindowClick = onInfoWindowClick, - onInfoWindowClose = onInfoWindowClose, onInfoWindowLongClick = onInfoWindowLongClick, infoWindow = content, + infoWindowState = infoWindowState, ) } @@ -218,6 +272,8 @@ fun MarkerInfoWindow( * @param flat sets if the marker should be flat against the map * @param icon sets the icon for the marker * @param infoWindowAnchor the anchor point of the info window on the marker image + * @param infoWindowState a [MarkerInfoWindowState] to be used for controlling and observing info + * window visibility * @param rotation the rotation of the marker in degrees clockwise about the marker's anchor point * @param snippet the snippet for the marker * @param tag optional tag to associate with the marker @@ -227,7 +283,6 @@ fun MarkerInfoWindow( * @param markerDragState a [MarkerDragState] to be used for observing marker drag events * @param onClick a lambda invoked when the marker is clicked * @param onInfoWindowClick a lambda invoked when the marker's info window is clicked - * @param onInfoWindowClose a lambda invoked when the marker's info window is closed * @param onInfoWindowLongClick a lambda invoked when the marker's info window is long clicked * @param content optional composable lambda expression for customizing the * info window's content @@ -241,6 +296,7 @@ fun MarkerInfoWindowContent( flat: Boolean = false, icon: BitmapDescriptor? = null, infoWindowAnchor: Offset = Offset(0.5f, 0.0f), + infoWindowState: MarkerInfoWindowState = rememberMarkerInfoWindowState(), rotation: Float = 0.0f, snippet: String? = null, tag: Any? = null, @@ -250,7 +306,6 @@ fun MarkerInfoWindowContent( markerDragState: MarkerDragState? = null, onClick: (Marker) -> Boolean = { false }, onInfoWindowClick: (Marker) -> Unit = {}, - onInfoWindowClose: (Marker) -> Unit = {}, onInfoWindowLongClick: (Marker) -> Unit = {}, content: (@Composable (Marker) -> Unit)? = null ) { @@ -271,9 +326,9 @@ fun MarkerInfoWindowContent( markerDragState = markerDragState, onClick = onClick, onInfoWindowClick = onInfoWindowClick, - onInfoWindowClose = onInfoWindowClose, onInfoWindowLongClick = onInfoWindowLongClick, infoContent = content, + infoWindowState = infoWindowState, ) } @@ -287,6 +342,8 @@ fun MarkerInfoWindowContent( * @param flat sets if the marker should be flat against the map * @param icon sets the icon for the marker * @param infoWindowAnchor the anchor point of the info window on the marker image + * @param infoWindowState a [MarkerInfoWindowState] to be used for controlling and observing info + * window visibility * @param rotation the rotation of the marker in degrees clockwise about the marker's anchor point * @param snippet the snippet for the marker * @param tag optional tag to associate with the marker @@ -296,7 +353,6 @@ fun MarkerInfoWindowContent( * @param markerDragState a [MarkerDragState] to be used for observing marker drag events * @param onClick a lambda invoked when the marker is clicked * @param onInfoWindowClick a lambda invoked when the marker's info window is clicked - * @param onInfoWindowClose a lambda invoked when the marker's info window is closed * @param onInfoWindowLongClick a lambda invoked when the marker's info window is long clicked * @param infoWindow optional composable lambda expression for customizing * the entire info window. If this value is non-null, the value in infoContent] @@ -313,6 +369,7 @@ private fun MarkerImpl( flat: Boolean = false, icon: BitmapDescriptor? = null, infoWindowAnchor: Offset = Offset(0.5f, 0.0f), + infoWindowState: MarkerInfoWindowState = rememberMarkerInfoWindowState(), rotation: Float = 0.0f, snippet: String? = null, tag: Any? = null, @@ -322,7 +379,6 @@ private fun MarkerImpl( markerDragState: MarkerDragState? = null, onClick: (Marker) -> Boolean = { false }, onInfoWindowClick: (Marker) -> Unit = {}, - onInfoWindowClose: (Marker) -> Unit = {}, onInfoWindowLongClick: (Marker) -> Unit = {}, infoWindow: (@Composable (Marker) -> Unit)? = null, infoContent: (@Composable (Marker) -> Unit)? = null, @@ -352,20 +408,20 @@ private fun MarkerImpl( markerDragState = markerDragState, onMarkerClick = onClick, onInfoWindowClick = onInfoWindowClick, - onInfoWindowClose = onInfoWindowClose, onInfoWindowLongClick = onInfoWindowLongClick, infoContent = infoContent, infoWindow = infoWindow, + infoWindowState = infoWindowState, ) }, update = { update(markerDragState) { this.markerDragState = it } update(onClick) { this.onMarkerClick = it } update(onInfoWindowClick) { this.onInfoWindowClick = it } - update(onInfoWindowClose) { this.onInfoWindowClose = it } update(onInfoWindowLongClick) { this.onInfoWindowLongClick = it } update(infoContent) { this.infoContent = it } update(infoWindow) { this.infoWindow = it } + update(infoWindowState) { this.infoWindowState = it } set(alpha) { this.marker.alpha = it } set(anchor) { this.marker.setAnchor(it.x, it.y) } From 680be0a1e505143d42fa7ae37ba9b8d981af4acb Mon Sep 17 00:00:00 2001 From: Newton Scavazzini Date: Mon, 14 Feb 2022 23:11:37 -0300 Subject: [PATCH 2/2] Update sample app --- .../maps/android/compose/MapSampleActivity.kt | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/app/src/main/java/com/google/maps/android/compose/MapSampleActivity.kt b/app/src/main/java/com/google/maps/android/compose/MapSampleActivity.kt index 0a79a801..671c12c6 100644 --- a/app/src/main/java/com/google/maps/android/compose/MapSampleActivity.kt +++ b/app/src/main/java/com/google/maps/android/compose/MapSampleActivity.kt @@ -108,6 +108,9 @@ private fun GoogleMapView(modifier: Modifier, onMapLoaded: () -> Unit) { var shouldAnimateZoom by remember { mutableStateOf(true) } var ticker by remember { mutableStateOf(0) } + // Observing and controlling the info window visibility can be done with a MarkerInfoWindowState + val markerInfoWindowState = rememberMarkerInfoWindowState(initialValue = InfoWindowState.SHOWN) + GoogleMap( modifier = modifier, cameraPositionState = cameraPositionState, @@ -130,6 +133,7 @@ private fun GoogleMapView(modifier: Modifier, onMapLoaded: () -> Unit) { position = singapore, title = "Zoom in has been tapped $ticker times.", onClick = markerClick, + infoWindowState = markerInfoWindowState, ) { Text(it.title ?: "Title", color = Color.Red) } @@ -158,6 +162,7 @@ private fun GoogleMapView(modifier: Modifier, onMapLoaded: () -> Unit) { ZoomControls( shouldAnimateZoom, uiSettings.zoomControlsEnabled, + isInfoWindowShowingChecked = markerInfoWindowState.state == InfoWindowState.SHOWN, onZoomOut = { if (shouldAnimateZoom) { coroutineScope.launch { @@ -182,6 +187,14 @@ private fun GoogleMapView(modifier: Modifier, onMapLoaded: () -> Unit) { }, onZoomControlsCheckedChange = { uiSettings = uiSettings.copy(zoomControlsEnabled = it) + }, + onInfoWindowShowingChange = { show -> + if (show) { + markerInfoWindowState.show() + } + else { + markerInfoWindowState.hide() + } } ) DebugView(cameraPositionState) @@ -222,10 +235,12 @@ private fun MapTypeButton(type: MapType, onClick: () -> Unit) { private fun ZoomControls( isCameraAnimationChecked: Boolean, isZoomControlsEnabledChecked: Boolean, + isInfoWindowShowingChecked: Boolean, onZoomOut: () -> Unit, onZoomIn: () -> Unit, onCameraAnimationCheckedChange: (Boolean) -> Unit, onZoomControlsCheckedChange: (Boolean) -> Unit, + onInfoWindowShowingChange: (Boolean) -> Unit, ) { Row(Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.Center) { MapButton("-", onClick = { onZoomOut() }) @@ -239,6 +254,10 @@ private fun ZoomControls( Text(text = "Zoom Controls On?") Switch(isZoomControlsEnabledChecked, onCheckedChange = onZoomControlsCheckedChange) } + Row(horizontalArrangement = Arrangement.Center) { + Text(text = "Info Window showing?") + Switch(isInfoWindowShowingChecked, onCheckedChange = onInfoWindowShowingChange) + } } } }