From bc86813cbc4affb1d1c0c06c9cf7c7d4c7dca111 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 2 Jun 2026 01:18:53 +0000 Subject: [PATCH] fix: load older history at the start of a short conversation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The conversation auto-fill only fired when the thread overflowed the screen, so a one-message room sat at its load-more boundary without ever advancing — you were at the start of the chat but it wouldn't reach for older messages. That overflow guard was added back when each widen re-downloaded the whole window (to stop a short thread auto-walking the gift-wrap firehose); now that history loads in bounded, non-re-downloading slices that reason is gone. Drop the overflow requirement: load the next slice whenever the oldest end is in view, including a thread too short to scroll. A one-message room now walks history back to its real beginning (or until the window is exhausted), one bounded slice at a time, gated on both loaders being idle. https://claude.ai/code/session_01B1fmmmX8JjQWH3amMLdvcW --- .../loggedIn/chats/privateDM/ChatroomView.kt | 26 ++++++++++--------- 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/ChatroomView.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/ChatroomView.kt index 38a02225f9..60eb3ffa3e 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/ChatroomView.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/ChatroomView.kt @@ -139,16 +139,17 @@ private const val PREFETCH_OLDER_MESSAGES = 3 /** * Scroll-driven history loader for a conversation. The thread is reverse-laid-out (newest at the - * bottom, index 0), so older messages live at higher indices. It loads the next, older window only - * when the thread already overflows the screen AND the user has scrolled near the oldest loaded - * message — so a short thread is never auto-walked to the start of history (that would load the whole - * account's gift-wrap history). For more than what scrolling reaches, the oldest-end boundary offers - * an explicit "Load entire history". + * bottom, index 0), so older messages (and the load-more boundary) live at the highest indices. It + * loads the next, older slice whenever the oldest end is in view — including a thread too short to + * scroll, so sitting at the start of a one-message chat keeps walking history back to its real + * beginning (or until the window is exhausted). Each step is a bounded, one-shot slice that never + * re-downloads, so walking a short thread is cheap per step — gift wraps can't be filtered per room, + * so this advances the shared account-wide history window and the conversation's messages surface as + * its slices are decrypted. * - * The account-wide gift-wrap window is the single source of truth for the floor: NIP-17 advances via - * [AccountGiftWrapsEoseManager.loadMore], and the NIP-04 loader [ChatroomNip04SubAssembler.reload] - * re-requests kind:4 from that same floor. The step is gated on BOTH loaders being idle, so it never - * outruns the slower protocol. + * NIP-17 advances via [AccountGiftWrapsHistoryEoseManager.loadMore]; the NIP-04 follower + * [ChatroomNip04HistorySubAssembler.reload] re-requests kind:4 at that same slice. The step is gated + * on BOTH loaders being idle, so it never outruns the slower protocol, and stops once exhausted. */ @Composable private fun LoadOlderMessagesWhenScrolling( @@ -164,8 +165,9 @@ private fun LoadOlderMessagesWhenScrolling( val info = listState.layoutInfo val total = info.totalItemsCount val lastVisible = info.visibleItemsInfo.lastOrNull()?.index ?: -1 - val overflowsScreen = info.visibleItemsInfo.size < total - overflowsScreen && lastVisible >= total - PREFETCH_OLDER_MESSAGES + // The oldest end is in view (no overflow requirement, so a one-message thread that + // can't scroll still qualifies and walks history to its start). + total > 0 && lastVisible >= total - PREFETCH_OLDER_MESSAGES }, giftWrapsHistory.loadingMore, nip04History.loadingMore, @@ -175,7 +177,7 @@ private fun LoadOlderMessagesWhenScrolling( }.distinctUntilChanged() .filter { it } .collect { - Log.d("DMPagination") { "convo: widen (scrolled near oldest) → loadMore + reload" } + Log.d("DMPagination") { "convo: widen (oldest in view) → loadMore + reload" } giftWrapsHistory.loadMore(accountViewModel.userProfile()) nip04History.reload() }