From 8eeeb2ce9966691d7d7885aab78e611fa1c3c2c6 Mon Sep 17 00:00:00 2001 From: si2503 Date: Fri, 30 Jan 2026 12:56:14 +0100 Subject: [PATCH] - Sortieren nach Relevanz in Schadensliste --- .../com/example/snapandsolve/MainScreen.kt | 1 + .../snapandsolve/ui/theme/DamageListSystem.kt | 154 +++++++++++++++--- 2 files changed, 132 insertions(+), 23 deletions(-) diff --git a/app/src/main/java/com/example/snapandsolve/MainScreen.kt b/app/src/main/java/com/example/snapandsolve/MainScreen.kt index a1b6bdc..0cea3f8 100644 --- a/app/src/main/java/com/example/snapandsolve/MainScreen.kt +++ b/app/src/main/java/com/example/snapandsolve/MainScreen.kt @@ -1,6 +1,7 @@ package com.example.snapandsolve import DamageFilterDialog +import DamageListDialog import MapViewModel import android.Manifest import android.R.attr.enabled diff --git a/app/src/main/java/com/example/snapandsolve/ui/theme/DamageListSystem.kt b/app/src/main/java/com/example/snapandsolve/ui/theme/DamageListSystem.kt index 2a01c54..79390e8 100644 --- a/app/src/main/java/com/example/snapandsolve/ui/theme/DamageListSystem.kt +++ b/app/src/main/java/com/example/snapandsolve/ui/theme/DamageListSystem.kt @@ -1,5 +1,3 @@ -package com.example.snapandsolve.ui.theme - import MapViewModel import android.content.Context 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.LocationOn import androidx.compose.material.icons.filled.MyLocation +import androidx.compose.material.icons.filled.TrendingUp import androidx.compose.material3.* import androidx.compose.runtime.* 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 fun DamageListDialog( @@ -87,6 +94,8 @@ fun DamageListDialog( var maxDistance by remember { mutableStateOf(1000f) } var userLocation by remember { mutableStateOf(null) } var errorMessage by remember { mutableStateOf(null) } + var sortBy by remember { mutableStateOf(SortBy.DISTANCE) } + var minRelevance by remember { mutableStateOf(0) } LaunchedEffect(maxDistance) { isLoading = true @@ -107,6 +116,15 @@ fun DamageListDialog( 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) { Card( modifier = Modifier @@ -138,7 +156,7 @@ fun DamageListDialog( Divider(modifier = Modifier.padding(vertical = 12.dp)) - // Entfernungs-Slider + // ===== ENTFERNUNGS-FILTER ===== Column(modifier = Modifier.fillMaxWidth()) { Row( 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) { Text( - text = "${damages.size} Schäden gefunden", + text = "${filteredAndSortedDamages.size} Schäden gefunden", style = MaterialTheme.typography.bodyMedium, color = MaterialTheme.colorScheme.secondary, modifier = Modifier.padding(bottom = 8.dp) @@ -232,7 +339,7 @@ fun DamageListDialog( } } - damages.isEmpty() -> { + filteredAndSortedDamages.isEmpty() -> { Box( modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center @@ -247,7 +354,7 @@ fun DamageListDialog( ) Spacer(modifier = Modifier.height(16.dp)) 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 ) } @@ -259,7 +366,7 @@ fun DamageListDialog( modifier = Modifier.fillMaxSize(), verticalArrangement = Arrangement.spacedBy(12.dp) ) { - items(damages) { damage -> + items(filteredAndSortedDamages) { damage -> DamageListItemWithPhoto( damage = damage, 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 fun DamageListItemWithPhoto( @@ -357,12 +464,13 @@ fun DamageListItemWithPhoto( maxLines = 1 ) - // Info-Row + // Info-Row (Entfernung + Bewertung) Row( modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.spacedBy(12.dp), verticalAlignment = Alignment.CenterVertically ) { + // Entfernung Row( verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(2.dp) @@ -376,18 +484,18 @@ fun DamageListItemWithPhoto( ) } - if (damage.rating > 0) { - Row( - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.spacedBy(2.dp) - ) { - Text("👥", style = MaterialTheme.typography.labelSmall) - Text( - text = "${damage.rating}", - style = MaterialTheme.typography.bodySmall, - fontWeight = FontWeight.Bold - ) - } + // Bewertung / Relevanz + Row( + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(2.dp) + ) { + Text("👥", style = MaterialTheme.typography.labelSmall) + Text( + text = "${damage.rating}", + style = MaterialTheme.typography.bodySmall, + fontWeight = FontWeight.Bold, + color = if (damage.rating > 0) MaterialTheme.colorScheme.tertiary else MaterialTheme.colorScheme.outline + ) } } }