From e036ee769ac9ba6ffea62adc484b3d796ae21474 Mon Sep 17 00:00:00 2001 From: Priyanka Rupani <44178002+prupani-7@users.noreply.github.com> Date: Fri, 29 Dec 2023 09:33:57 -0800 Subject: [PATCH] Update sample - add dynamic entity sample (#161) --- add-dynamic-entity-layer/README.md | 3 +- add-dynamic-entity-layer/README.metadata.json | 3 +- add-dynamic-entity-layer/build.gradle | 3 + .../adddynamicentitylayer/MainActivity.kt | 3 +- .../components/ComposeMapView.kt | 90 ------------------- .../components/MapViewModel.kt | 20 ++--- .../screens/MainScreen.kt | 16 +++- 7 files changed, 26 insertions(+), 112 deletions(-) delete mode 100644 add-dynamic-entity-layer/src/main/java/com/esri/arcgismaps/sample/adddynamicentitylayer/components/ComposeMapView.kt diff --git a/add-dynamic-entity-layer/README.md b/add-dynamic-entity-layer/README.md index d2ae6259a..0e95d60d8 100644 --- a/add-dynamic-entity-layer/README.md +++ b/add-dynamic-entity-layer/README.md @@ -38,8 +38,9 @@ This sample uses a [stream service](https://realtimegis2016.esri.com:6443/arcgis ## Additional information +This sample uses the GeoCompose Toolkit module to be able to implement a Composable MapView. More information about dynamic entities can be found in the [guide documentation](https://developers.arcgis.com/kotlin/real-time/work-with-dynamic-entities/). ## Tags -data, dynamic, entity, live, purge, real-time, service, stream, track +data, dynamic, entity, geocompose, live, purge, real-time, service, stream, toolkit, track diff --git a/add-dynamic-entity-layer/README.metadata.json b/add-dynamic-entity-layer/README.metadata.json index fc7c41a10..c691d020f 100644 --- a/add-dynamic-entity-layer/README.metadata.json +++ b/add-dynamic-entity-layer/README.metadata.json @@ -10,11 +10,13 @@ "data", "dynamic", "entity", + "geocompose", "live", "purge", "real-time", "service", "stream", + "toolkit", "track", "ArcGISStreamService", "DynamicEntity", @@ -36,7 +38,6 @@ "snippets": [ "src/main/java/com/esri/arcgismaps/sample/adddynamicentitylayer/MainActivity.kt", "src/main/java/com/esri/arcgismaps/sample/adddynamicentitylayer/components/BottomSheetContent.kt", - "src/main/java/com/esri/arcgismaps/sample/adddynamicentitylayer/components/ComposeMapView.kt", "src/main/java/com/esri/arcgismaps/sample/adddynamicentitylayer/components/MapViewModel.kt", "src/main/java/com/esri/arcgismaps/sample/adddynamicentitylayer/screens/MainScreen.kt" ], diff --git a/add-dynamic-entity-layer/build.gradle b/add-dynamic-entity-layer/build.gradle index 254bf5853..9a1c69488 100644 --- a/add-dynamic-entity-layer/build.gradle +++ b/add-dynamic-entity-layer/build.gradle @@ -45,4 +45,7 @@ dependencies { implementation "androidx.compose.ui:ui-tooling" implementation "androidx.compose.ui:ui-tooling-preview" implementation project(path: ':samples-lib') + // Toolkit dependencies + implementation(platform("com.esri:arcgis-maps-kotlin-toolkit-bom:$arcgisToolkitVersion")) + implementation('com.esri:arcgis-maps-kotlin-toolkit-geo-compose') } diff --git a/add-dynamic-entity-layer/src/main/java/com/esri/arcgismaps/sample/adddynamicentitylayer/MainActivity.kt b/add-dynamic-entity-layer/src/main/java/com/esri/arcgismaps/sample/adddynamicentitylayer/MainActivity.kt index b8444a445..602ca410f 100644 --- a/add-dynamic-entity-layer/src/main/java/com/esri/arcgismaps/sample/adddynamicentitylayer/MainActivity.kt +++ b/add-dynamic-entity-layer/src/main/java/com/esri/arcgismaps/sample/adddynamicentitylayer/MainActivity.kt @@ -47,8 +47,7 @@ class MainActivity : ComponentActivity() { color = MaterialTheme.colorScheme.background ) { MainScreen( - sampleName = getString(R.string.app_name), - application = application + sampleName = getString(R.string.app_name) ) } } diff --git a/add-dynamic-entity-layer/src/main/java/com/esri/arcgismaps/sample/adddynamicentitylayer/components/ComposeMapView.kt b/add-dynamic-entity-layer/src/main/java/com/esri/arcgismaps/sample/adddynamicentitylayer/components/ComposeMapView.kt deleted file mode 100644 index 73efcabbd..000000000 --- a/add-dynamic-entity-layer/src/main/java/com/esri/arcgismaps/sample/adddynamicentitylayer/components/ComposeMapView.kt +++ /dev/null @@ -1,90 +0,0 @@ -/* Copyright 2023 Esri - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package com.esri.arcgismaps.sample.adddynamicentitylayer.components - -import androidx.compose.runtime.Composable -import androidx.compose.runtime.DisposableEffect -import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.collectAsState -import androidx.compose.runtime.getValue -import androidx.compose.ui.Modifier -import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.platform.LocalLifecycleOwner -import androidx.compose.ui.viewinterop.AndroidView -import androidx.lifecycle.LifecycleOwner -import com.arcgismaps.mapping.view.MapView -import kotlinx.coroutines.launch - -/** - * Wraps the MapView in a Composable function. - */ -@Composable -fun ComposeMapView( - modifier: Modifier = Modifier, - mapViewModel: MapViewModel -) { - // get an instance of the current lifecycle owner - val lifecycleOwner = LocalLifecycleOwner.current - // collect the latest state of the MapViewState - val mapViewState by mapViewModel.mapViewState.collectAsState() - // create and add MapView to the activity lifecycle - val mapView = createMapViewInstance(lifecycleOwner) - - // wrap the MapView as an AndroidView - AndroidView( - modifier = modifier, - factory = { mapView }, - // recomposes the MapView on changes in the MapViewState - update = { mapView -> - mapView.apply { - map = mapViewState.arcGISMap - setViewpoint(mapViewState.viewpoint) - } - } - ) - - // launch coroutine functions in the composition's CoroutineContext - LaunchedEffect(Unit) { - launch { - mapView.onSingleTapConfirmed.collect { - mapViewModel.dismissBottomSheet() - } - } - launch { - mapView.onPan.collect{ - mapViewModel.dismissBottomSheet() - } - } - } -} - -/** - * Create the MapView instance and add it to the Activity lifecycle - */ -@Composable -fun createMapViewInstance(lifecycleOwner: LifecycleOwner): MapView { - // create the MapView - val mapView = MapView(LocalContext.current) - // add the side effects for MapView composition - DisposableEffect(lifecycleOwner) { - lifecycleOwner.lifecycle.addObserver(mapView) - onDispose { - lifecycleOwner.lifecycle.removeObserver(mapView) - } - } - return mapView -} diff --git a/add-dynamic-entity-layer/src/main/java/com/esri/arcgismaps/sample/adddynamicentitylayer/components/MapViewModel.kt b/add-dynamic-entity-layer/src/main/java/com/esri/arcgismaps/sample/adddynamicentitylayer/components/MapViewModel.kt index f26268939..71a7cfe79 100644 --- a/add-dynamic-entity-layer/src/main/java/com/esri/arcgismaps/sample/adddynamicentitylayer/components/MapViewModel.kt +++ b/add-dynamic-entity-layer/src/main/java/com/esri/arcgismaps/sample/adddynamicentitylayer/components/MapViewModel.kt @@ -17,17 +17,16 @@ package com.esri.arcgismaps.sample.adddynamicentitylayer.components import android.app.Application +import androidx.compose.runtime.mutableFloatStateOf import androidx.compose.runtime.mutableStateOf import androidx.lifecycle.AndroidViewModel import com.arcgismaps.mapping.ArcGISMap import com.arcgismaps.mapping.BasemapStyle -import com.arcgismaps.mapping.Viewpoint import com.arcgismaps.mapping.layers.DynamicEntityLayer import com.arcgismaps.realtime.ArcGISStreamService import com.arcgismaps.realtime.ArcGISStreamServiceFilter import com.esri.arcgismaps.sample.adddynamicentitylayer.R import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.launch class MapViewModel( @@ -38,14 +37,11 @@ class MapViewModel( // set the state of the switches and slider val trackLineCheckedState = mutableStateOf(false) val prevObservationCheckedState = mutableStateOf(false) - val trackSliderValue = mutableStateOf(5f) + val trackSliderValue = mutableFloatStateOf(5f) // flag to show or dismiss the bottom sheet val isBottomSheetVisible = mutableStateOf(false) - // set the MapView mutable stateflow - val mapViewState = MutableStateFlow(MapViewState()) - // create ArcGIS Stream Service private val streamService = ArcGISStreamService(application.getString(R.string.stream_service_url)) @@ -56,6 +52,9 @@ class MapViewModel( // layer displaying the dynamic entities on the map private val dynamicEntityLayer: DynamicEntityLayer + // define ArcGIS map using Streets basemap + val map = ArcGISMap(BasemapStyle.ArcGISStreets) + /** * set the data source for the dynamic entity layer. */ @@ -70,7 +69,7 @@ class MapViewModel( dynamicEntityLayer = DynamicEntityLayer(streamService) // add the dynamic entity layer to the map's operational layers - mapViewState.value.arcGISMap.operationalLayers.add(dynamicEntityLayer) + map.operationalLayers.add(dynamicEntityLayer) } // disconnects the stream service @@ -125,10 +124,3 @@ class MapViewModel( } } -/** - * Data class that represents the MapView state - */ -data class MapViewState( - var arcGISMap: ArcGISMap = ArcGISMap(BasemapStyle.ArcGISStreets), - var viewpoint: Viewpoint = Viewpoint(40.559691, -111.869001, 150000.0) -) diff --git a/add-dynamic-entity-layer/src/main/java/com/esri/arcgismaps/sample/adddynamicentitylayer/screens/MainScreen.kt b/add-dynamic-entity-layer/src/main/java/com/esri/arcgismaps/sample/adddynamicentitylayer/screens/MainScreen.kt index 307933ae3..7f7fa674a 100644 --- a/add-dynamic-entity-layer/src/main/java/com/esri/arcgismaps/sample/adddynamicentitylayer/screens/MainScreen.kt +++ b/add-dynamic-entity-layer/src/main/java/com/esri/arcgismaps/sample/adddynamicentitylayer/screens/MainScreen.kt @@ -34,8 +34,11 @@ import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.unit.dp -import com.esri.arcgismaps.sample.adddynamicentitylayer.components.ComposeMapView +import com.arcgismaps.mapping.Viewpoint +import com.arcgismaps.toolkit.geocompose.MapView +import com.arcgismaps.toolkit.geocompose.MapViewpointOperation import com.esri.arcgismaps.sample.adddynamicentitylayer.components.DynamicEntityLayerProperties import com.esri.arcgismaps.sample.adddynamicentitylayer.components.MapViewModel import com.esri.arcgismaps.sample.sampleslib.components.BottomSheet @@ -45,9 +48,11 @@ import com.esri.arcgismaps.sample.sampleslib.components.SampleTopAppBar * Main screen layout for the sample app */ @Composable -fun MainScreen(sampleName: String, application: Application) { +fun MainScreen(sampleName: String) { /// coroutineScope that will be cancelled when this call leaves the composition val sampleCoroutineScope = rememberCoroutineScope() + // get the application context + val application = LocalContext.current.applicationContext as Application // create a ViewModel to handle MapView interactions val mapViewModel = remember { MapViewModel(application, sampleCoroutineScope) } @@ -64,11 +69,14 @@ fun MainScreen(sampleName: String, application: Application) { .padding(it) ) { // composable function that wraps the MapView - ComposeMapView( + MapView( modifier = Modifier .fillMaxSize() .weight(1f), - mapViewModel = mapViewModel + arcGISMap = mapViewModel.map, + viewpointOperation = MapViewpointOperation.Set(viewpoint = Viewpoint(40.559691, -111.869001, 150000.0)), + onSingleTapConfirmed = { mapViewModel.dismissBottomSheet() }, + onPan = { mapViewModel.dismissBottomSheet() } ) Row( modifier = Modifier