Add GPS and map-based feature creation to CreatePage with attribute validation, MapViewModel enhancements for feature handling, and dependency updates.

This commit is contained in:
2025-12-04 11:02:45 +01:00
parent 56c61d38a1
commit bd66f298e0
4 changed files with 85 additions and 5 deletions

View File

@@ -66,6 +66,8 @@ dependencies {
androidTestImplementation(libs.androidx.compose.ui.test.junit4)
debugImplementation(libs.androidx.compose.ui.tooling)
debugImplementation(libs.androidx.compose.ui.test.manifest)
implementation("androidx.compose.material:material-icons-extended:1.7.8")
implementation("com.google.android.gms:play-services-location:21.3.0")
// ArcGIS Maps for Kotlin - SDK dependency
implementation(libs.arcgis.maps.kotlin)

View File

@@ -12,6 +12,7 @@ import com.arcgismaps.data.ArcGISFeature
import com.arcgismaps.data.CodedValueDomain
import com.arcgismaps.data.ServiceFeatureTable
import com.arcgismaps.geometry.GeometryEngine
import com.arcgismaps.geometry.Point
import com.arcgismaps.mapping.ArcGISMap
import com.arcgismaps.mapping.BasemapStyle
import com.arcgismaps.mapping.Viewpoint
@@ -118,6 +119,56 @@ class MapViewModel(application: Application): AndroidViewModel(application) {
}
}
fun createFeatureWithAttributesAt(screenCoordinate: ScreenCoordinate, beschreibung: String, typ: String) {
// Create the feature.
val feature = serviceFeatureTable?.createFeature()?.apply {
// Get the normalized geometry for the tapped location and use it as the feature's geometry.
mapViewProxy.screenToLocationOrNull(screenCoordinate)?.let { mapPoint ->
geometry = GeometryEngine.normalizeCentralMeridian(mapPoint)
// Set feature attributes.
attributes["Typ"] = typ
attributes["Beschreibung"] = beschreibung
}
}
feature?.let {
viewModelScope.launch {
// Add the feature to the table.
serviceFeatureTable?.addFeature(it)
// Apply the edits to the service on the service geodatabase.
serviceFeatureTable?.applyEdits()
// Update the feature to get the updated objectid - a temporary ID is used before the feature is added.
it.refresh()
// Confirm feature addition.
snackBarMessage = "Created feature ${it.attributes["objectid"]}"
}
}
}
fun createFeatureWithAttributesAtPoint(point: Point, beschreibung: String, typ: String) {
// Create the feature.
val feature = serviceFeatureTable?.createFeature()?.apply {
// Get the normalized geometry for the tapped location and use it as the feature's geometry.
geometry = GeometryEngine.normalizeCentralMeridian(point)
// Set feature attributes.
attributes["Typ"] = typ
attributes["Beschreibung"] = beschreibung
}
feature?.let {
viewModelScope.launch {
// Add the feature to the table.
serviceFeatureTable?.addFeature(it)
// Apply the edits to the service on the service geodatabase.
serviceFeatureTable?.applyEdits()
// Update the feature to get the updated objectid - a temporary ID is used before the feature is added.
it.refresh()
// Confirm feature addition.
snackBarMessage = "Created feature ${it.attributes["objectid"]}"
}
}
}
/**
* Selects a feature at the tapped location in preparation for deletion.
*/

View File

