refactor: offload filtering, sorting, and grouping to background thread for improved performance
This commit is contained in:
+71
-38
@@ -53,6 +53,7 @@ import androidx.compose.runtime.LaunchedEffect
|
|||||||
import androidx.compose.runtime.collectAsState
|
import androidx.compose.runtime.collectAsState
|
||||||
import androidx.compose.runtime.derivedStateOf
|
import androidx.compose.runtime.derivedStateOf
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.produceState
|
||||||
import androidx.compose.runtime.key
|
import androidx.compose.runtime.key
|
||||||
import androidx.compose.runtime.mutableStateListOf
|
import androidx.compose.runtime.mutableStateListOf
|
||||||
import androidx.compose.runtime.mutableStateMapOf
|
import androidx.compose.runtime.mutableStateMapOf
|
||||||
@@ -89,6 +90,8 @@ import kotlinx.coroutines.Job
|
|||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.isActive
|
import kotlinx.coroutines.isActive
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
import org.burnoutcrew.reorderable.ReorderableItem
|
import org.burnoutcrew.reorderable.ReorderableItem
|
||||||
import org.burnoutcrew.reorderable.detectReorder
|
import org.burnoutcrew.reorderable.detectReorder
|
||||||
import org.burnoutcrew.reorderable.rememberReorderableLazyListState
|
import org.burnoutcrew.reorderable.rememberReorderableLazyListState
|
||||||
@@ -194,46 +197,30 @@ fun ListDetailScreen(
|
|||||||
},
|
},
|
||||||
floatingActionButton = {},
|
floatingActionButton = {},
|
||||||
) { padding ->
|
) { padding ->
|
||||||
// Apply filtering, sorting, and grouping to items
|
// Apply filtering, sorting and grouping off the main thread and memoize the result
|
||||||
fun valueFor(
|
val transformed by produceState(
|
||||||
item: ItemWithValues,
|
initialValue = TransformedItems(emptyList(), mapOf("_all" to emptyList())),
|
||||||
field: Field?,
|
stableItems,
|
||||||
): String {
|
sortField,
|
||||||
if (field == null) return ""
|
sortAscending,
|
||||||
return item.values.find { it.fieldId == field.id }?.value ?: ""
|
groupByField,
|
||||||
|
filterField,
|
||||||
|
filterValue,
|
||||||
|
) {
|
||||||
|
value = withContext(Dispatchers.Default) {
|
||||||
|
transformItems(
|
||||||
|
items = stableItems,
|
||||||
|
sortField = sortField,
|
||||||
|
sortAscending = sortAscending,
|
||||||
|
groupByField = groupByField,
|
||||||
|
filterField = filterField,
|
||||||
|
filterValue = filterValue,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val filteredItems: List<ItemWithValues> =
|
val processedItems = transformed.processed
|
||||||
if (filterField != null && filterValue.isNotBlank()) {
|
val groupedItems = transformed.grouped
|
||||||
val needle = filterValue.lowercase(Locale.getDefault())
|
|
||||||
stableItems.filter { item ->
|
|
||||||
valueFor(item, filterField).lowercase(Locale.getDefault()).contains(needle)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
stableItems
|
|
||||||
}
|
|
||||||
|
|
||||||
// Default ordering: append new items at bottom by createdAt ascending.
|
|
||||||
// If an explicit sortField is chosen, use that instead.
|
|
||||||
val sortedItems: List<ItemWithValues> =
|
|
||||||
if (sortField != null) {
|
|
||||||
val base = filteredItems.sortedWith(compareBy { item -> valueFor(item, sortField) })
|
|
||||||
if (sortAscending) base else base.asReversed()
|
|
||||||
} else {
|
|
||||||
// Items from DB may not be ordered; enforce createdAt ascending
|
|
||||||
filteredItems.sortedBy { it.item.createdAt }
|
|
||||||
}
|
|
||||||
|
|
||||||
val processedItems: List<ItemWithValues> = sortedItems
|
|
||||||
|
|
||||||
val groupedItems: Map<String, List<ItemWithValues>> =
|
|
||||||
if (groupByField != null) {
|
|
||||||
processedItems.groupBy { item ->
|
|
||||||
valueFor(item, groupByField).ifBlank { "(Empty)" }
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
mapOf(" | |||||||