The unified "All inboxes" PagingConfig left maxSize at the default Int.MAX_VALUE, so loaded pages were never evicted — a deep scroll accumulated every page in memory (grow-only, not a bounded sliding window). Set maxSize = MAILBOX_PAGE_SIZE * 5 (200), which satisfies the Paging invariant maxSize >= pageSize + 2*prefetchDistance (= 120). With enablePlaceholders = false, evicted leading positions drop from the loaded window and the list rendering already null-guards them.
MessageRow formatted the relative timestamp via DateUtils.getRelativeTimeSpanStringun-remembered, allocating a new String (and reading System.currentTimeMillis()) on every recomposition of the row. Wrapped it in remember(message.timestampMillis) { … }.
Testing
Preflight green: assembleDebug, testDebugUnitTest, lintDebug, ktlintCheck, detekt, and compileDebugAndroidTestKotlin. No behavioural change — same UI, less resident memory on deep scroll and no per-recomposition string allocation per row.
Two small, self-contained mailbox-list perf fixes from the Paging 3 audit.
## 1. Bound the paging window (`maxSize`) — Closes #212
The unified "All inboxes" `PagingConfig` left `maxSize` at the default `Int.MAX_VALUE`, so loaded pages were **never evicted** — a deep scroll accumulated every page in memory (grow-only, not a bounded sliding window). Set `maxSize = MAILBOX_PAGE_SIZE * 5` (200), which satisfies the Paging invariant `maxSize >= pageSize + 2*prefetchDistance` (= 120). With `enablePlaceholders = false`, evicted leading positions drop from the loaded window and the list rendering already null-guards them.
## 2. `remember()` the per-row timestamp — Closes #213
`MessageRow` formatted the relative timestamp via `DateUtils.getRelativeTimeSpanString` **un-`remember`ed**, allocating a new `String` (and reading `System.currentTimeMillis()`) on every recomposition of the row. Wrapped it in `remember(message.timestampMillis) { … }`.
## Testing
Preflight green: `assembleDebug`, `testDebugUnitTest`, `lintDebug`, `ktlintCheck`, `detekt`, and `compileDebugAndroidTestKotlin`. No behavioural change — same UI, less resident memory on deep scroll and no per-recomposition string allocation per row.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Two small, self-contained mailbox-list perf fixes from the Paging 3 audit.
1. Bound the paging window (
maxSize) — Closes #212The unified "All inboxes"
PagingConfigleftmaxSizeat the defaultInt.MAX_VALUE, so loaded pages were never evicted — a deep scroll accumulated every page in memory (grow-only, not a bounded sliding window). SetmaxSize = MAILBOX_PAGE_SIZE * 5(200), which satisfies the Paging invariantmaxSize >= pageSize + 2*prefetchDistance(= 120). WithenablePlaceholders = false, evicted leading positions drop from the loaded window and the list rendering already null-guards them.2.
remember()the per-row timestamp — Closes #213MessageRowformatted the relative timestamp viaDateUtils.getRelativeTimeSpanStringun-remembered, allocating a newString(and readingSystem.currentTimeMillis()) on every recomposition of the row. Wrapped it inremember(message.timestampMillis) { … }.Testing
Preflight green:
assembleDebug,testDebugUnitTest,lintDebug,ktlintCheck,detekt, andcompileDebugAndroidTestKotlin. No behavioural change — same UI, less resident memory on deep scroll and no per-recomposition string allocation per row.🤖 Generated with Claude Code