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