fix(#25,#26,#28): Expenses screen polish — scrim, tab badges, shared SearchToolbar #37

Merged
admin merged 4 commits from fix/25-26-28-expenses-screen-polish into main 2026-06-28 14:33:43 +00:00

4 Commits

Author SHA1 Message Date
Achmad Setyabudi Susilo d5c0d395c5 Merge origin/main into fix/25-26-28-expenses-screen-polish
Main moved ahead with the home-polish (#29/#32/#33), category HSV color
picker (#30), and category lock-icon fix (#31) PRs. The only conflicts
were in ExpenseListScreen.kt:

- Imports: main added AppBar + EmptyStateIllustration. The branch had
  already removed AppBar (replaced by SearchToolbar) and replaced the
  inline text empty state. Resolution: keep the branch's
  AppBarTitle/SearchToolbar/TabText set, drop AppBar (no longer used),
  add EmptyStateIllustration.
- ExpensesTabContent empty state: main replaced the Box+Text
  'No expenses yet' with EmptyStateIllustration. Resolution: use
  EmptyStateIllustration (consistent with main's new design) but keep
  the branch's three-way message selection (no results vs no data).

For visual consistency between the two tabs, also swap
RecurringTabContent's empty state to EmptyStateIllustration. No
behavioral change for the recurring case — same per-tab vs no-results
message selection, same strings, just rendered through the shared
component.

All other files (build.gradle.kts, libs.versions.toml, HomeScreen,
SettingsScreen, CategoryScreen, EmptyStateIllustration.kt, strings.xml)
auto-merged cleanly.
2026-06-28 21:32:23 +07:00
Achmad Setyabudi Susilo 16236c6d6c fix(#26): replace inline search with SearchToolbar (debounced, shared)
Replace the inline OutlinedTextField inside ExpensesTabContent with
the shared SearchToolbar in the topBar. The query is shared across
both tabs; closing the toolbar (X / navigate-up) deactivates search
and clears the filter.

In ExpenseListScreenModel:
- searchQuery becomes StateFlow<String?> (null = inactive, "" = active
  empty, "foo" = active query)
- setSearchQuery now accepts String? to match SearchToolbar's
  onChangeSearchQuery signature
- expenses and recurring combine on
  _searchQuery.debounce(SEARCH_DEBOUNCE_MILLIS).distinctUntilChanged()
  so fast typing does not re-filter on every keystroke
- recurring is now filtered by query against category name and
  recurring note (case-insensitive substring)

In ExpenseListScreen:
- Remove the inline search field, the date-range-filter search hint
  label, and the now-unused OutlinedTextField / Icons.Outlined.Search
  imports
- Both ExpensesTabContent and RecurringTabContent now take a nullable
  searchQuery and show a generic 'No results' message when the active
  filter empties the list, or the per-tab empty copy otherwise
- Add the expense_list_no_results string
2026-06-28 21:23:13 +07:00
Achmad Setyabudi Susilo 5953111897 fix(#25): render expense tab counts via TabText
Replace the plain Text inside PrimaryTabRow's Tab with the shared
TabText composable. Pass the current size of the expenses and
recurring state flows as badgeCount so each tab shows a small pill
with the (post-filter) list size. Counts update reactively as
items are added, deleted, or filtered by search/date.
2026-06-28 21:22:09 +07:00
Achmad Setyabudi Susilo b698f5084f fix(#28): add scrim when ExpandedFab is open
Add ExpandedFabScrim composable that renders a Material 3 scrim
overlay fading in/out in sync with the mini-FABs. Tapping the scrim
dismisses the FAB.

Move the ExpandedFab out of Scaffold's floatingActionButton slot and
into the body inside a Box, so the scrim can match the body size via
matchParentSize() and stack above the list but below the FAB. Add a
BackHandler that dismisses the FAB on system back while it is open.
2026-06-28 21:21:36 +07:00