- Sortieren nach Relevanz in Schadensliste
This commit is contained in:
@@ -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
|
||||||
|
|||||||
@@ -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(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))
|
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,7 +484,7 @@ 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)
|
||||||
@@ -385,7 +493,8 @@ fun DamageListItemWithPhoto(
|
|||||||
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
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -393,7 +502,6 @@ fun DamageListItemWithPhoto(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extension-Funktion für MapViewModel
|
* Extension-Funktion für MapViewModel
|
||||||
|
|||||||
Reference in New Issue
Block a user