@@ -22,9 +22,12 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.unit.dp
import com.arcgismaps.geometry.Point
import com.arcgismaps.geometry.SpatialReference
import com.arcgismaps.location.LocationDisplayAutoPanMode
import com.arcgismaps.toolkit.geoviewcompose.MapView
import com.arcgismaps.toolkit.geoviewcompose.rememberLocationDisplay
import com.google.android.gms.location.LocationServices
import de.jadehs.strassenschadenpro2.MapViewModel
import de.jadehs.strassenschadenpro2.components.DropDownMenuBox
import kotlinx.coroutines.launch
@@ -38,6 +41,8 @@ fun CreatePage(modifier: Modifier = Modifier, mapViewModel: MapViewModel) {
var showModalBottomSheet = remember { mutableStateOf(false) }
var enableSaveButton = remember { mutableStateOf(false) }
val locationDisplay = rememberLocationDisplay().apply {
setAutoPanMode(LocationDisplayAutoPanMode.Off)
}
@@ -60,6 +65,8 @@ fun CreatePage(modifier: Modifier = Modifier, mapViewModel: MapViewModel) {
)
}
val fuesedLocationClient = remember { LocationServices.getFusedLocationProviderClient(context) }
Column(modifier = modifier.fillMaxSize()
.padding(top = 16.dp, start = 16.dp, end = 16.dp, bottom = 16.dp),
verticalArrangement = Arrangement.Top,
@@ -69,6 +76,7 @@ fun CreatePage(modifier: Modifier = Modifier, mapViewModel: MapViewModel) {
value = beschreibungTextFieldValue.value,
onValueChange = {
beschreibungTextFieldValue.value = it
enableSaveButton.value = beschreibungTextFieldValue.value.text.isNotEmpty() && currentDamageType.value.isNotEmpty()
},
minLines = 5,
label = { Text("Beschreibung")}
@@ -81,15 +89,28 @@ fun CreatePage(modifier: Modifier = Modifier, mapViewModel: MapViewModel) {
dropDownItemList = mapViewModel.damageTypeList,
onIndexSelected = { index ->
currentDamageType.value = mapViewModel.damageTypeList[index]
Log.d("CreatePage", "Selected index: $index")
enableSaveButton.value = beschreibungTextFieldValue.value.text.isNotEmpty() && currentDamageType.value.isNotEmpty()
}
)
Row(modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceEvenly){
Button(onClick = {}){
Button(enabled = enableSaveButton.value,
onClick = {
fuesedLocationClient.lastLocation.addOnSuccessListener { location ->
location?.let { location->
val beschreibung = beschreibungTextFieldValue.value.text
val typ = currentDamageType.value
var point = Point(location.longitude,
location.latitude,
SpatialReference.wgs84())
mapViewModel.createFeatureWithAttributesAtPoint(point,beschreibung,typ)
}
}
}){
Text("GPS")
}
Button(onClick = {
Button(enabled = enableSaveButton.value,
onClick = {
showModalBottomSheet.value = !showModalBottomSheet.value
}){
Text("Karte")
@@ -98,6 +119,7 @@ fun CreatePage(modifier: Modifier = Modifier, mapViewModel: MapViewModel) {
}
if(showModalBottomSheet.value) {
ModalBottomSheet(
sheetGesturesEnabled = false,
onDismissRequest = {
showModalBottomSheet.value = false
}
@@ -107,7 +129,12 @@ fun CreatePage(modifier: Modifier = Modifier, mapViewModel: MapViewModel) {
arcGISMap = mapViewModel.map,
locationDisplay = locationDisplay,
mapViewProxy = mapViewModel.mapViewProxy,
onSingleTapConfirmed = mapViewModel::onTap,
onSingleTapConfirmed = { singleTapConfirmedEvent ->
val screenCoordinate = singleTapConfirmedEvent.screenCoordinate
val beschreibung = beschreibungTextFieldValue.value.text
val typ = currentDamageType.value
mapViewModel.createFeatureWithAttributesAt(screenCoordinate,beschreibung,typ)
},
)
}
}

View File

@@ -7,7 +7,7 @@ junitVersion = "1.3.0"
espressoCore = "3.7.0"
lifecycleRuntimeKtx = "2.9.4"
activityCompose = "1.11.0"
composeBom = "2024.09.00"
composeBom = "2025.12.00"
arcgisMapsKotlin = "200.8.0"
[libraries]