- README hinzugefügt
- BugFixing eigenen Standort.
This commit is contained in:
@@ -119,61 +119,73 @@ class MapViewModel(application: Application, context: Context) : AndroidViewMode
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun pickCurrentLocation() {
|
fun pickCurrentLocation() {
|
||||||
// keine Coroutine nötig, das ist alles sync
|
|
||||||
val pos = locationDisplay?.location?.value?.position
|
val pos = locationDisplay?.location?.value?.position
|
||||||
if (pos == null) {
|
if (pos == null) {
|
||||||
snackBarMessage = "Kein GPS Signal. Bitte kurz warten oder Standort aktivieren."
|
snackBarMessage = "Kein GPS Signal. Bitte kurz warten oder Standort aktivieren."
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// pos ist ggf. schon Point, aber wir erzwingen WGS84 (sicher für deinen Feature-Service)
|
// pos ist ggf. schon Point, aber wir erzwingen WGS84
|
||||||
val pointWgs84 =
|
val pointWgs84 = if (pos.spatialReference == SpatialReference.wgs84()) {
|
||||||
if (pos.spatialReference == SpatialReference.wgs84()) pos
|
pos
|
||||||
else GeometryEngine.projectOrNull(pos, SpatialReference.wgs84()) as Point
|
} else {
|
||||||
|
GeometryEngine.projectOrNull(pos, SpatialReference.wgs84()) as Point
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===== KEIN Z hinzufügen! =====
|
||||||
updateReportDraft { copy(point = pointWgs84) }
|
updateReportDraft { copy(point = pointWgs84) }
|
||||||
pointGraphic.geometry = pointWgs84
|
pointGraphic.geometry = pointWgs84
|
||||||
|
|
||||||
|
println("DEBUG pickCurrentLocation: point = $pointWgs84")
|
||||||
|
|
||||||
snackBarMessage = "Position aus GPS gesetzt."
|
snackBarMessage = "Position aus GPS gesetzt."
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun applyEditsWithPhotos(feature: ArcGISFeature, photos: List<ImageBitmap>) {
|
private suspend fun applyEditsWithPhotos(feature: ArcGISFeature, photos: List<ImageBitmap>) {
|
||||||
|
println("DEBUG applyEditsWithPhotos: START")
|
||||||
|
println("DEBUG applyEditsWithPhotos: photos.size = ${photos.size}")
|
||||||
|
|
||||||
|
// ERST: Feature zum Server senden
|
||||||
serviceFeatureTable.applyEdits().onSuccess { editResults ->
|
serviceFeatureTable.applyEdits().onSuccess { editResults ->
|
||||||
|
println("DEBUG applyEditsWithPhotos: applyEdits SUCCESS")
|
||||||
|
|
||||||
val result = editResults.firstOrNull()
|
val result = editResults.firstOrNull()
|
||||||
if (result != null && result.error == null) {
|
if (result != null && result.error == null) {
|
||||||
val serverObjectId = result.objectId
|
val serverObjectId = result.objectId
|
||||||
println("DEBUG: Server-Erfolg! Echte ObjectID: $serverObjectId")
|
println("DEBUG: Server-Erfolg! ObjectID: $serverObjectId")
|
||||||
|
|
||||||
if (photos.isNotEmpty()) {
|
if (photos.isNotEmpty()) {
|
||||||
// Fix: erstellen eine Abfrage für die neue ID
|
// Feature vom Server neu laden
|
||||||
val queryParameters = QueryParameters().apply {
|
val queryParameters = QueryParameters().apply {
|
||||||
objectIds.add(serverObjectId)
|
objectIds.add(serverObjectId)
|
||||||
}
|
}
|
||||||
|
|
||||||
// laden das Feature neu vom Server
|
|
||||||
serviceFeatureTable.queryFeatures(queryParameters).onSuccess { queryResult ->
|
serviceFeatureTable.queryFeatures(queryParameters).onSuccess { queryResult ->
|
||||||
// Ein FeatureQueryResult ist ein Iterator, nehmen das erste Element
|
|
||||||
val fetchedFeature = queryResult.firstOrNull() as? ArcGISFeature
|
val fetchedFeature = queryResult.firstOrNull() as? ArcGISFeature
|
||||||
|
|
||||||
if (fetchedFeature != null) {
|
if (fetchedFeature != null) {
|
||||||
|
println("DEBUG: Feature neu geladen, füge Fotos hinzu...")
|
||||||
addPhotosToFeature(fetchedFeature, photos, serverObjectId)
|
addPhotosToFeature(fetchedFeature, photos, serverObjectId)
|
||||||
} else {
|
} else {
|
||||||
println("DEBUG: Feature nach Query nicht gefunden")
|
println("DEBUG: Feature nach Query nicht gefunden")
|
||||||
snackBarMessage = "Fehler: Feature-ID $serverObjectId nicht gefunden."
|
snackBarMessage = "Feature erstellt (ID: $serverObjectId), aber Fotos konnten nicht hinzugefügt werden."
|
||||||
}
|
}
|
||||||
}.onFailure {
|
}.onFailure { error ->
|
||||||
println("DEBUG: Query fehlgeschlagen: ${it.message}")
|
println("DEBUG: Query fehlgeschlagen: ${error.message}")
|
||||||
snackBarMessage = "Fotos konnten nicht zugeordnet werden."
|
snackBarMessage = "Feature erstellt, aber Fotos konnten nicht zugeordnet werden."
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
println("DEBUG: Keine Fotos, Feature erfolgreich erstellt!")
|
||||||
snackBarMessage = "Erfolgreich gemeldet! ID: $serverObjectId"
|
snackBarMessage = "Erfolgreich gemeldet! ID: $serverObjectId"
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
println("DEBUG: Server-Fehler bei applyEdits: ${result?.error?.message}")
|
println("DEBUG: Server-Fehler bei applyEdits: ${result?.error?.message}")
|
||||||
snackBarMessage = "Serverfehler: ${result?.error?.message}"
|
snackBarMessage = "Serverfehler: ${result?.error?.message}"
|
||||||
}
|
}
|
||||||
}.onFailure {
|
}.onFailure { error ->
|
||||||
println("DEBUG: applyEdits total fehlgeschlagen: ${it.message}")
|
println("DEBUG: applyEdits total fehlgeschlagen: ${error.message}")
|
||||||
snackBarMessage = "Senden fehlgeschlagen: ${it.message}"
|
error.printStackTrace()
|
||||||
|
snackBarMessage = "Senden fehlgeschlagen: ${error.message}"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -300,12 +312,16 @@ class MapViewModel(application: Application, context: Context) : AndroidViewMode
|
|||||||
|
|
||||||
private fun pickReportLocation(screen: ScreenCoordinate) {
|
private fun pickReportLocation(screen: ScreenCoordinate) {
|
||||||
val mapPoint = mapViewProxy.screenToLocationOrNull(screen)
|
val mapPoint = mapViewProxy.screenToLocationOrNull(screen)
|
||||||
val p = mapPoint?.let { GeometryEngine.normalizeCentralMeridian(it) as? Point }
|
val normalized = mapPoint?.let { GeometryEngine.normalizeCentralMeridian(it) as? Point }
|
||||||
|
|
||||||
if (p != null) {
|
if (normalized != null) {
|
||||||
reportDraft = reportDraft.copy(point = p)
|
// ===== KEIN Z hinzufügen! =====
|
||||||
pointGraphic.geometry = p
|
reportDraft = reportDraft.copy(point = normalized)
|
||||||
|
pointGraphic.geometry = normalized
|
||||||
reopenReport = true
|
reopenReport = true
|
||||||
|
|
||||||
|
println("DEBUG pickReportLocation: point = $normalized")
|
||||||
|
|
||||||
snackBarMessage = "Position gesetzt."
|
snackBarMessage = "Position gesetzt."
|
||||||
} else {
|
} else {
|
||||||
snackBarMessage = "Position konnte nicht gesetzt werden."
|
snackBarMessage = "Position konnte nicht gesetzt werden."
|
||||||
@@ -343,26 +359,48 @@ class MapViewModel(application: Application, context: Context) : AndroidViewMode
|
|||||||
|
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
try {
|
try {
|
||||||
// 1) Feature lokal erstellen
|
println("DEBUG: Creating feature...")
|
||||||
|
|
||||||
|
// ===== FIX: Point OHNE Z erstellen =====
|
||||||
|
val point2D = if (draft.point != null) {
|
||||||
|
Point(
|
||||||
|
x = draft.point.x,
|
||||||
|
y = draft.point.y,
|
||||||
|
spatialReference = draft.point.spatialReference
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
|
||||||
|
println("DEBUG: Point 2D created: $point2D (hasZ = ${point2D?.hasZ})")
|
||||||
|
|
||||||
|
// 1) Feature lokal erstellen MIT 2D-Point
|
||||||
val feature = serviceFeatureTable.createFeature().apply {
|
val feature = serviceFeatureTable.createFeature().apply {
|
||||||
geometry = draft.point
|
geometry = point2D // ← OHNE Z!
|
||||||
attributes["Beschreibung"] = draft.beschreibung
|
attributes["Beschreibung"] = draft.beschreibung
|
||||||
attributes["Typ"] = draft.typ
|
attributes["Typ"] = draft.typ
|
||||||
attributes["status"] = draft.status
|
attributes["status"] = draft.status
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2) Erst addFeature + applyEdits => Feature existiert am Server (ObjectID)
|
println("DEBUG: Adding feature to table...")
|
||||||
|
|
||||||
|
// 2) Feature zur Tabelle hinzufügen
|
||||||
serviceFeatureTable.addFeature(feature).onSuccess {
|
serviceFeatureTable.addFeature(feature).onSuccess {
|
||||||
// applyEditsWithPhotos macht bei dir: applyEdits -> ObjectID holen -> feature neu queryn -> attachments adden
|
println("DEBUG: addFeature SUCCESS, calling applyEditsWithPhotos...")
|
||||||
|
|
||||||
|
// 3) JETZT ERST applyEdits mit Fotos
|
||||||
applyEditsWithPhotos(feature as ArcGISFeature, draft.photos)
|
applyEditsWithPhotos(feature as ArcGISFeature, draft.photos)
|
||||||
|
|
||||||
// Draft/Preview zurücksetzen (am besten nach Erfolg; fürs Erste hier ok)
|
// 4) Draft zurücksetzen
|
||||||
resetDraft()
|
resetDraft()
|
||||||
}.onFailure {
|
}.onFailure { error ->
|
||||||
snackBarMessage = "Fehler beim Hinzufügen: ${it.message}"
|
println("DEBUG: addFeature FAILED: ${error.message}")
|
||||||
|
snackBarMessage = "Fehler beim Hinzufügen: ${error.message}"
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
|
println("DEBUG: Exception in submitDraftToLayer: ${e.message}")
|
||||||
|
e.printStackTrace()
|
||||||
snackBarMessage = "Fehler: ${e.message}"
|
snackBarMessage = "Fehler: ${e.message}"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ class LocationHelper(private val context: Context) {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Composable zum Einrichten des Location Display
|
* Composable zum Einrichten des Location Display
|
||||||
*
|
* Beim Auslagern wird diese Funktion nicht mehr genutzt. Das sollte gefixt werden!!!!!!!!!!!!!!
|
||||||
*/
|
*/
|
||||||
@Composable
|
@Composable
|
||||||
fun setupLocationDisplay(
|
fun setupLocationDisplay(
|
||||||
|
|||||||
@@ -98,15 +98,25 @@ fun ReportDialog(
|
|||||||
text = { "Hinzufügen" },
|
text = { "Hinzufügen" },
|
||||||
style = AppButtonStyle.Outlined,
|
style = AppButtonStyle.Outlined,
|
||||||
onClick = {
|
onClick = {
|
||||||
|
// ===== DEBUG VOR DEM SUBMIT =====
|
||||||
|
println("DEBUG Button CLICKED: isValid = ${mapViewModel.reportDraft.isValid}")
|
||||||
|
println("DEBUG Button CLICKED: point = ${mapViewModel.reportDraft.point}")
|
||||||
|
println("DEBUG Button CLICKED: photos.size = ${mapViewModel.reportDraft.photos.size}")
|
||||||
|
println("DEBUG Button CLICKED: typ = '${mapViewModel.reportDraft.typ}'")
|
||||||
|
println("DEBUG Button CLICKED: beschreibung = '${mapViewModel.reportDraft.beschreibung}'")
|
||||||
|
|
||||||
scope.launch {
|
scope.launch {
|
||||||
checking = true
|
checking = true
|
||||||
showDuplicateDialog = mapViewModel.isDuplicateNearby(20.0)
|
showDuplicateDialog = mapViewModel.isDuplicateNearby(20.0)
|
||||||
checking = false
|
checking = false
|
||||||
|
|
||||||
if (!showDuplicateDialog) {
|
if (!showDuplicateDialog) {
|
||||||
|
println("DEBUG: Calling submitDraftToLayer()...")
|
||||||
mapViewModel.submitDraftToLayer()
|
mapViewModel.submitDraftToLayer()
|
||||||
viewModel.clearSelection()
|
viewModel.clearSelection()
|
||||||
onCancel()
|
onCancel()
|
||||||
|
} else {
|
||||||
|
println("DEBUG: Duplicate gefunden, zeige Dialog")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
73
docs/README.md
Normal file
73
docs/README.md
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
# Scan And Solve - Setup & Konfiguration
|
||||||
|
|
||||||
|
## Voraussetzungen
|
||||||
|
|
||||||
|
### ArcGIS Feature Layer
|
||||||
|
|
||||||
|
Die App benötigt einen ArcGIS Feature Layer mit spezifischen Attributen. Es gibt zwei Möglichkeiten:
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Option 1: Fertiger Demo-Layer (empfohlen)
|
||||||
|
|
||||||
|
Verwende den vorkonfigurierten Feature Layer:
|
||||||
|
|
||||||
|
```
|
||||||
|
https://services9.arcgis.com/UVxdrlZq3S3gqt7w/ArcGIS/rest/services/251120_StrassenSchaeden/FeatureServer/0
|
||||||
|
```
|
||||||
|
|
||||||
|
Dieser Layer enthält bereits alle erforderlichen Attribute und ist sofort einsatzbereit.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Option 2: Eigenen Layer konfigurieren
|
||||||
|
|
||||||
|
Falls du einen eigenen Feature Layer verwenden möchtest, müssen folgende Attribute hinzugefügt werden:
|
||||||
|
|
||||||
|
### Erforderliche Attribute
|
||||||
|
|
||||||
|
| Attributname | Typ | Beschreibung | Standardwert |
|
||||||
|
|--------------|-----|--------------|--------------|
|
||||||
|
| **communitycounter** | Integer | Anzahl der Nutzerbestätigungen (Upvotes/Downvotes) | 0 |
|
||||||
|
| **status** | String | Bearbeitungsstatus des Schadens | "neu" |
|
||||||
|
|
||||||
|
### Status-Werte
|
||||||
|
|
||||||
|
Das `status`-Attribut akzeptiert folgende Werte (siehe `StatusSymbolRenderer.kt`):
|
||||||
|
|
||||||
|
| Wert | Beschreibung | Farbe |
|
||||||
|
|------|--------------|-------|
|
||||||
|
| `"neu"` | Neu gemeldeter Schaden | 🔴 Rot |
|
||||||
|
| `"in Bearbeitung"` | Schaden wird bearbeitet | 🟠 Orange |
|
||||||
|
| `"Schaden behoben"` | Schaden wurde behoben | 🟢 Grün |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Berechtigungen & Benutzerrollen
|
||||||
|
|
||||||
|
### Nutzer-Rechte (App-Benutzer)
|
||||||
|
|
||||||
|
**Erlaubt:**
|
||||||
|
- Neue Schäden melden
|
||||||
|
- Fotos hochladen
|
||||||
|
- Community-Bewertungen abgeben (Upvote/Downvote)
|
||||||
|
- Schäden filtern und anzeigen
|
||||||
|
|
||||||
|
**Nicht erlaubt:**
|
||||||
|
- Status eines Schadens ändern
|
||||||
|
- Features löschen
|
||||||
|
|
||||||
|
### Mitarbeiter-Rechte (Internes Team)
|
||||||
|
|
||||||
|
**Erlaubt:**
|
||||||
|
- Alle Nutzer-Rechte
|
||||||
|
- Status ändern (neu → in Bearbeitung → behoben)
|
||||||
|
- Features löschen
|
||||||
|
|
||||||
|
> **Hinweis:** Der Status wird bei Erstellung automatisch auf `"neu"` gesetzt. Die Statusänderung erfolgt durch interne Mitarbeiter außerhalb der App (z.B. über ArcGIS Online).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Reference in New Issue
Block a user