Empty states: Image (top) + text (bottom) on Home and Expenses #33

Closed
opened 2026-06-28 14:00:22 +00:00 by admin · 0 comments
Owner

Enhancement / UX

Both the Home and Expenses screens render an empty state as a single line of text:

  • Home: app/src/main/java/dev/achmad/ledgerr/ui/screens/home/HomeScreen.kt:232-239Text(stringResource(R.string.home_dashboard_empty), …) ("No expenses yet for this period") inside a LazyColumn item.
  • Expenses: app/src/main/java/dev/achmad/ledgerr/ui/screens/expenses/ExpenseListScreen.kt:242-254Text(stringResource(R.string.expense_list_empty), …) inside a Box(Modifier.fillMaxSize(), contentAlignment = Center).

The text floats in the middle of the list area but feels uninviting. The user wants a centered Image (top) + text (bottom) column.

Expected behavior

Replace the empty states with a new shared composable, e.g. EmptyStateIllustration (suggested location: app/src/main/java/dev/achmad/ledgerr/ui/components/EmptyStateIllustration.kt), with this layout:

Column(
    modifier = Modifier.fillMaxSize().padding(32.dp),
    horizontalAlignment = Alignment.CenterHorizontally,
    verticalArrangement = Arrangement.Center,
) {
    Image(
        painter = painterResource(R.drawable.ill_empty), // see below
        contentDescription = null,
        modifier = Modifier.size(120.dp),
        colorFilter = ColorFilter.tint(MaterialTheme.colorScheme.onSurfaceVariant),
    )
    Spacer(Modifier.height(16.dp))
    Text(
        text = message,
        style = MaterialTheme.typography.bodyMedium,
        color = MaterialTheme.colorScheme.onSurfaceVariant,
        textAlign = TextAlign.Center,
    )
}

Image asset

  • Add a single illustration to app/src/main/res/drawable/ (vector / xml if possible) — call it ill_empty.xml (or similar). A simple, on-brand line illustration is fine: a wallet, a receipt, or a "no data" mark. The size should look balanced at ~120.dp.
  • If a new asset is too much for this slice, the empty Image slot can be filled with a Material symbol (e.g. Icons.Outlined.ReceiptLong or Icons.Outlined.Inbox) as a placeholder — just keep the same Modifier.size(120.dp) and colorFilter treatment so the visual weight is identical.

Call sites

  1. HomeScreenHomeScreen.kt:231-240 (the else branch of if (recent.isNotEmpty())). The current code is a LazyColumn item { Text(...) }. The image+text column needs the remaining space, not just its own intrinsic height. Refactor the empty branch to render outside the LazyColumn (e.g. wrap DashboardContent in a Box, render the list as one child, render EmptyStateIllustration as a sibling that fills the remaining space and shows when recent.isEmpty()), OR keep the item but apply Modifier.fillParentMaxSize() and the same column layout.
  2. ExpenseListScreenExpenseListScreen.kt:242-254 (the empty branch in ExpensesTabContent). Already wrapped in Box(fillMaxSize, contentAlignment = Center), so swapping the Text for the new EmptyStateIllustration(message = stringResource(R.string.expense_list_empty)) is essentially a one-line change.

Acceptance criteria

  • The Home empty state shows an illustration centered vertically and horizontally in the available space below the chart / above the FAB.
  • The Expenses tab empty state shows the same illustration treatment, centered.
  • The illustration respects the current theme (uses onSurfaceVariant tint via colorFilter).
  • When the list is non-empty, no illustration is shown.
  • The existing string resources (R.string.home_dashboard_empty, R.string.expense_list_empty) are still used — no copy changes required for this slice.
  • The Home screen's recent section header (see #32) is hidden when the list is empty, so the illustration is the only thing in that area.
**Enhancement / UX** Both the Home and Expenses screens render an empty state as a single line of text: - Home: `app/src/main/java/dev/achmad/ledgerr/ui/screens/home/HomeScreen.kt:232-239` — `Text(stringResource(R.string.home_dashboard_empty), …)` ("No expenses yet for this period") inside a `LazyColumn` item. - Expenses: `app/src/main/java/dev/achmad/ledgerr/ui/screens/expenses/ExpenseListScreen.kt:242-254` — `Text(stringResource(R.string.expense_list_empty), …)` inside a `Box(Modifier.fillMaxSize(), contentAlignment = Center)`. The text floats in the middle of the list area but feels uninviting. The user wants a centered **Image (top) + text (bottom)** column. **Expected behavior** Replace the empty states with a new shared composable, e.g. `EmptyStateIllustration` (suggested location: `app/src/main/java/dev/achmad/ledgerr/ui/components/EmptyStateIllustration.kt`), with this layout: ```kotlin Column( modifier = Modifier.fillMaxSize().padding(32.dp), horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.Center, ) { Image( painter = painterResource(R.drawable.ill_empty), // see below contentDescription = null, modifier = Modifier.size(120.dp), colorFilter = ColorFilter.tint(MaterialTheme.colorScheme.onSurfaceVariant), ) Spacer(Modifier.height(16.dp)) Text( text = message, style = MaterialTheme.typography.bodyMedium, color = MaterialTheme.colorScheme.onSurfaceVariant, textAlign = TextAlign.Center, ) } ``` **Image asset** - Add a single illustration to `app/src/main/res/drawable/` (vector / `xml` if possible) — call it `ill_empty.xml` (or similar). A simple, on-brand line illustration is fine: a wallet, a receipt, or a "no data" mark. The size should look balanced at ~120.dp. - If a new asset is too much for this slice, the empty `Image` slot can be filled with a Material symbol (e.g. `Icons.Outlined.ReceiptLong` or `Icons.Outlined.Inbox`) as a placeholder — just keep the same `Modifier.size(120.dp)` and `colorFilter` treatment so the visual weight is identical. **Call sites** 1. **HomeScreen** — `HomeScreen.kt:231-240` (the `else` branch of `if (recent.isNotEmpty())`). The current code is a `LazyColumn` `item { Text(...) }`. The image+text column needs the **remaining** space, not just its own intrinsic height. Refactor the empty branch to render outside the `LazyColumn` (e.g. wrap `DashboardContent` in a `Box`, render the list as one child, render `EmptyStateIllustration` as a sibling that fills the remaining space and shows when `recent.isEmpty()`), OR keep the item but apply `Modifier.fillParentMaxSize()` and the same column layout. 2. **ExpenseListScreen** — `ExpenseListScreen.kt:242-254` (the empty branch in `ExpensesTabContent`). Already wrapped in `Box(fillMaxSize, contentAlignment = Center)`, so swapping the `Text` for the new `EmptyStateIllustration(message = stringResource(R.string.expense_list_empty))` is essentially a one-line change. **Acceptance criteria** - The Home empty state shows an illustration centered vertically and horizontally in the available space below the chart / above the FAB. - The Expenses tab empty state shows the same illustration treatment, centered. - The illustration respects the current theme (uses `onSurfaceVariant` tint via `colorFilter`). - When the list is non-empty, no illustration is shown. - The existing string resources (`R.string.home_dashboard_empty`, `R.string.expense_list_empty`) are still used — no copy changes required for this slice. - The Home screen's recent section header (see #32) is hidden when the list is empty, so the illustration is the only thing in that area.
admin closed this issue 2026-06-28 14:25:58 +00:00
Sign in to join this conversation.
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: admin/ledgerr#33