- Featurelayer ArcGIS hinzugefügt
- Textbox jetzt nutzbar - Schadenauswahl Dropdown Menü - Featureerstellung nimmt eigene Position und wird hinzugefügt.
This commit is contained in:
@@ -1,64 +1,182 @@
|
||||
package com.example.snapandsolve
|
||||
|
||||
import android.app.Application
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.graphics.ImageBitmap
|
||||
import androidx.compose.ui.graphics.asAndroidBitmap
|
||||
import androidx.lifecycle.AndroidViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.arcgismaps.LoadStatus
|
||||
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.geometry.SpatialReference
|
||||
import com.arcgismaps.mapping.ArcGISMap
|
||||
import com.arcgismaps.mapping.BasemapStyle
|
||||
import com.arcgismaps.mapping.Viewpoint
|
||||
import com.arcgismaps.mapping.layers.FeatureLayer
|
||||
import com.arcgismaps.mapping.view.LocationDisplay
|
||||
import com.arcgismaps.toolkit.geoviewcompose.MapViewProxy
|
||||
import kotlinx.coroutines.launch
|
||||
import java.io.ByteArrayOutputStream
|
||||
|
||||
class MapViewModel(application: Application ): AndroidViewModel(application) {
|
||||
class MapViewModel(application: Application) : AndroidViewModel(application) {
|
||||
val map: ArcGISMap = ArcGISMap(BasemapStyle.OpenOsmStyle).apply {
|
||||
initialViewpoint = Viewpoint(53.14, 8.20, 20000.0)
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
ALLES UNTER DIESEM KOMMENTAR WIRD NICHT GENUTZT. Aber EVENTUELL nötig zum einbinden von
|
||||
Layer und Features.
|
||||
*/
|
||||
// Hold a reference to the selected feature.
|
||||
var selectedFeature: ArcGISFeature? by mutableStateOf(null)
|
||||
val mapViewProxy = MapViewProxy()
|
||||
|
||||
//var currentFeatureOperation by mutableStateOf(FeatureOperationType.CREATE)
|
||||
|
||||
lateinit var featureLayer: FeatureLayer
|
||||
|
||||
// Create a snackbar message to display the result of feature operations.
|
||||
var snackBarMessage: String by mutableStateOf("")
|
||||
|
||||
lateinit var serviceFeatureTable: ServiceFeatureTable
|
||||
|
||||
var currentDamageType by mutableStateOf("")
|
||||
|
||||
// The list of damage types to update the feature attribute.
|
||||
var damageTypeList: List<String> = mutableListOf()
|
||||
var locationDisplay: LocationDisplay? = null
|
||||
|
||||
init {
|
||||
viewModelScope.launch {
|
||||
serviceFeatureTable = ServiceFeatureTable("https://services9.arcgis.com/UVxdrlZq3S3gqt7w/ArcGIS/rest/services/StrassenSchaeden/FeatureServer/0")
|
||||
serviceFeatureTable = ServiceFeatureTable("https://services9.arcgis.com/UVxdrlZq3S3gqt7w/arcgis/rest/services/si_StrassenSchaeden/FeatureServer/0")
|
||||
serviceFeatureTable.load().onSuccess {
|
||||
// Get the field from the feature table that will be updated.
|
||||
val typeDamageField = serviceFeatureTable.fields.first { it.name == "Typ" }
|
||||
// Get the coded value domain for the field.
|
||||
val attributeDomain = typeDamageField.domain as CodedValueDomain
|
||||
// Add the damage types to the list.
|
||||
attributeDomain.codedValues.forEach {
|
||||
val typeDamageField = serviceFeatureTable.fields.firstOrNull { it.name == "Typ" }
|
||||
val attributeDomain = typeDamageField?.domain as? CodedValueDomain
|
||||
attributeDomain?.codedValues?.forEach {
|
||||
damageTypeList += it.name
|
||||
}
|
||||
println("DEBUG: ServiceFeatureTable erfolgreich geladen")
|
||||
}.onFailure {
|
||||
println("DEBUG: Fehler beim Laden der Tabelle: ${it.message}")
|
||||
}
|
||||
featureLayer = FeatureLayer.createWithFeatureTable(serviceFeatureTable)
|
||||
map.operationalLayers.add(featureLayer)
|
||||
}
|
||||
}
|
||||
|
||||
fun createFeatureAtCurrentLocation(
|
||||
beschreibung: String,
|
||||
typ: String,
|
||||
photos: List<ImageBitmap> = emptyList()
|
||||
) {
|
||||
viewModelScope.launch {
|
||||
println("DEBUG: createFeature gestartet") // Erscheint das in der Logcat?
|
||||
try {
|
||||
// 1. Location prüfen
|
||||
val locationData = locationDisplay?.location?.value
|
||||
val gpsPoint = locationData?.position
|
||||
|
||||
if (gpsPoint == null) {
|
||||
println("DEBUG: Standort ist NULL - GPS Signal fehlt!")
|
||||
snackBarMessage = "Kein GPS Signal. Bitte kurz warten oder nach draußen gehen."
|
||||
return@launch
|
||||
}
|
||||
|
||||
println("DEBUG: GPS gefunden: x=${gpsPoint.x}, y=${gpsPoint.y}")
|
||||
|
||||
// 2. Feature erstellen
|
||||
// Wichtig: explizit WGS84, falls es nicht schon hat
|
||||
val pointWgs84 = Point(gpsPoint.x, gpsPoint.y, SpatialReference.wgs84())
|
||||
|
||||
val feature = serviceFeatureTable.createFeature().apply {
|
||||
geometry = pointWgs84
|
||||
attributes["Typ"] = typ
|
||||
attributes["Beschreibung"] = beschreibung
|
||||
}
|
||||
|
||||
println("DEBUG: Feature lokal erstellt. Sende an Server...")
|
||||
|
||||
// 3. Hochladen
|
||||
serviceFeatureTable.addFeature(feature).onSuccess {
|
||||
println("DEBUG: addFeature erfolgreich")
|
||||
applyEditsWithPhotos(feature as ArcGISFeature, photos)
|
||||
}.onFailure {
|
||||
println("DEBUG: addFeature FEHLER: ${it.message}")
|
||||
snackBarMessage = "Fehler: ${it.message}"
|
||||
}
|
||||
|
||||
} catch (e: Exception) {
|
||||
println("DEBUG: CRASH in createFeature: ${e.message}")
|
||||
e.printStackTrace()
|
||||
snackBarMessage = "Fehler: ${e.message}"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun applyEditsWithPhotos(feature: ArcGISFeature, photos: List<ImageBitmap>) {
|
||||
serviceFeatureTable.applyEdits().onSuccess { editResults ->
|
||||
val result = editResults.firstOrNull()
|
||||
if (result != null && result.error == null) {
|
||||
val serverObjectId = result.objectId
|
||||
println("DEBUG: Server-Erfolg! Echte ObjectID: $serverObjectId")
|
||||
|
||||
if (photos.isNotEmpty()) {
|
||||
// Fix: erstellen eine Abfrage für die neue ID
|
||||
val queryParameters = com.arcgismaps.data.QueryParameters().apply {
|
||||
objectIds.add(serverObjectId)
|
||||
}
|
||||
|
||||
// laden das Feature neu vom Server
|
||||
serviceFeatureTable.queryFeatures(queryParameters).onSuccess { queryResult ->
|
||||
// Ein FeatureQueryResult ist ein Iterator, nehmen das erste Element
|
||||
val fetchedFeature = queryResult.firstOrNull() as? ArcGISFeature
|
||||
|
||||
if (fetchedFeature != null) {
|
||||
addPhotosToFeature(fetchedFeature, photos, serverObjectId)
|
||||
} else {
|
||||
println("DEBUG: Feature nach Query nicht gefunden")
|
||||
snackBarMessage = "Fehler: Feature-ID $serverObjectId nicht gefunden."
|
||||
}
|
||||
}.onFailure {
|
||||
println("DEBUG: Query fehlgeschlagen: ${it.message}")
|
||||
snackBarMessage = "Fotos konnten nicht zugeordnet werden."
|
||||
}
|
||||
} else {
|
||||
snackBarMessage = "Erfolgreich gemeldet! ID: $serverObjectId"
|
||||
}
|
||||
} else {
|
||||
println("DEBUG: Server-Fehler bei applyEdits: ${result?.error?.message}")
|
||||
snackBarMessage = "Serverfehler: ${result?.error?.message}"
|
||||
}
|
||||
}.onFailure {
|
||||
println("DEBUG: applyEdits total fehlgeschlagen: ${it.message}")
|
||||
snackBarMessage = "Senden fehlgeschlagen: ${it.message}"
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun addPhotosToFeature(
|
||||
feature: ArcGISFeature,
|
||||
photos: List<ImageBitmap>,
|
||||
objectId: Long?
|
||||
) {
|
||||
println("DEBUG: Füge ${photos.size} Fotos hinzu...")
|
||||
photos.forEachIndexed { index, imageBitmap ->
|
||||
try {
|
||||
val byteArray = imageBitmapToByteArray(imageBitmap)
|
||||
feature.addAttachment(
|
||||
name = "photo_$index.jpg",
|
||||
contentType = "image/jpeg",
|
||||
data = byteArray
|
||||
)
|
||||
} catch (e: Exception) {
|
||||
println("DEBUG: Attachment-Fehler bei Foto $index: ${e.message}")
|
||||
}
|
||||
}
|
||||
|
||||
serviceFeatureTable.updateFeature(feature).onSuccess {
|
||||
println("DEBUG: Feature mit Anhängen aktualisiert. Finales applyEdits...")
|
||||
serviceFeatureTable.applyEdits().onSuccess {
|
||||
snackBarMessage = "Gespeichert mit ${photos.size} Fotos! ID: $objectId"
|
||||
}
|
||||
}.onFailure {
|
||||
println("DEBUG: updateFeature für Anhänge fehlgeschlagen: ${it.message}")
|
||||
}
|
||||
}
|
||||
|
||||
private fun imageBitmapToByteArray(imageBitmap: ImageBitmap): ByteArray {
|
||||
val stream = ByteArrayOutputStream()
|
||||
imageBitmap.asAndroidBitmap().compress(android.graphics.Bitmap.CompressFormat.JPEG, 80, stream)
|
||||
return stream.toByteArray()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user