@@ -2,8 +2,10 @@ package com.what3words.components.compose.maps
22
33import android.annotation.SuppressLint
44import android.graphics.PointF
5- import android.util.Log
65import androidx.annotation.RequiresPermission
6+ import androidx.compose.runtime.Composable
7+ import androidx.compose.runtime.saveable.Saver
8+ import androidx.compose.runtime.saveable.rememberSaveable
79import androidx.compose.ui.graphics.Color
810import com.google.android.gms.maps.model.CameraPosition
911import com.google.maps.android.compose.CameraPositionState
@@ -63,26 +65,29 @@ import kotlinx.coroutines.withContext
6365 * through a [StateFlow]. It acts as a bridge between your application logic and the W3W map,
6466 * providing a convenient way to control the map's behavior and access its data.
6567 *
68+ * In most cases, this will be created via [rememberW3WMapManager].
69+ *
6670 * @param textDataSource An instance of [W3WTextDataSource], used for fetching what3words address information.
6771 * @param mapProvider An instance of enum [MapProvider] to define map provide: GoogleMap, MapBox.
68- * @param mapState An optional [W3WMapState] object representing the initial state of the map. If not
72+ * @param initialMapState An optional [W3WMapState] object representing the initial state of the map. If not
6973 * provided, a default [W3WMapState] is used.
7074 *
7175 * @property mapState A read-only [StateFlow] of [W3WMapState] exposing the current state of the map.
7276 */
7377class W3WMapManager (
7478 private val textDataSource : W3WTextDataSource ,
7579 val mapProvider : MapProvider ,
76- mapState : W3WMapState = W3WMapState (),
77- buttonState : W3WButtonsState = W3WButtonsState (),
80+ val initialMapState : W3WMapState = W3WMapState (),
81+ private val initialButtonState : W3WButtonsState = W3WButtonsState (),
7882 private val dispatcher : CoroutineDispatcher = IO ,
7983) {
8084 private val scope = CoroutineScope (dispatcher + SupervisorJob ())
8185
82- private val _mapState : MutableStateFlow <W3WMapState > = MutableStateFlow (mapState )
86+ private val _mapState : MutableStateFlow <W3WMapState > = MutableStateFlow (initialMapState )
8387 val mapState: StateFlow <W3WMapState > = _mapState .asStateFlow()
8488
85- private val _buttonState : MutableStateFlow <W3WButtonsState > = MutableStateFlow (buttonState)
89+ private val _buttonState : MutableStateFlow <W3WButtonsState > =
90+ MutableStateFlow (initialButtonState)
8691 val buttonState: StateFlow <W3WButtonsState > = _buttonState .asStateFlow()
8792
8893 // This flow controls when the grid calculation should be performed.
@@ -107,6 +112,13 @@ class W3WMapManager(
107112 }
108113
109114 private fun createMapboxCameraState (): W3WMapboxCameraState {
115+ val initialCameraState = initialMapState.cameraState
116+ if (initialCameraState != null ) {
117+ return W3WMapboxCameraState (
118+ initialCameraState.cameraState as MapViewportState
119+ )
120+ }
121+
110122 return W3WMapboxCameraState (
111123 MapViewportState (
112124 initialCameraState = CameraState (
@@ -121,6 +133,12 @@ class W3WMapManager(
121133 }
122134
123135 private fun createGoogleCameraState (): W3WGoogleCameraState {
136+ val initialCameraState = initialMapState.cameraState
137+ if (initialCameraState != null ) {
138+ return W3WGoogleCameraState (
139+ initialCameraState.cameraState as CameraPositionState
140+ )
141+ }
124142 return W3WGoogleCameraState (
125143 CameraPositionState (
126144 position = CameraPosition (
@@ -206,7 +224,6 @@ class W3WMapManager(
206224 }
207225
208226 _mapState .update {
209- Log .d(TAG , " Update GridLines" )
210227 it.copy(gridLines = newGridLines ? : W3WGridLines ())
211228 }
212229 }
@@ -883,5 +900,84 @@ class W3WMapManager(
883900 companion object {
884901 const val LIST_DEFAULT_ID = " LIST_DEFAULT_ID"
885902 const val TAG = " W3WMapManager"
903+
904+ /* *
905+ * The default saver implementation for [W3WMapManager].
906+ */
907+ val Saver : Saver <W3WMapManager , * > = Saver (
908+ save = { manager: W3WMapManager ->
909+ val cameraState = manager.mapState.value.cameraState
910+ mapOf (
911+ " textDataSource" to manager.textDataSource,
912+ " mapProvider" to manager.mapProvider,
913+ " language" to manager.language,
914+ " mapState" to manager.mapState.value,
915+ " buttonState" to manager.buttonState.value,
916+ " mapConfig" to manager.mapConfig,
917+ " markersMap" to manager.markersMap.mapValues { (_, markers) ->
918+ markers.toList()
919+ },
920+ " cameraState" to when (cameraState) {
921+ is W3WGoogleCameraState -> mapOf (
922+ " type" to " google" ,
923+ " position" to cameraState.cameraState.position
924+ )
925+
926+ is W3WMapboxCameraState -> mapOf (
927+ " type" to " mapbox" ,
928+ " position" to cameraState.cameraState.cameraState
929+ )
930+
931+ else -> null
932+ }
933+ )
934+ },
935+ restore = { savedMap: Map <String , Any ?> ->
936+ val mapProvider = savedMap[" mapProvider" ] as MapProvider
937+ val restoredCameraState = savedMap[" cameraState" ] as ? Map <String , Any >
938+ val cameraState = when (restoredCameraState?.get(" type" ) as ? String ) {
939+ " google" -> W3WGoogleCameraState (CameraPositionState (restoredCameraState[" position" ] as CameraPosition ))
940+ " mapbox" -> W3WMapboxCameraState (MapViewportState (restoredCameraState[" position" ] as CameraState ))
941+ else -> when (mapProvider) {
942+ MapProvider .GOOGLE_MAP -> W3WGoogleCameraState (CameraPositionState ())
943+ MapProvider .MAPBOX -> W3WMapboxCameraState (MapViewportState ())
944+ }
945+ }
946+ val restoredMapState =
947+ (savedMap[" mapState" ] as W3WMapState ).copy(cameraState = cameraState)
948+ val restoredButtonState = savedMap[" buttonState" ] as W3WButtonsState
949+
950+ W3WMapManager (
951+ textDataSource = savedMap[" textDataSource" ] as W3WTextDataSource ,
952+ mapProvider = mapProvider,
953+ initialMapState = restoredMapState,
954+ initialButtonState = restoredButtonState
955+ ).apply {
956+ language = savedMap[" language" ] as W3WRFC5646Language
957+ mapConfig = savedMap[" mapConfig" ] as W3WMapDefaults .MapConfig ?
958+ markersMap.clear()
959+ markersMap.putAll(
960+ (savedMap[" markersMap" ] as Map <String , List <W3WMarker >>).mapValues {
961+ it.value.toMutableList()
962+ }
963+ )
964+ }
965+ }
966+ )
886967 }
968+ }
969+
970+ /* *
971+ * Create and [rememberSaveable] a [W3WMapManager] using [W3WMapManager.Saver].
972+ * [init] will be called when the [W3WMapManager] is first created to configure its
973+ * initial state.
974+ */
975+ @Composable
976+ inline fun rememberW3WMapManager (
977+ key : String? = null,
978+ textDataSource : W3WTextDataSource ,
979+ mapProvider : MapProvider ,
980+ crossinline init : W3WMapManager .() -> Unit = {}
981+ ): W3WMapManager = rememberSaveable(key = key, saver = W3WMapManager .Saver ) {
982+ W3WMapManager (textDataSource = textDataSource, mapProvider = mapProvider).apply (init )
887983}
0 commit comments