feat: add loading state management to ListDetailViewModel and display loading overlay in ListDetailScreen
This commit is contained in:
+19
-6
@@ -121,6 +121,7 @@ fun ListDetailScreen(
|
||||
val list by viewModel.list.collectAsState()
|
||||
val fields by viewModel.fields.collectAsState()
|
||||
val items by viewModel.items.collectAsState()
|
||||
val isLoading by viewModel.isLoading.collectAsState()
|
||||
|
||||
// Use derivedStateOf to create stable references
|
||||
val stableFields by remember { derivedStateOf { fields } }
|
||||
@@ -239,15 +240,18 @@ fun ListDetailScreen(
|
||||
|
||||
val processedItems = transformed.processed
|
||||
val groupedItems = transformed.grouped
|
||||
if (stableFields.isEmpty()) {
|
||||
// Root container to allow loading overlay
|
||||
Box(
|
||||
modifier =
|
||||
Modifier
|
||||
.fillMaxSize()
|
||||
.padding(padding),
|
||||
contentAlignment = Alignment.Center,
|
||||
) {
|
||||
Column(horizontalAlignment = Alignment.CenterHorizontally) {
|
||||
if (stableFields.isEmpty()) {
|
||||
Column(
|
||||
modifier = Modifier.align(Alignment.Center),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
) {
|
||||
Text(
|
||||
text = "No fields yet. Add fields to get started!",
|
||||
style = MaterialTheme.typography.bodyLarge,
|
||||
@@ -260,13 +264,11 @@ fun ListDetailScreen(
|
||||
Text(stringResource(R.string.add_field))
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Column(
|
||||
modifier =
|
||||
Modifier
|
||||
.fillMaxSize()
|
||||
.padding(padding),
|
||||
.fillMaxSize(),
|
||||
) {
|
||||
// Filter/Sort/Group Controls - Always visible above table
|
||||
Row(
|
||||
@@ -560,6 +562,17 @@ fun ListDetailScreen(
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Loading overlay during initial content load
|
||||
if (isLoading) {
|
||||
Box(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
contentAlignment = Alignment.Center,
|
||||
) {
|
||||
androidx.compose.material3.CircularProgressIndicator()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Items list below the fixed header
|
||||
|
||||
+24
@@ -34,6 +34,9 @@ class ListDetailViewModel(
|
||||
private val _items = MutableStateFlow<List<ItemWithValues>>(emptyList())
|
||||
val items: StateFlow<List<ItemWithValues>> = _items.asStateFlow()
|
||||
|
||||
private val _isLoading = MutableStateFlow(true)
|
||||
val isLoading: StateFlow<Boolean> = _isLoading.asStateFlow()
|
||||
|
||||
private val syncRepository = SyncRepository(context)
|
||||
|
||||
init {
|
||||
@@ -42,6 +45,15 @@ class ListDetailViewModel(
|
||||
}
|
||||
|
||||
private fun loadListData() {
|
||||
// Track first emissions to flip loading off after initial data is ready
|
||||
var hasList = false
|
||||
var hasFields = false
|
||||
var hasItems = false
|
||||
fun maybeLoaded() {
|
||||
if (hasList && hasFields && hasItems) {
|
||||
_isLoading.value = false
|
||||
}
|
||||
}
|
||||
viewModelScope.launch {
|
||||
database
|
||||
.listDao()
|
||||
@@ -49,6 +61,10 @@ class ListDetailViewModel(
|
||||
.debounce(75)
|
||||
.collect { listWithFields ->
|
||||
_list.value = listWithFields?.list
|
||||
if (!hasList) {
|
||||
hasList = true
|
||||
maybeLoaded()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,6 +75,10 @@ class ListDetailViewModel(
|
||||
.debounce(75)
|
||||
.collect { itemsData ->
|
||||
_items.value = itemsData
|
||||
if (!hasItems) {
|
||||
hasItems = true
|
||||
maybeLoaded()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,6 +89,10 @@ class ListDetailViewModel(
|
||||
.debounce(75)
|
||||
.collect { fieldsData ->
|
||||
_fields.value = fieldsData
|
||||
if (!hasFields) {
|
||||
hasFields = true
|
||||
maybeLoaded()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user