Expanding a conversation in the message list (row click, expand chevron,
or the `x` shortcut) and clicking a row in a Pro folder tab marked the
messages read straight away. They ignored "Mark as read: Never" and any
delay, which the reading pane and the conversation view follow.
Route them through one helper, scheduleAutoMarkAsRead: -1 never marks,
0 marks at once, any other value marks after that many milliseconds and
returns a cancel function.
- New store action autoMarkExpandedThreadAsRead keeps one pending timer
per thread key. Collapsing the thread, or collapsing all threads, drops
it. Both expansion paths (EmailList and the `x` handler in MailApp) use
it.
- MailApp's handleEmailSelect drops the pending mark of every expanded
thread other than the one the newly opened message belongs to, through
cancelAutoMarkThreadAsRead. Moving on with `j`/`k` or a click no longer
lets the delayed mark land on a conversation the user has left. The
thread stays expanded.
- ProFolderTabBody schedules the row mark through the helper and drops a
pending one when another row is opened or the tab unmounts.
`ProComposeTabBody` rendered `<EmailComposer>` without
`composeFromAccountEmail`; only the standard shell in
`components/mail/mail-app.tsx` passed it, so `mode === 'compose'` resolved
`findComposeIdentityId(identities, undefined)` to null and every new message
in the Pro shell defaulted to the account owner even with a shared folder
open. That covered the whole compose surface there, since the Pro shell
hoists every "show composer" intent - `mailto:` links included - into a tab.
Resolved exactly as the standard shell does, so both share one rule, but
read once at mount: a tab body stays mounted while the tab lives, so
subscribing to the mailbox list would re-render the composer and its editor
on every counter refresh.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>