Jewelry AI · Library

Tapping a tab keeps your category, tool and date filters

The quick tabs and the advanced filters act on different parts of the same list. A tab press clears status, favorite and deleted, and leaves category, tool, date range and order exactly as you set them. The count on the filter button is counting only that second group.

Two controls, two axes, one list

The library has a row of quick tabs across the top and an advanced filter screen behind the filter button. They are not a shortcut and a long form of the same thing. They own different axes of the same list.

The tab row owns three dimensions: the status of a generation, whether it is marked as a favorite, and whether it is deleted. The advanced filters own four more: category, tool, date range and the order the list is in.

What comes back from either control is a list, not a file. Pressing a control changes which of your generations are listed and in what order - nothing about the images themselves is part of this screen.

What a tab press changes, and what it leaves alone

The question is worth answering precisely, because 'filters are kept' would be too loose to act on.

Cleared by the press: status, favorite, deleted.
The press starts from "const base: FeedFilters = { ...f, status: undefined, favorite: undefined, deleted: false };" and then applies the tab you pressed on top of that base.
Kept by the press: category, tool, date range.
None of the three is named in that line, so none of them is touched. A view narrowed to one category and one month stays narrowed while you move from Completed to Favorites and back.
Kept by the press: the order.
Newest or oldest survives a tab press in the same way the other three do. It is part of the advanced set, not part of the tab set.
The tab you are on is derived, not chosen separately.
Selecting a status such as Completed inside the advanced filters moves the tab at the top of the screen too. There is one filter state; the tab row is a view of part of it.

Which control owns which dimension

Seven dimensions, two controls, one count. The last column is the one the screen does not make obvious.

DimensionSet fromAfter a tab pressCounted by the filter badge
Status (processing, completed, failed)Tab row or advanced filtersCleared, then set by the tab you pressedNo
FavoriteTab rowCleared, then set by the tab you pressedNo
DeletedTab rowCleared, then set by the tab you pressedNo
CategoryAdvanced filtersKeptYes
ToolAdvanced filtersKeptYes
Date rangeAdvanced filtersKeptYes
Order (newest or oldest)Advanced filtersKeptYes, whenever it is not newest

Why the badge counts 'oldest first'

The number on the filter button counts the advanced filters that are away from their default. The order is one of them: newest is the default, so choosing oldest adds one to the count. That is the whole explanation for a badge reading 1 when, as far as you are concerned, you have not filtered anything.

The same rule works in the other direction. Status, favorite and deleted are never counted, because the tab row is already displaying them. A list showing only failed jobs, narrowed by a tab, can carry a badge showing nothing.

So the badge answers a narrower question than it appears to: not 'how much is narrowing this list' but 'how many advanced filters are away from their default'.

Building the view you actually want

Situations that come up with a large archive, and the control that answers each one.

SituationChooseWhy
Everything one tool produced within a date range, whatever its state.Set tool and date range in the advanced filters, leave the tab on All.Tool and date range survive tab presses, and All adds none of the three tab dimensions back after the press clears them.
Your favorites inside a single category.Set the category in the advanced filters first, then press Favorites.The press keeps the category and sets the favorite dimension in the same action.
The oldest items first, and a badge you can explain.Change the order in the advanced filters and expect the count to read one higher.Any order other than newest is counted as an advanced filter.
You need a particular status and you are already inside the advanced filters.Set it there and stop; do not press the matching tab afterwards.The active tab is derived from the filter state, so it has already moved to match your choice.
You will come back to this view later in the day.Open images freely, but plan to set the filters again after the app has been restarted.The selection is held in the screen's state and is not written to storage.

What survives leaving the screen

Opening a generated image and coming back to the library keeps your filter selection. This used to work the other way: returning from a result or processing screen reset the filters and the selection had to be rebuilt by hand. That reset was removed, so the habit of rebuilding is now unnecessary.

The boundary is worth stating exactly, because it is easy to over-read. The selection is preserved as long as the library screen lives, and it starts empty if the app restarts. It is not remembered between sessions, because it is never written to storage.

In practice: a long working session on one screen holds its view; a fresh start after a restart begins with no filters.

Limits worth knowing before you build a routine

Four boundaries that decide what a repeatable view can and cannot be.

  • Sorting has exactly two options, newest and oldest. There is no ordering by name, by category or by cost.
  • The filter badge counts advanced filters only. Status, favorite and deleted never add to it, so it is not a count of everything narrowing the list.
  • The tab row and the advanced filters are not independent. The active tab is derived from the filter state, so setting a status in the advanced filters moves the tab as well.
  • Filters are held in the library screen's state. They are preserved while that screen lives, and they start empty if the app restarts.

Before you rely on a filtered view

Five checks, in the order you would work through them.

  • Decide the state you want in one place - the tab row or the advanced filters, not both.
  • Set category, tool and date range in the advanced filters; a later tab press will keep all three.
  • Check the order before you read the list: newest is the default, oldest is the only alternative.
  • Read the tab and the badge together; the badge does not count what the tab is showing.
  • If the app has just been restarted, assume the filters are empty and set them again.

Where these statements come from

Every statement on this page was checked against the app's own source on 18 August 2026. There is no external document behind them.

Tab behaviour: apps/jewelry-mobile/src/features/generation/feed-filters.ts, where a tab press builds its base as "const base: FeedFilters = { ...f, status: undefined, favorite: undefined, deleted: false };". Category, tool, date range and order are absent from that line, which is why they survive.

The badge count: the same file, "if (f.sort !== 'newest') n++;" - the line that makes a non-default order count as an advanced filter.

Persistence: apps/jewelry-mobile/src/app/(tabs)/library.tsx:850, where the filter set is created with "useState<FeedFilters>(emptyFilters)". A comment in the same file records that the reset which used to run on every return to the library was removed.

Questions

If I tap a tab, do I lose the filters I set?

No. A tab press clears status, favorite and deleted, then applies the tab you pressed. Category, tool, date range and the order are untouched.

Why does the filter badge say 1 when the only thing I changed is 'oldest first'?

Because the order is counted as an advanced filter. Newest is the default, so any other order adds one to the count on the filter button.

Can I sort by name, by category or by cost?

No. There are exactly two orders, newest and oldest. To work through one category or one tool, narrow with the matching filter instead.

Do my filters survive opening an image, or closing the app?

Opening an image and returning to the library keeps them. They are held in the library screen's state only: preserved while that screen lives, empty again if the app restarts.