Let the message list be sorted by something other than the date

Newest-first was the only order, so the mail you had not read yet was
wherever it happened to fall.

Seven presets and up to three levels of your own. It covers the Inbox
alone by default: unread-first is what people want in the folder they
triage and confusing in Sent, where everything is read and the order that
matters is when it went. Search keeps newest-first whatever the setting
says, since a result list is already ordered by the question that was
asked.

The server does the sorting, over the whole folder, for the same reason
search runs there: a list sorted in the browser is sorted only as far as
the browser has loaded, which on a folder of ten thousand is the first
fifty and a lie about the rest.

Two details that are easy to get wrong and were worth pinning in tests.
hasKeyword sorts a boolean and false comes before true, so "unread first"
is $seen ASCENDING while "starred first" is $flagged DESCENDING -- the
other way round. Getting either backwards puts exactly the mail you were
looking for at the bottom. And every order ends with newest-first as a
tiebreak, because a sort whose last level is a keyword or a subject leaves
every tie undefined, and an undefined order changes between two looks at
the same folder for no reason the reader can see.

Sorting on a keyword is optional in RFC 8621, and a server that will not
do it fails the whole query rather than degrading it -- so this setting
could turn a folder into one that does not open. The refusal is caught
once, the keyword levels dropped and the query retried, and nothing is
said: the reader asked for an order and got the closest the server can
give, and a toast on every folder change would be the app complaining
about its own request.

The mock now honours the sort instead of always answering newest-first,
which had it reproducing a server that silently returns a different order
from the one asked for -- the one shape of wrongness a client cannot
detect. MOCK_NO_KEYWORD_SORT=1 reproduces a server that refuses the
keyword sorts, so the fallback can be developed against.
This commit is contained in:
2026-09-01 23:51:56 -07:00
parent 6c7c6d19b3
commit 34fc5ab81f
10 changed files with 480 additions and 4 deletions
+22
View File
@@ -150,6 +150,28 @@ more attempt. A drag that is merely more sideways than not stays a scroll.
- **Infinite scroll** with server-side paging, 50 at a time by default.
- **Conversation view** groups a thread into one row, with the thread's own
message count; it can be switched off to list messages individually.
- **Message order** is a setting: newest or oldest first, unread first, starred
first, largest first, by sender or by subject — or up to three levels of your
own, chosen in Settings General. It covers the Inbox alone by default,
because unread-first is what people want where they triage and confusing in
Sent, where everything is read; it can be widened to every folder.
The ordering is done by the **server**, over the whole folder, for the same
reason search is: a list sorted in the browser is sorted only as far as the
browser has loaded, which on a folder of ten thousand is the first fifty and
a lie about the rest. Search keeps newest-first whatever the setting says — a
result list is already ordered by the question that was asked.
Every order ends with newest-first as a tiebreak, so rows inside a tie do not
shuffle between two looks at the same folder.
**Sorting on a keyword is optional in RFC 8621**, and a server that will not
do it fails the whole query rather than degrading it — so "unread first" on
such a server would mean a folder that does not open at all. The refusal is
caught once, the keyword levels dropped, and the query retried, quietly: the
reader asked for an order and got the closest the server can give, and a
toast on every folder change would be the app complaining about its own
request. `MOCK_NO_KEYWORD_SORT=1` reproduces such a server.
- **Multi-select** with `x`, shift-click for ranges, `Ctrl/Cmd+A` for all, and
a long press on a touchscreen.
- **Select the whole folder**, not just the rows that happen to be loaded. The