feat: refactor ListDetailScreen layout for improved header and content alignment; enhance empty state messaging
This commit is contained in:
+81
-80
@@ -495,93 +495,94 @@ fun ListDetailScreen(
|
|||||||
pendingScrollToBottom = false
|
pendingScrollToBottom = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Column(
|
// Header: horizontally scrollable across the table width
|
||||||
|
Row(
|
||||||
modifier =
|
modifier =
|
||||||
Modifier
|
Modifier
|
||||||
.fillMaxSize()
|
.horizontalScroll(horizontalScrollState)
|
||||||
.horizontalScroll(horizontalScrollState),
|
.background(MaterialTheme.colorScheme.surface),
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
) {
|
) {
|
||||||
// Fixed header (always visible even with zero items)
|
stableFields.forEach { field ->
|
||||||
Row(
|
key(field.id) {
|
||||||
modifier =
|
FieldHeader(
|
||||||
Modifier
|
field = field,
|
||||||
.fillMaxWidth()
|
width = fieldWidths[field.id] ?: 150.dp,
|
||||||
.background(MaterialTheme.colorScheme.surface),
|
onWidthChange = { delta ->
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
val currentWidth = fieldWidths[field.id] ?: 150.dp
|
||||||
) {
|
val newWidth = (currentWidth.value + delta).coerceAtLeast(100f)
|
||||||
stableFields.forEach { field ->
|
fieldWidths[field.id] = newWidth.dp
|
||||||
key(field.id) {
|
prefs.setColumnWidths(
|
||||||
FieldHeader(
|
listId,
|
||||||
field = field,
|
fieldWidths.mapValues { it.value.value },
|
||||||
width = fieldWidths[field.id] ?: 150.dp,
|
)
|
||||||
onWidthChange = { delta ->
|
},
|
||||||
val currentWidth = fieldWidths[field.id] ?: 150.dp
|
scrollState = horizontalScrollState,
|
||||||
val newWidth = (currentWidth.value + delta).coerceAtLeast(100f)
|
isLast = (field.id == stableFields.lastOrNull()?.id),
|
||||||
fieldWidths[field.id] = newWidth.dp
|
onHeaderClick = { showManageColumnsDialog = true },
|
||||||
prefs.setColumnWidths(
|
alignment = columnAlignments[field.id] ?: "start",
|
||||||
listId,
|
onAlignmentChange = { newAlign ->
|
||||||
fieldWidths.mapValues { it.value.value },
|
columnAlignments[field.id] = newAlign
|
||||||
)
|
viewModel.updateFieldAlignment(field.id, newAlign)
|
||||||
},
|
prefs.setColumnAlignments(listId, columnAlignments.toMap())
|
||||||
scrollState = horizontalScrollState,
|
},
|
||||||
isLast = (field.id == stableFields.lastOrNull()?.id),
|
)
|
||||||
onHeaderClick = { showManageColumnsDialog = true },
|
}
|
||||||
alignment = columnAlignments[field.id] ?: "start",
|
}
|
||||||
onAlignmentChange = { newAlign ->
|
}
|
||||||
columnAlignments[field.id] = newAlign
|
|
||||||
viewModel.updateFieldAlignment(field.id, newAlign)
|
// Content area: if empty, center message; else render horizontally scrollable rows
|
||||||
prefs.setColumnAlignments(listId, columnAlignments.toMap())
|
when {
|
||||||
},
|
isLoading && stableItems.isEmpty() -> {
|
||||||
|
Box(
|
||||||
|
modifier = Modifier.fillMaxSize(),
|
||||||
|
contentAlignment = Alignment.Center,
|
||||||
|
) { androidx.compose.material3.CircularProgressIndicator() }
|
||||||
|
}
|
||||||
|
stableItems.isEmpty() -> {
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxSize(),
|
||||||
|
contentAlignment = Alignment.Center,
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = stringResource(R.string.no_items),
|
||||||
|
style = MaterialTheme.typography.bodyLarge,
|
||||||
|
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(horizontal = 24.dp),
|
||||||
|
textAlign = TextAlign.Center,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
processedItems.isEmpty() -> {
|
||||||
|
Box(
|
||||||
|
modifier = Modifier.fillMaxSize(),
|
||||||
|
contentAlignment = Alignment.Center,
|
||||||
|
) {
|
||||||
|
Column(horizontalAlignment = Alignment.CenterHorizontally) {
|
||||||
|
Text(
|
||||||
|
text = "No items match the current filter",
|
||||||
|
style = MaterialTheme.typography.bodyLarge,
|
||||||
|
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||||
)
|
)
|
||||||
|
Spacer(modifier = Modifier.height(8.dp))
|
||||||
|
TextButton(onClick = {
|
||||||
|
filterField = null
|
||||||
|
filterValue = ""
|
||||||
|
}) { Text(stringResource(R.string.clear_filter)) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else -> {
|
||||||
// Render content states outside the horizontalScroll so empty state centers relative to viewport
|
// Content list in a horizontally scrollable container to stay aligned with header
|
||||||
when {
|
Column(
|
||||||
isLoading && stableItems.isEmpty() -> {
|
modifier =
|
||||||
Box(
|
Modifier
|
||||||
modifier = Modifier.fillMaxSize(),
|
.fillMaxSize()
|
||||||
contentAlignment = Alignment.Center,
|
.horizontalScroll(horizontalScrollState),
|
||||||
) { androidx.compose.material3.CircularProgressIndicator() }
|
) {
|
||||||
}
|
|
||||||
stableItems.isEmpty() -> {
|
|
||||||
// Use full-width Box + centered text (header remains above inside scroll container)
|
|
||||||
Box(
|
|
||||||
modifier = Modifier.fillMaxSize(),
|
|
||||||
contentAlignment = Alignment.Center,
|
|
||||||
) {
|
|
||||||
Text(
|
|
||||||
text = stringResource(R.string.no_items),
|
|
||||||
style = MaterialTheme.typography.bodyLarge,
|
|
||||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.padding(horizontal = 24.dp),
|
|
||||||
textAlign = TextAlign.Center,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
processedItems.isEmpty() -> {
|
|
||||||
Box(
|
|
||||||
modifier = Modifier.fillMaxSize(),
|
|
||||||
contentAlignment = Alignment.Center,
|
|
||||||
) {
|
|
||||||
Column(horizontalAlignment = Alignment.CenterHorizontally) {
|
|
||||||
Text(
|
|
||||||
text = "No items match the current filter",
|
|
||||||
style = MaterialTheme.typography.bodyLarge,
|
|
||||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
|
||||||
)
|
|
||||||
Spacer(modifier = Modifier.height(8.dp))
|
|
||||||
TextButton(onClick = {
|
|
||||||
filterField = null
|
|
||||||
filterValue = ""
|
|
||||||
}) { Text(stringResource(R.string.clear_filter)) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else -> {
|
|
||||||
LazyColumn(
|
LazyColumn(
|
||||||
modifier = Modifier.fillMaxSize(),
|
modifier = Modifier.fillMaxSize(),
|
||||||
state = listState,
|
state = listState,
|
||||||
|
|||||||
Reference in New Issue
Block a user