Implement ExpenseListScreen, AddEditExpenseScreen, AddEditRecurringScreen #6

Closed
opened 2026-06-28 08:44:41 +00:00 by admin · 0 comments
Owner

Overview

Implements three screens:

  1. ExpenseListScreen — 2-tab screen (Expenses | Recurring) with tab-aware FAB
  2. AddEditExpenseScreen — shared add & edit form
  3. AddEditRecurringScreen — shared add & edit form for recurring templates

Depends on #2, #3, #4.

Prerequisites

Issues #1, #2, #3, #4 must all be merged first.

What to do

1. ui/screens/expenses/ExpenseListScreen.kt + ExpenseListScreenModel.kt

  • TabRow (Material 3) with 2 tabs: "Expenses", "Recurring".
  • HorizontalPager for swipeable content; bind pager state to tab selection.
  • Expenses tab: search field (text), filter chip for date range, list of ExpenseWithCategory. Tap row → navigator.push(AddEditExpenseScreen(expenseId = expense.id)). Long-press → delete confirmation dialog.
  • Recurring tab: list of RecurringExpenseWithCategory. Tap row → navigator.push(AddEditRecurringScreen(recurringId = recurring.id)). Toggle isActive inline.
  • Tab-aware FAB (single FAB that changes based on the selected tab):
    • Expenses tab selected → FAB expands to "Manual" (push AddEditExpenseScreen(null)) + "Import Bank Statement" (push ImportBankStatementScreen). Same as HomeScreen.
    • Recurring tab selected → FAB expands to only "Add Recurring" (push AddEditRecurringScreen(null)).
    • The expanded mini-FAB UI is shared; only the actions list is tab-driven. Pass the current tab state into the FAB composable.
  • Top app bar: Export icon (uses ExportAction helper from #7 — if #7 is not merged, stub inline).

2. ui/screens/add_edit_expense/AddEditExpenseScreen.kt + AddEditExpenseScreenModel.kt

Voyager Screen parameterized by an expenseId: Long?:

  • If expenseId == null, this is "add". If non-null, this is "edit" — prefill from getExpenses.awaitOne(expenseId).
  • Form fields:
    • Amount (numeric text field)
    • Category (dropdown of all categories from getCategories.subscribeAll(); current selection)
    • Date (Material 3 DatePicker dialog)
    • Note (multiline text field)
  • Top app bar: "Save" action. On save → upsertExpense.await(Expense(...))navigator.pop().
  • A "Manage Categories" button below the form → navigator.push(CategoryScreen). When user returns, the category dropdown auto-refreshes via the getCategories.subscribeAll() flow.

3. ui/screens/add_edit_recurring/AddEditRecurringScreen.kt + AddEditRecurringScreenModel.kt

Voyager Screen parameterized by recurringId: Long?:

  • If null, "add". If non-null, "edit" — prefill from getRecurringExpenses.awaitOne(recurringId).
  • Form fields:
    • Amount
    • Category (dropdown)
    • Interval (radio group: Daily, Weekly, Monthly, Yearly)
    • Start date (DatePicker)
    • Note (optional)
    • Active toggle (default true)
  • On save: build RecurringExpense(..., nextDueDate = startDate) and upsertRecurringExpense.await(...)navigator.pop().

Acceptance

  • ExpenseListScreen has 2 tabs with plain Compose TabRow + HorizontalPager
  • FAB actions change based on the selected tab
  • AddEditExpenseScreen works for both add and edit
  • AddEditRecurringScreen works for both add and edit, with nextDueDate = startDate on initial insert
  • All three screens build and ./gradlew assembleDebug succeeds

Implementation rule

Per AGENTS.md — do not start implementation without explicit user sign-off on this issue. When working, check for related issues in the remote repo first.

## Overview Implements three screens: 1. `ExpenseListScreen` — 2-tab screen (Expenses | Recurring) with **tab-aware FAB** 2. `AddEditExpenseScreen` — shared add & edit form 3. `AddEditRecurringScreen` — shared add & edit form for recurring templates Depends on #2, #3, #4. ## Prerequisites Issues #1, #2, #3, #4 must all be merged first. ## What to do ### 1. `ui/screens/expenses/ExpenseListScreen.kt` + `ExpenseListScreenModel.kt` - `TabRow` (Material 3) with 2 tabs: "Expenses", "Recurring". - `HorizontalPager` for swipeable content; bind pager state to tab selection. - **Expenses tab**: search field (text), filter chip for date range, list of `ExpenseWithCategory`. Tap row → `navigator.push(AddEditExpenseScreen(expenseId = expense.id))`. Long-press → delete confirmation dialog. - **Recurring tab**: list of `RecurringExpenseWithCategory`. Tap row → `navigator.push(AddEditRecurringScreen(recurringId = recurring.id))`. Toggle `isActive` inline. - **Tab-aware FAB** (single FAB that changes based on the selected tab): - **Expenses tab** selected → FAB expands to "Manual" (push `AddEditExpenseScreen(null)`) + "Import Bank Statement" (push `ImportBankStatementScreen`). Same as `HomeScreen`. - **Recurring tab** selected → FAB expands to only "Add Recurring" (push `AddEditRecurringScreen(null)`). - The expanded mini-FAB UI is shared; only the actions list is tab-driven. Pass the current tab state into the FAB composable. - Top app bar: Export icon (uses `ExportAction` helper from #7 — if #7 is not merged, stub inline). ### 2. `ui/screens/add_edit_expense/AddEditExpenseScreen.kt` + `AddEditExpenseScreenModel.kt` Voyager `Screen` parameterized by an `expenseId: Long?`: - If `expenseId == null`, this is "add". If non-null, this is "edit" — prefill from `getExpenses.awaitOne(expenseId)`. - Form fields: - Amount (numeric text field) - Category (dropdown of all categories from `getCategories.subscribeAll()`; current selection) - Date (Material 3 `DatePicker` dialog) - Note (multiline text field) - Top app bar: "Save" action. On save → `upsertExpense.await(Expense(...))` → `navigator.pop()`. - A "Manage Categories" button below the form → `navigator.push(CategoryScreen)`. When user returns, the category dropdown auto-refreshes via the `getCategories.subscribeAll()` flow. ### 3. `ui/screens/add_edit_recurring/AddEditRecurringScreen.kt` + `AddEditRecurringScreenModel.kt` Voyager `Screen` parameterized by `recurringId: Long?`: - If null, "add". If non-null, "edit" — prefill from `getRecurringExpenses.awaitOne(recurringId)`. - Form fields: - Amount - Category (dropdown) - Interval (radio group: Daily, Weekly, Monthly, Yearly) - Start date (DatePicker) - Note (optional) - Active toggle (default `true`) - On save: build `RecurringExpense(..., nextDueDate = startDate)` and `upsertRecurringExpense.await(...)` → `navigator.pop()`. ## Acceptance - [ ] `ExpenseListScreen` has 2 tabs with plain Compose `TabRow` + `HorizontalPager` - [ ] FAB actions change based on the selected tab - [ ] `AddEditExpenseScreen` works for both add and edit - [ ] `AddEditRecurringScreen` works for both add and edit, with `nextDueDate = startDate` on initial insert - [ ] All three screens build and `./gradlew assembleDebug` succeeds ## Implementation rule Per `AGENTS.md` — do not start implementation without explicit user sign-off on this issue. When working, check for related issues in the remote repo first.
admin referenced this issue from a commit 2026-06-28 12:49:04 +00:00
admin closed this issue 2026-06-28 12:57:17 +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#6