From 87956988069cfaaebf2fbb2b23dd6bf71de51012 Mon Sep 17 00:00:00 2001 From: Uli Bubenheimer Date: Mon, 1 Jan 2024 15:36:15 -0500 Subject: [PATCH] Replace most GoogleMap() rememberUpdatedState() usages with single State object and encapsulate Subcomposition functionality Fixes #492 --- .../google/maps/android/compose/GoogleMap.kt | 79 ++++++++++++++----- .../google/maps/android/compose/MapUpdater.kt | 11 +-- 2 files changed, 59 insertions(+), 31 deletions(-) diff --git a/maps-compose/src/main/java/com/google/maps/android/compose/GoogleMap.kt b/maps-compose/src/main/java/com/google/maps/android/compose/GoogleMap.kt index 8e89cb2a5..f6fa20d2a 100644 --- a/maps-compose/src/main/java/com/google/maps/android/compose/GoogleMap.kt +++ b/maps-compose/src/main/java/com/google/maps/android/compose/GoogleMap.kt @@ -27,11 +27,13 @@ import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.MutableState +import androidx.compose.runtime.Stable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCompositionContext import androidx.compose.runtime.rememberUpdatedState +import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalInspectionMode @@ -114,39 +116,74 @@ public fun GoogleMap( it.onMyLocationClick = onMyLocationClick it.onPOIClick = onPOIClick } - val currentLocationSource by rememberUpdatedState(locationSource) - val currentCameraPositionState by rememberUpdatedState(cameraPositionState) - val currentContentPadding by rememberUpdatedState(contentPadding) - val currentUiSettings by rememberUpdatedState(uiSettings) - val currentMapProperties by rememberUpdatedState(properties) + + val mapUpdaterState = remember { + MapUpdaterState( + mergeDescendants, + contentDescription, + cameraPositionState, + contentPadding, + locationSource, + properties, + uiSettings + ) + }.also { + it.mergeDescendants = mergeDescendants + it.contentDescription = contentDescription + it.cameraPositionState = cameraPositionState + it.contentPadding = contentPadding + it.locationSource = locationSource + it.mapProperties = properties + it.mapUiSettings = uiSettings + } val parentComposition = rememberCompositionContext() val currentContent by rememberUpdatedState(content) LaunchedEffect(Unit) { disposingComposition { mapView.newComposition(parentComposition, mapClickListeners) { - MapUpdater( - mergeDescendants = mergeDescendants, - contentDescription = contentDescription, - cameraPositionState = currentCameraPositionState, - contentPadding = currentContentPadding, - locationSource = currentLocationSource, - mapProperties = currentMapProperties, - mapUiSettings = currentUiSettings, - ) - - MapClickListenerUpdater() - - CompositionLocalProvider( - LocalCameraPositionState provides cameraPositionState, - ) { - currentContent?.invoke() + Subcomposition(mapUpdaterState) { + // todo change parameter default to {} from "null", which is less meaningful + currentContent ?: {} } } } } } +@Composable +private inline fun Subcomposition( + mapUpdaterState: MapUpdaterState, + crossinline content: @GoogleMapComposable () -> Unit +) { + MapUpdater(mapUpdaterState) + + MapClickListenerUpdater() + + CompositionLocalProvider( + LocalCameraPositionState provides mapUpdaterState.cameraPositionState + ) { content() } +} + +@Stable +internal class MapUpdaterState( + mergeDescendants: Boolean, + contentDescription: String?, + cameraPositionState: CameraPositionState, + contentPadding: PaddingValues, + locationSource: LocationSource?, + mapProperties: MapProperties, + mapUiSettings: MapUiSettings +) { + var mergeDescendants by mutableStateOf(mergeDescendants) + var contentDescription by mutableStateOf(contentDescription) + var cameraPositionState by mutableStateOf(cameraPositionState) + var contentPadding by mutableStateOf(contentPadding) + var locationSource by mutableStateOf(locationSource) + var mapProperties by mutableStateOf(mapProperties) + var mapUiSettings by mutableStateOf(mapUiSettings) +} + internal suspend inline fun disposingComposition(factory: () -> Composition) { val composition = factory() try { diff --git a/maps-compose/src/main/java/com/google/maps/android/compose/MapUpdater.kt b/maps-compose/src/main/java/com/google/maps/android/compose/MapUpdater.kt index f27a000d3..3a331efe3 100644 --- a/maps-compose/src/main/java/com/google/maps/android/compose/MapUpdater.kt +++ b/maps-compose/src/main/java/com/google/maps/android/compose/MapUpdater.kt @@ -25,7 +25,6 @@ import androidx.compose.ui.platform.LocalLayoutDirection import androidx.compose.ui.unit.Density import androidx.compose.ui.unit.LayoutDirection import com.google.android.gms.maps.GoogleMap -import com.google.android.gms.maps.LocationSource internal class MapPropertiesNode( val map: GoogleMap, @@ -93,15 +92,7 @@ internal val NoPadding = PaddingValues() @SuppressLint("MissingPermission") @Suppress("NOTHING_TO_INLINE") @Composable -internal inline fun MapUpdater( - mergeDescendants: Boolean = false, - contentDescription: String?, - cameraPositionState: CameraPositionState, - contentPadding: PaddingValues = NoPadding, - locationSource: LocationSource?, - mapProperties: MapProperties, - mapUiSettings: MapUiSettings, -) { +internal inline fun MapUpdater(mapUpdaterState: MapUpdaterState) = with(mapUpdaterState) { val map = (currentComposer.applier as MapApplier).map val mapView = (currentComposer.applier as MapApplier).mapView if (mergeDescendants) {