- Code bereinigt
- MapView in MapSegment ausgelagert - Punkt kann jetzt manuell gesetzt werden - Eingaben werden erstmal im ReportDraft gespeichert
This commit is contained in:
@@ -2,6 +2,7 @@ package com.example.snapandsolve
|
||||
|
||||
import MapViewModel
|
||||
import android.Manifest
|
||||
import android.R.attr.enabled
|
||||
import android.app.Application
|
||||
import androidx.activity.compose.rememberLauncherForActivityResult
|
||||
import androidx.activity.result.PickVisualMediaRequest
|
||||
@@ -17,6 +18,8 @@ import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Add
|
||||
import androidx.compose.material.icons.filled.AddLocation
|
||||
import androidx.compose.material.icons.filled.AddLocationAlt
|
||||
import androidx.compose.material.icons.filled.FilterAlt
|
||||
import androidx.compose.material.icons.filled.FormatListNumbered
|
||||
import androidx.compose.material.icons.filled.Menu
|
||||
@@ -25,6 +28,7 @@ import androidx.compose.runtime.*
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.layout.ContentScale
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
@@ -44,10 +48,30 @@ import kotlinx.coroutines.Dispatchers
|
||||
@Composable
|
||||
fun MainScreen(modifier: Modifier = Modifier, application: Application) {
|
||||
var showReport by rememberSaveable { mutableStateOf(false) }
|
||||
var sliderOpen by remember { mutableStateOf(false) }
|
||||
var sliderOpen by rememberSaveable { mutableStateOf(false) }
|
||||
|
||||
val mapViewModel = remember { MapViewModel(application) }
|
||||
val albumViewModel = remember { AlbumViewModel(Dispatchers.Default) }
|
||||
|
||||
// test
|
||||
fun openReport() {
|
||||
showReport = true
|
||||
sliderOpen = false
|
||||
}
|
||||
|
||||
// test
|
||||
fun closeReport() {
|
||||
showReport = false
|
||||
}
|
||||
|
||||
LaunchedEffect(mapViewModel.reopenReport) {
|
||||
if (mapViewModel.reopenReport) {
|
||||
showReport = true
|
||||
mapViewModel.consumeReopenReport()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Scaffold(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
topBar = { AppTopBar() },
|
||||
@@ -64,8 +88,7 @@ fun MainScreen(modifier: Modifier = Modifier, application: Application) {
|
||||
floatingActionButton = {
|
||||
LargeFloatingActionButton(
|
||||
onClick = {
|
||||
showReport = true
|
||||
sliderOpen = false
|
||||
openReport()
|
||||
},
|
||||
modifier = Modifier.offset(y = 64.dp),
|
||||
containerColor = ButtonColor
|
||||
@@ -77,11 +100,11 @@ fun MainScreen(modifier: Modifier = Modifier, application: Application) {
|
||||
) { innerPadding ->
|
||||
ContentScreen(
|
||||
modifier = Modifier.padding(innerPadding),
|
||||
mapViewModel,
|
||||
albumViewModel,
|
||||
mapViewModel = mapViewModel,
|
||||
albumViewModel = albumViewModel,
|
||||
showReport = showReport,
|
||||
sliderOpen = sliderOpen,
|
||||
onDismissReport = { showReport = false }
|
||||
onDismissReport = ::closeReport
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -115,7 +138,9 @@ fun ContentScreen(
|
||||
)
|
||||
onDismissReport()
|
||||
},
|
||||
viewModel = albumViewModel
|
||||
onClose = onDismissReport,
|
||||
viewModel = albumViewModel,
|
||||
mapViewModel = mapViewModel
|
||||
)
|
||||
}
|
||||
|
||||
@@ -166,16 +191,21 @@ fun AppTopBar(
|
||||
fun ReportOverlay(
|
||||
onCancel: () -> Unit,
|
||||
onAdd: (beschreibung: String, typ: String) -> Unit,
|
||||
viewModel: AlbumViewModel
|
||||
onClose: () -> Unit,
|
||||
viewModel: AlbumViewModel,
|
||||
mapViewModel: MapViewModel
|
||||
) {
|
||||
val viewState: AlbumViewState by viewModel.viewStateFlow.collectAsState()
|
||||
val currentContext = LocalContext.current
|
||||
|
||||
// State für Beschreibung und Typ
|
||||
var beschreibung by remember { mutableStateOf("") }
|
||||
var selectedTyp by remember { mutableStateOf("Schadenstyp wählen...") }
|
||||
val hasPoint = mapViewModel.reportDraft.point != null
|
||||
var dropdownExpanded by remember { mutableStateOf(false) }
|
||||
|
||||
LaunchedEffect(viewState.selectedPictures) {
|
||||
mapViewModel.updateReportDraft {
|
||||
copy(photos = viewState.selectedPictures)
|
||||
}
|
||||
}
|
||||
|
||||
// Launcher für Bildauswahl aus Galerie
|
||||
val pickImageFromAlbumLauncher = rememberLauncherForActivityResult(
|
||||
ActivityResultContracts.PickMultipleVisualMedia(20)
|
||||
@@ -229,10 +259,17 @@ fun ReportOverlay(
|
||||
.background(Color.Black.copy(alpha = 0.25f)),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
BoxWithConstraints {
|
||||
val verticalMargin = 50.dp // <-- dein gewünschter Mindestabstand oben + unten
|
||||
val maxCardHeight = maxHeight - verticalMargin * 2
|
||||
|
||||
Card(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth(0.9f)
|
||||
.heightIn(min = 400.dp),
|
||||
.heightIn(
|
||||
min = 400.dp,
|
||||
max = maxCardHeight
|
||||
),
|
||||
shape = RoundedCornerShape(24.dp),
|
||||
colors = CardColors(
|
||||
containerColor = WidgetColor,
|
||||
@@ -256,17 +293,27 @@ fun ReportOverlay(
|
||||
onClick = { dropdownExpanded = true },
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
) {
|
||||
Text("Typ: $selectedTyp")
|
||||
Text("Typ: ${mapViewModel.reportDraft.typ}")
|
||||
}
|
||||
DropdownMenu(
|
||||
expanded = dropdownExpanded,
|
||||
onDismissRequest = { dropdownExpanded = false }
|
||||
) {
|
||||
listOf("Straße", "Gehweg", "Fahrradweg", "Beleuchtung","Sonstiges").forEach { typ ->
|
||||
listOf(
|
||||
"Straße",
|
||||
"Gehweg",
|
||||
"Fahrradweg",
|
||||
"Beleuchtung",
|
||||
"Sonstiges"
|
||||
).forEach { typ ->
|
||||
DropdownMenuItem(
|
||||
text = { Text(typ) },
|
||||
text = {
|
||||
Text(typ)
|
||||
},
|
||||
onClick = {
|
||||
selectedTyp = typ
|
||||
mapViewModel.updateReportDraft {
|
||||
copy(typ = typ)
|
||||
}
|
||||
dropdownExpanded = false
|
||||
}
|
||||
)
|
||||
@@ -299,8 +346,12 @@ fun ReportOverlay(
|
||||
|
||||
// Textfeld für Beschreibung
|
||||
TextField(
|
||||
value = beschreibung,
|
||||
onValueChange = { beschreibung = it },
|
||||
value = mapViewModel.reportDraft.beschreibung,
|
||||
onValueChange = {
|
||||
mapViewModel.updateReportDraft {
|
||||
copy(beschreibung = it)
|
||||
}
|
||||
},
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(220.dp),
|
||||
@@ -335,13 +386,38 @@ fun ReportOverlay(
|
||||
}
|
||||
}
|
||||
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.SpaceBetween
|
||||
) {
|
||||
Button(
|
||||
onClick = {
|
||||
|
||||
},
|
||||
) {
|
||||
Text("Position aus Standort")
|
||||
}
|
||||
Button(
|
||||
onClick = {
|
||||
mapViewModel.startPickReportLocation()
|
||||
onClose()
|
||||
},
|
||||
) {
|
||||
Text(if (hasPoint) "Position neu setzen" else "Position manuell setzen")
|
||||
}
|
||||
}
|
||||
|
||||
// Buttons
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.SpaceBetween
|
||||
) {
|
||||
OutlinedButton(
|
||||
onClick = onCancel,
|
||||
onClick = {
|
||||
mapViewModel.resetDraft()
|
||||
viewModel.clearSelection()
|
||||
onCancel()
|
||||
},
|
||||
colors = ButtonColors(
|
||||
containerColor = ButtonColor,
|
||||
contentColor = Color.White,
|
||||
@@ -352,8 +428,12 @@ fun ReportOverlay(
|
||||
Text("Abbrechen", color = Color.Black)
|
||||
}
|
||||
Button(
|
||||
onClick = { onAdd(beschreibung, selectedTyp) },
|
||||
enabled = beschreibung.isNotBlank()
|
||||
onClick = {
|
||||
mapViewModel.submitDraftToLayer()
|
||||
viewModel.clearSelection()
|
||||
onCancel()
|
||||
},
|
||||
enabled = mapViewModel.reportDraft.isValid
|
||||
) {
|
||||
Text("Hinzufügen")
|
||||
}
|
||||
@@ -361,4 +441,5 @@ fun ReportOverlay(
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -20,7 +20,11 @@ import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.core.content.ContextCompat
|
||||
import com.arcgismaps.ApiKey
|
||||
import com.arcgismaps.ArcGISEnvironment
|
||||
import com.arcgismaps.Color
|
||||
import com.arcgismaps.location.LocationDisplayAutoPanMode
|
||||
import com.arcgismaps.mapping.symbology.SimpleMarkerSymbol
|
||||
import com.arcgismaps.mapping.symbology.SimpleMarkerSymbolStyle
|
||||
import com.arcgismaps.mapping.view.GraphicsOverlay
|
||||
import com.arcgismaps.toolkit.geoviewcompose.MapView
|
||||
import com.arcgismaps.toolkit.geoviewcompose.rememberLocationDisplay
|
||||
import kotlinx.coroutines.launch
|
||||
@@ -68,7 +72,8 @@ fun MapSegment(
|
||||
arcGISMap = mapViewModel.map,
|
||||
locationDisplay = locationDisplay,
|
||||
mapViewProxy = mapViewModel.mapViewProxy,
|
||||
onSingleTapConfirmed = {}//mapViewModel::onTap,
|
||||
onSingleTapConfirmed = mapViewModel::onTap,
|
||||
graphicsOverlays = listOf(mapViewModel.tempOverlay)
|
||||
) {
|
||||
/* TODO */
|
||||
}
|
||||
|
||||
@@ -1,14 +1,20 @@
|
||||
import android.app.Application
|
||||
import android.graphics.Bitmap
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.ImageBitmap
|
||||
import androidx.compose.ui.graphics.asAndroidBitmap
|
||||
import androidx.compose.ui.unit.dp
|
||||
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.QueryParameters
|
||||
import com.arcgismaps.data.ServiceFeatureTable
|
||||
import com.arcgismaps.geometry.GeometryEngine
|
||||
import com.arcgismaps.geometry.Point
|
||||
@@ -17,25 +23,46 @@ 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.symbology.SimpleMarkerSymbol
|
||||
import com.arcgismaps.mapping.symbology.SimpleMarkerSymbolStyle
|
||||
import com.arcgismaps.mapping.symbology.SimpleRenderer
|
||||
import com.arcgismaps.mapping.view.Graphic
|
||||
import com.arcgismaps.mapping.view.GraphicsOverlay
|
||||
import com.arcgismaps.mapping.view.LocationDisplay
|
||||
import com.arcgismaps.mapping.view.ScreenCoordinate
|
||||
import com.arcgismaps.mapping.view.SingleTapConfirmedEvent
|
||||
import com.arcgismaps.toolkit.geoviewcompose.MapViewProxy
|
||||
import kotlinx.coroutines.launch
|
||||
import java.io.ByteArrayOutputStream
|
||||
|
||||
|
||||
class MapViewModel(application: Application) : AndroidViewModel(application) {
|
||||
val map: ArcGISMap = ArcGISMap(BasemapStyle.OpenOsmStyle).apply {
|
||||
initialViewpoint = Viewpoint(53.14, 8.20, 20000.0)
|
||||
}
|
||||
var selectedOperation by mutableStateOf(FeatureOperationType.DEFAULT)
|
||||
private set
|
||||
var reopenReport by mutableStateOf(false)
|
||||
private set
|
||||
|
||||
var selectedFeature: ArcGISFeature? by mutableStateOf(null)
|
||||
val mapViewProxy = MapViewProxy()
|
||||
|
||||
var reportDraft by mutableStateOf(ReportDraft())
|
||||
private set
|
||||
lateinit var featureLayer: FeatureLayer
|
||||
var snackBarMessage: String by mutableStateOf("")
|
||||
lateinit var serviceFeatureTable: ServiceFeatureTable
|
||||
var currentDamageType by mutableStateOf("")
|
||||
var damageTypeList: List<String> = mutableListOf()
|
||||
var locationDisplay: LocationDisplay? = null
|
||||
// Create a red circle simple marker symbol.
|
||||
val redCircleSymbol = SimpleMarkerSymbol(
|
||||
style = SimpleMarkerSymbolStyle.Circle,
|
||||
color = com.arcgismaps.Color.red,
|
||||
size = 10.0f
|
||||
)
|
||||
var pointGraphic = Graphic(null, redCircleSymbol)
|
||||
val tempOverlay = GraphicsOverlay()
|
||||
|
||||
init {
|
||||
viewModelScope.launch {
|
||||
@@ -113,7 +140,7 @@ class MapViewModel(application: Application) : AndroidViewModel(application) {
|
||||
|
||||
if (photos.isNotEmpty()) {
|
||||
// Fix: erstellen eine Abfrage für die neue ID
|
||||
val queryParameters = com.arcgismaps.data.QueryParameters().apply {
|
||||
val queryParameters = QueryParameters().apply {
|
||||
objectIds.add(serverObjectId)
|
||||
}
|
||||
|
||||
@@ -176,7 +203,213 @@ class MapViewModel(application: Application) : AndroidViewModel(application) {
|
||||
|
||||
private fun imageBitmapToByteArray(imageBitmap: ImageBitmap): ByteArray {
|
||||
val stream = ByteArrayOutputStream()
|
||||
imageBitmap.asAndroidBitmap().compress(android.graphics.Bitmap.CompressFormat.JPEG, 80, stream)
|
||||
imageBitmap.asAndroidBitmap().compress(Bitmap.CompressFormat.JPEG, 80, stream)
|
||||
return stream.toByteArray()
|
||||
}
|
||||
|
||||
fun onTap(singleTapConfirmedEvent: SingleTapConfirmedEvent) {
|
||||
|
||||
if (featureLayer.loadStatus.value != LoadStatus.Loaded) {
|
||||
snackBarMessage = "Layer not loaded!"
|
||||
return
|
||||
}
|
||||
|
||||
when (selectedOperation) {
|
||||
FeatureOperationType.DEFAULT -> selectFeatureForAttributeEditAt(singleTapConfirmedEvent.screenCoordinate)
|
||||
FeatureOperationType.DELETE -> deleteFeatureAt(singleTapConfirmedEvent.screenCoordinate)
|
||||
FeatureOperationType.UPDATE_ATTRIBUTE -> selectFeatureForAttributeEditAt(singleTapConfirmedEvent.screenCoordinate)
|
||||
FeatureOperationType.UPDATE_GEOMETRY -> updateFeatureGeometryAt(singleTapConfirmedEvent.screenCoordinate)
|
||||
FeatureOperationType.PICK_REPORT_LOCATION -> pickReportLocation(singleTapConfirmedEvent.screenCoordinate)
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
|
||||
private fun deleteFeatureAt(screenCoordinate: ScreenCoordinate) {
|
||||
featureLayer?.let { featureLayer ->
|
||||
// Clear any existing selection.
|
||||
featureLayer.clearSelection()
|
||||
selectedFeature = null
|
||||
viewModelScope.launch {
|
||||
// Determine if a user tapped on a feature.
|
||||
mapViewProxy.identify(featureLayer, screenCoordinate, 10.dp).onSuccess { identifyResult ->
|
||||
selectedFeature = (identifyResult.geoElements.firstOrNull() as? ArcGISFeature)?.also {
|
||||
featureLayer.selectFeature(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun selectFeatureForAttributeEditAt(screenCoordinate: ScreenCoordinate) {
|
||||
featureLayer?.let { featureLayer ->
|
||||
// Clear any existing selection.
|
||||
featureLayer.clearSelection()
|
||||
selectedFeature = null
|
||||
viewModelScope.launch {
|
||||
// Determine if a user tapped on a feature.
|
||||
mapViewProxy.identify(featureLayer, screenCoordinate, 10.dp).onSuccess { identifyResult ->
|
||||
// Get the identified feature.
|
||||
val identifiedFeature = identifyResult.geoElements.firstOrNull() as? ArcGISFeature
|
||||
identifiedFeature?.let {
|
||||
val currentAttributeValue = it.attributes["typ"] as String
|
||||
currentDamageType = currentAttributeValue
|
||||
selectedFeature = it.also {
|
||||
featureLayer.selectFeature(it)
|
||||
}
|
||||
} ?: run {
|
||||
// Reset damage type if no feature identified.
|
||||
currentDamageType = ""
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateFeatureGeometryAt(screenCoordinate: ScreenCoordinate) {
|
||||
|
||||
featureLayer?.let { featureLayer ->
|
||||
when (selectedFeature) {
|
||||
// When no feature is selected.
|
||||
null -> {
|
||||
viewModelScope.launch {
|
||||
// Determine if a user tapped on a feature.
|
||||
mapViewProxy.identify(featureLayer, screenCoordinate, 10.dp).onSuccess { identifyResult ->
|
||||
// Get the identified feature.
|
||||
val identifiedFeature = identifyResult.geoElements.firstOrNull() as? ArcGISFeature
|
||||
identifiedFeature?.let {
|
||||
selectedFeature = it.also {
|
||||
featureLayer.selectFeature(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// When a feature is selected, update its geometry to the tapped location.
|
||||
else -> {
|
||||
mapViewProxy.screenToLocationOrNull(screenCoordinate)?.let { mapPoint ->
|
||||
// Normalize the point - needed when the tapped location is over the international date line.
|
||||
val destinationPoint = GeometryEngine.normalizeCentralMeridian(mapPoint)
|
||||
viewModelScope.launch {
|
||||
selectedFeature?.let { selectedFeature ->
|
||||
// Load the feature.
|
||||
selectedFeature.load().onSuccess {
|
||||
// Update the geometry of the selected feature.
|
||||
selectedFeature.geometry = destinationPoint
|
||||
// Apply the edit to the feature table.
|
||||
serviceFeatureTable?.updateFeature(selectedFeature)
|
||||
// Push the update to the service with the service geodatabase.
|
||||
serviceFeatureTable?.applyEdits()?.onSuccess {
|
||||
snackBarMessage = "Moved feature ${selectedFeature.attributes["objectid"]}"
|
||||
}?.onFailure {
|
||||
snackBarMessage =
|
||||
"Failed to move feature ${selectedFeature.attributes["objectid"]}"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun pickReportLocation(screen: ScreenCoordinate) {
|
||||
val mapPoint = mapViewProxy.screenToLocationOrNull(screen)
|
||||
val p = mapPoint?.let { GeometryEngine.normalizeCentralMeridian(it) as? Point }
|
||||
|
||||
if (p != null) {
|
||||
reportDraft = reportDraft.copy(point = p)
|
||||
tempOverlay.graphics.clear()
|
||||
pointGraphic.geometry = p
|
||||
tempOverlay.graphics.add(pointGraphic)
|
||||
reopenReport = true
|
||||
snackBarMessage = "Position gesetzt."
|
||||
} else {
|
||||
snackBarMessage = "Position konnte nicht gesetzt werden."
|
||||
}
|
||||
|
||||
selectedOperation = FeatureOperationType.DEFAULT
|
||||
}
|
||||
|
||||
|
||||
fun startPickReportLocation() {
|
||||
selectedOperation = FeatureOperationType.PICK_REPORT_LOCATION
|
||||
snackBarMessage = "Tippe auf die Karte, um die Position zu setzen."
|
||||
}
|
||||
|
||||
fun consumeReopenReport() {
|
||||
reopenReport = false
|
||||
}
|
||||
|
||||
fun resetDraft() {
|
||||
reportDraft = ReportDraft()
|
||||
pointGraphic.geometry = null
|
||||
selectedOperation = FeatureOperationType.DEFAULT
|
||||
}
|
||||
|
||||
fun updateReportDraft(update: ReportDraft.() -> ReportDraft) {
|
||||
reportDraft = reportDraft.update()
|
||||
}
|
||||
|
||||
fun submitDraftToLayer() {
|
||||
val draft = reportDraft
|
||||
if (!draft.isValid) {
|
||||
snackBarMessage = "Bitte Beschreibung, Typ, Position und Fotos setzen."
|
||||
return
|
||||
}
|
||||
|
||||
viewModelScope.launch {
|
||||
try {
|
||||
// 1) Feature lokal erstellen
|
||||
val feature = serviceFeatureTable.createFeature().apply {
|
||||
geometry = draft.point
|
||||
attributes["Beschreibung"] = draft.beschreibung
|
||||
attributes["Typ"] = draft.typ
|
||||
}
|
||||
|
||||
// 2) Erst addFeature + applyEdits => Feature existiert am Server (ObjectID)
|
||||
serviceFeatureTable.addFeature(feature).onSuccess {
|
||||
// applyEditsWithPhotos macht bei dir: applyEdits -> ObjectID holen -> feature neu queryn -> attachments adden
|
||||
applyEditsWithPhotos(feature as ArcGISFeature, draft.photos)
|
||||
|
||||
// Draft/Preview zurücksetzen (am besten nach Erfolg; fürs Erste hier ok)
|
||||
resetDraft()
|
||||
}.onFailure {
|
||||
snackBarMessage = "Fehler beim Hinzufügen: ${it.message}"
|
||||
}
|
||||
|
||||
} catch (e: Exception) {
|
||||
snackBarMessage = "Fehler: ${e.message}"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
enum class FeatureOperationType(val operationName: String, val instruction: String) {
|
||||
DEFAULT("Default", ""),
|
||||
DELETE("Delete feature", "Select an existing feature to delete it."),
|
||||
UPDATE_ATTRIBUTE("Update attribute", "Select an existing feature to edit its attribute."),
|
||||
UPDATE_GEOMETRY("Update geometry", "Select an existing feature and tap the map to move it to a new position."),
|
||||
PICK_REPORT_LOCATION("Pick report location", "Tippe auf die Karte, um die Position zu setzen."),
|
||||
}
|
||||
|
||||
data class ReportDraft(
|
||||
val beschreibung: String = "",
|
||||
val typ: String = "Schadenstyp wählen...",
|
||||
val photos: List<ImageBitmap> = emptyList(),
|
||||
val point: Point? = null
|
||||
) {
|
||||
val isValid: Boolean
|
||||
get() =
|
||||
beschreibung.isNotBlank() &&
|
||||
typ != "Schadenstyp wählen..." &&
|
||||
point != null &&
|
||||
photos.isNotEmpty()
|
||||
}
|
||||
@@ -116,4 +116,7 @@ class AlbumViewModel(private val coroutineContext: CoroutineContext
|
||||
}
|
||||
}
|
||||
// endregion
|
||||
fun clearSelection() {
|
||||
_albumViewState.value = _albumViewState.value.copy(selectedPictures = emptyList())
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user