From 7b5abed587695f5ed75a99d9403be1d2cd304906 Mon Sep 17 00:00:00 2001 From: si2503 Date: Sat, 14 Feb 2026 12:52:03 +0100 Subject: [PATCH] =?UTF-8?q?-=20README=20hinzugef=C3=BCgt=20-=20BugFixing?= =?UTF-8?q?=20eigenen=20Standort.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/example/snapandsolve/MapViewModel.kt | 92 +++++++++++++------ .../snapandsolve/ui/theme/locationHelper.kt | 2 +- .../example/snapandsolve/view/ReportDialog.kt | 10 ++ docs/README.md | 73 +++++++++++++++ 4 files changed, 149 insertions(+), 28 deletions(-) create mode 100644 docs/README.md diff --git a/app/src/main/java/com/example/snapandsolve/MapViewModel.kt b/app/src/main/java/com/example/snapandsolve/MapViewModel.kt index f893dbf..cff9422 100644 --- a/app/src/main/java/com/example/snapandsolve/MapViewModel.kt +++ b/app/src/main/java/com/example/snapandsolve/MapViewModel.kt @@ -119,61 +119,73 @@ class MapViewModel(application: Application, context: Context) : AndroidViewMode } fun pickCurrentLocation() { - // keine Coroutine nötig, das ist alles sync val pos = locationDisplay?.location?.value?.position if (pos == null) { snackBarMessage = "Kein GPS Signal. Bitte kurz warten oder Standort aktivieren." return } - // pos ist ggf. schon Point, aber wir erzwingen WGS84 (sicher für deinen Feature-Service) - val pointWgs84 = - if (pos.spatialReference == SpatialReference.wgs84()) pos - else GeometryEngine.projectOrNull(pos, SpatialReference.wgs84()) as Point + // pos ist ggf. schon Point, aber wir erzwingen WGS84 + val pointWgs84 = if (pos.spatialReference == SpatialReference.wgs84()) { + pos + } else { + GeometryEngine.projectOrNull(pos, SpatialReference.wgs84()) as Point + } + // ===== KEIN Z hinzufügen! ===== updateReportDraft { copy(point = pointWgs84) } pointGraphic.geometry = pointWgs84 + + println("DEBUG pickCurrentLocation: point = $pointWgs84") + snackBarMessage = "Position aus GPS gesetzt." } private suspend fun applyEditsWithPhotos(feature: ArcGISFeature, photos: List) { + println("DEBUG applyEditsWithPhotos: START") + println("DEBUG applyEditsWithPhotos: photos.size = ${photos.size}") + + // ERST: Feature zum Server senden serviceFeatureTable.applyEdits().onSuccess { editResults -> + println("DEBUG applyEditsWithPhotos: applyEdits SUCCESS") + val result = editResults.firstOrNull() if (result != null && result.error == null) { val serverObjectId = result.objectId - println("DEBUG: Server-Erfolg! Echte ObjectID: $serverObjectId") + println("DEBUG: Server-Erfolg! ObjectID: $serverObjectId") if (photos.isNotEmpty()) { - // Fix: erstellen eine Abfrage für die neue ID + // Feature vom Server neu laden val queryParameters = 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) { + println("DEBUG: Feature neu geladen, füge Fotos hinzu...") addPhotosToFeature(fetchedFeature, photos, serverObjectId) } else { 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 { - println("DEBUG: Query fehlgeschlagen: ${it.message}") - snackBarMessage = "Fotos konnten nicht zugeordnet werden." + }.onFailure { error -> + println("DEBUG: Query fehlgeschlagen: ${error.message}") + snackBarMessage = "Feature erstellt, aber Fotos konnten nicht zugeordnet werden." } } else { + println("DEBUG: Keine Fotos, Feature erfolgreich erstellt!") 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}" + }.onFailure { error -> + println("DEBUG: applyEdits total fehlgeschlagen: ${error.message}") + error.printStackTrace() + snackBarMessage = "Senden fehlgeschlagen: ${error.message}" } } @@ -300,12 +312,16 @@ class MapViewModel(application: Application, context: Context) : AndroidViewMode private fun pickReportLocation(screen: ScreenCoordinate) { 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) { - reportDraft = reportDraft.copy(point = p) - pointGraphic.geometry = p + if (normalized != null) { + // ===== KEIN Z hinzufügen! ===== + reportDraft = reportDraft.copy(point = normalized) + pointGraphic.geometry = normalized reopenReport = true + + println("DEBUG pickReportLocation: point = $normalized") + snackBarMessage = "Position gesetzt." } else { snackBarMessage = "Position konnte nicht gesetzt werden." @@ -343,26 +359,48 @@ class MapViewModel(application: Application, context: Context) : AndroidViewMode viewModelScope.launch { 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 { - geometry = draft.point + geometry = point2D // ← OHNE Z! attributes["Beschreibung"] = draft.beschreibung attributes["Typ"] = draft.typ 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 { - // 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) - // Draft/Preview zurücksetzen (am besten nach Erfolg; fürs Erste hier ok) + // 4) Draft zurücksetzen resetDraft() - }.onFailure { - snackBarMessage = "Fehler beim Hinzufügen: ${it.message}" + }.onFailure { error -> + println("DEBUG: addFeature FAILED: ${error.message}") + snackBarMessage = "Fehler beim Hinzufügen: ${error.message}" } } catch (e: Exception) { + println("DEBUG: Exception in submitDraftToLayer: ${e.message}") + e.printStackTrace() snackBarMessage = "Fehler: ${e.message}" } } diff --git a/app/src/main/java/com/example/snapandsolve/ui/theme/locationHelper.kt b/app/src/main/java/com/example/snapandsolve/ui/theme/locationHelper.kt index 090b3c9..aef3055 100644 --- a/app/src/main/java/com/example/snapandsolve/ui/theme/locationHelper.kt +++ b/app/src/main/java/com/example/snapandsolve/ui/theme/locationHelper.kt @@ -42,7 +42,7 @@ class LocationHelper(private val context: Context) { /** * Composable zum Einrichten des Location Display - * + * Beim Auslagern wird diese Funktion nicht mehr genutzt. Das sollte gefixt werden!!!!!!!!!!!!!! */ @Composable fun setupLocationDisplay( diff --git a/app/src/main/java/com/example/snapandsolve/view/ReportDialog.kt b/app/src/main/java/com/example/snapandsolve/view/ReportDialog.kt index 8b436c6..4d68ea7 100644 --- a/app/src/main/java/com/example/snapandsolve/view/ReportDialog.kt +++ b/app/src/main/java/com/example/snapandsolve/view/ReportDialog.kt @@ -98,15 +98,25 @@ fun ReportDialog( text = { "Hinzufügen" }, style = AppButtonStyle.Outlined, 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 { checking = true showDuplicateDialog = mapViewModel.isDuplicateNearby(20.0) checking = false if (!showDuplicateDialog) { + println("DEBUG: Calling submitDraftToLayer()...") mapViewModel.submitDraftToLayer() viewModel.clearSelection() onCancel() + } else { + println("DEBUG: Duplicate gefunden, zeige Dialog") } } }, diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 0000000..74d6691 --- /dev/null +++ b/docs/README.md @@ -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). + +--- + + + +