- Sortieren nach Relevanz in Schadensliste

This commit is contained in:
2026-01-30 12:56:14 +01:00
parent d05da838a8
commit 8eeeb2ce99
2 changed files with 132 additions and 23 deletions

View File

@@ -1,6 +1,7 @@
package com.example.snapandsolve package com.example.snapandsolve
import DamageFilterDialog import DamageFilterDialog
import DamageListDialog
import MapViewModel import MapViewModel
import android.Manifest import android.Manifest
import android.R.attr.enabled import android.R.attr.enabled

View File

@@ -1,5 +1,3 @@
package com.example.snapandsolve.ui.theme
import MapViewModel import MapViewModel
import android.content.Context import android.content.Context
import android.graphics.BitmapFactory import android.graphics.BitmapFactory
@@ -16,6 +14,7 @@ import androidx.compose.material.icons.filled.Close
import androidx.compose.material.icons.filled.Image import androidx.compose.material.icons.filled.Image
import androidx.compose.material.icons.filled.LocationOn import androidx.compose.material.icons.filled.LocationOn
import androidx.compose.material.icons.filled.MyLocation import androidx.compose.material.icons.filled.MyLocation
import androidx.compose.material.icons.filled.TrendingUp
import androidx.compose.material3.* import androidx.compose.material3.*
import androidx.compose.runtime.* import androidx.compose.runtime.*
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
@@ -72,7 +71,15 @@ fun calculateDistance(lat1: Double, lon1: Double, lat2: Double, lon2: Double): D
} }
/** /**
* Dialog für Schadensliste mit Entfernungsfilter * Enum für Sortierung
*/
enum class SortBy {
DISTANCE, // Nach Entfernung sortieren (nächste zuerst)
RELEVANCE // Nach Relevanz sortieren (höchste communitycounter zuerst)
}
/**
* Dialog für Schadensliste mit Entfernungs- und Relevanz-Filter
*/ */
@Composable @Composable
fun DamageListDialog( fun DamageListDialog(
@@ -87,6 +94,8 @@ fun DamageListDialog(
var maxDistance by remember { mutableStateOf(1000f) } var maxDistance by remember { mutableStateOf(1000f) }
var userLocation by remember { mutableStateOf<Point?>(null) } var userLocation by remember { mutableStateOf<Point?>(null) }
var errorMessage by remember { mutableStateOf<String?>(null) } var errorMessage by remember { mutableStateOf<String?>(null) }
var sortBy by remember { mutableStateOf(SortBy.DISTANCE) }
var minRelevance by remember { mutableStateOf(0) }
LaunchedEffect(maxDistance) { LaunchedEffect(maxDistance) {
isLoading = true isLoading = true
@@ -107,6 +116,15 @@ fun DamageListDialog(
isLoading = false isLoading = false
} }
// Sortierte und gefilterte Liste
val filteredAndSortedDamages = remember(damages, sortBy, minRelevance) {
val filtered = damages.filter { it.rating >= minRelevance }
when (sortBy) {
SortBy.DISTANCE -> filtered.sortedBy { it.distanceInMeters }
SortBy.RELEVANCE -> filtered.sortedByDescending { it.rating }
}
}
Dialog(onDismissRequest = onDismiss) { Dialog(onDismissRequest = onDismiss) {
Card( Card(
modifier = Modifier modifier = Modifier
@@ -138,7 +156,7 @@ fun DamageListDialog(
Divider(modifier = Modifier.padding(vertical = 12.dp)) Divider(modifier = Modifier.padding(vertical = 12.dp))
// Entfernungs-Slider // ===== ENTFERNUNGS-FILTER =====
Column(modifier = Modifier.fillMaxWidth()) { Column(modifier = Modifier.fillMaxWidth()) {
Row( Row(
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
@@ -176,11 +194,100 @@ fun DamageListDialog(
} }
} }
Spacer(modifier = Modifier.height(12.dp)) Spacer(modifier = Modifier.height(16.dp))
// ===== SORTIERUNG =====
Column(modifier = Modifier.fillMaxWidth()) {
Text(
text = "Sortieren nach:",
style = MaterialTheme.typography.titleSmall,
fontWeight = FontWeight.Bold,
modifier = Modifier.padding(bottom = 8.dp)
)
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.spacedBy(8.dp)
) {
// Distance Button
FilterChip(
selected = sortBy == SortBy.DISTANCE,
onClick = { sortBy = SortBy.DISTANCE },
label = {
Row(
horizontalArrangement = Arrangement.spacedBy(4.dp),
verticalAlignment = Alignment.CenterVertically
) {
Text("📍 Entfernung")
}
},
modifier = Modifier.weight(1f)
)
// Relevance Button
FilterChip(
selected = sortBy == SortBy.RELEVANCE,
onClick = { sortBy = SortBy.RELEVANCE },
label = {
Row(
horizontalArrangement = Arrangement.spacedBy(4.dp),
verticalAlignment = Alignment.CenterVertically
) {
Text("👥 Relevanz")
}
},
modifier = Modifier.weight(1f)
)
}
}
Spacer(modifier = Modifier.height(16.dp))
// ===== RELEVANZ-FILTER (nur wenn nach Relevanz sortiert) =====
if (sortBy == SortBy.RELEVANCE) {
Column(modifier = Modifier.fillMaxWidth()) {
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
) {
Icon(
Icons.Default.TrendingUp,
contentDescription = "Relevanz",
tint = MaterialTheme.colorScheme.primary
)
Text(
text = "Min. Bewertungen: ${minRelevance}+",
style = MaterialTheme.typography.titleMedium,
fontWeight = FontWeight.Bold,
color = MaterialTheme.colorScheme.primary
)
}
Slider(
value = minRelevance.toFloat(),
onValueChange = { minRelevance = it.toInt() },
valueRange = 0f..50f,
steps = 49,
modifier = Modifier.fillMaxWidth()
)
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween
) {
Text("0", style = MaterialTheme.typography.bodySmall)
Text("50+", style = MaterialTheme.typography.bodySmall)
}
}
Spacer(modifier = Modifier.height(12.dp))
}
if (!isLoading && errorMessage == null) { if (!isLoading && errorMessage == null) {
Text( Text(
text = "${damages.size} Schäden gefunden", text = "${filteredAndSortedDamages.size} Schäden gefunden",
style = MaterialTheme.typography.bodyMedium, style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.secondary, color = MaterialTheme.colorScheme.secondary,
modifier = Modifier.padding(bottom = 8.dp) modifier = Modifier.padding(bottom = 8.dp)
@@ -232,7 +339,7 @@ fun DamageListDialog(
} }
} }
damages.isEmpty() -> { filteredAndSortedDamages.isEmpty() -> {
Box( Box(
modifier = Modifier.fillMaxSize(), modifier = Modifier.fillMaxSize(),
contentAlignment = Alignment.Center contentAlignment = Alignment.Center
@@ -247,7 +354,7 @@ fun DamageListDialog(
) )
Spacer(modifier = Modifier.height(16.dp)) Spacer(modifier = Modifier.height(16.dp))
Text( Text(
text = "Keine Schäden im Umkreis", text = if (damages.isEmpty()) "Keine Schäden im Umkreis" else "Keine Schäden mit dieser Bewertung",
style = MaterialTheme.typography.bodyLarge style = MaterialTheme.typography.bodyLarge
) )
} }
@@ -259,7 +366,7 @@ fun DamageListDialog(
modifier = Modifier.fillMaxSize(), modifier = Modifier.fillMaxSize(),
verticalArrangement = Arrangement.spacedBy(12.dp) verticalArrangement = Arrangement.spacedBy(12.dp)
) { ) {
items(damages) { damage -> items(filteredAndSortedDamages) { damage ->
DamageListItemWithPhoto( DamageListItemWithPhoto(
damage = damage, damage = damage,
onClick = { onClick = {
@@ -277,7 +384,7 @@ fun DamageListDialog(
} }
/** /**
* Einzelnes Schadens-Item in der Liste MIT FOTO * Einzelnes Schadens-Item in der Liste MIT FOTO und BEWERTUNG
*/ */
@Composable @Composable
fun DamageListItemWithPhoto( fun DamageListItemWithPhoto(
@@ -357,12 +464,13 @@ fun DamageListItemWithPhoto(
maxLines = 1 maxLines = 1
) )
// Info-Row // Info-Row (Entfernung + Bewertung)
Row( Row(
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.spacedBy(12.dp), horizontalArrangement = Arrangement.spacedBy(12.dp),
verticalAlignment = Alignment.CenterVertically verticalAlignment = Alignment.CenterVertically
) { ) {
// Entfernung
Row( Row(
verticalAlignment = Alignment.CenterVertically, verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(2.dp) horizontalArrangement = Arrangement.spacedBy(2.dp)
@@ -376,18 +484,18 @@ fun DamageListItemWithPhoto(
) )
} }
if (damage.rating > 0) { // Bewertung / Relevanz
Row( Row(
verticalAlignment = Alignment.CenterVertically, verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(2.dp) horizontalArrangement = Arrangement.spacedBy(2.dp)
) { ) {
Text("👥", style = MaterialTheme.typography.labelSmall) Text("👥", style = MaterialTheme.typography.labelSmall)
Text( Text(
text = "${damage.rating}", text = "${damage.rating}",
style = MaterialTheme.typography.bodySmall, style = MaterialTheme.typography.bodySmall,
fontWeight = FontWeight.Bold fontWeight = FontWeight.Bold,
) color = if (damage.rating > 0) MaterialTheme.colorScheme.tertiary else MaterialTheme.colorScheme.outline
} )
} }
} }
} }