fix(chat): keep the focused message where it was long-pressed - #1400
Merged
Conversation
Editing a message part-way up the thread scrolled it off the top. The list is reverseLayout inside an imePadding'd scaffold, so the keyboard shortens the viewport from the bottom and every row rides up by the keyboard's height. FocusPin hands that height back to the list in the layout pass, letting its bottom-anchored content overflow behind the keyboard so the focused row lands back where it started. Reading the compensation in the layout phase is what keeps it in step with imePadding across the IME animation; a counter-scroll from an effect trails it by a frame the whole way down. The keyboard's height is not the whole of the movement. The input bar's navigationBarsPadding subtracts the insets the scaffold's imePadding has already consumed, so the bar loses its navigation-bar inset as the keyboard arrives and the list's bottom padding shrinks with it, dropping the content back down. Correcting for the keyboard alone left the row 63px low on a Pixel 10 emulator, exactly that inset, so the pin corrects for both terms. The total is capped at the room the row had above the composer, so a message already sitting near the bar rides up with the bar instead of being buried. On release it animates back to zero rather than being handed to the scroll position, which would have cost the transcript a keyboard's worth of history once the keyboard closed. The pin holds for the whole focus, not just the edit it can lead to. Tapping the composer with the selection bar up raises the keyboard as well, and a selected message pushed off the top is the same message lost from under the buttons acting on it. Around that: - The transcript stops taking drags for as long as the backdrop is up, selection and edit alike. It is behind the same scrim that already swallows taps. - A message arriving mid-edit still scrolls the list, but only as far as the point where the edited row would pass under the top bar. - A row long-pressed while it runs under the top bar is brought level with the bar's lower edge, so it isn't left sitting behind the buttons acting on it. - Back unwinds the edit, then the selection, before it leaves the conversation. MessageList had grown to the point where the per-row rendering obscured this, so the row, the pin, the read reporting and the receipt rules move to their own files.
bmc08gt
added a commit
that referenced
this pull request
Sep 3, 2026
Picks up #1397 (UserFlags), #1401 (restores KikCode+Badge/KikCode+Figure/ SVGPath/KikCodeFigureTests), and #1400 (FocusPin/MessageRow/ MessageReadReporter/ReceiptRules) via the true fork point as the merge base, correcting an earlier rewrite that had reparented this branch onto code/cash's graph without actually merging its content.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Editing a message part-way up the thread scrolled it off the top. The list is
reverseLayoutinside animePadding'd scaffold, so the keyboard shortens the viewport from the bottom and every row rides up by the keyboard's height.FocusPinhands that height back to the list in the layout pass, letting its bottom-anchored content overflow behind the keyboard so the focused row lands back where it started. Reading the compensation in the layout phase is what keeps it in step withimePaddingacross the IME animation; a counter-scroll from an effect trails it by a frame the whole way down.The keyboard's height is not the whole of the movement. The input bar's
navigationBarsPaddingsubtracts the insets the scaffold'simePaddinghas already consumed, so the bar loses its navigation-bar inset as the keyboard arrives and the list's bottom padding shrinks with it, dropping the content back down. Correcting for the keyboard alone left the row 63px low on a Pixel 10 emulator, exactly that inset, so the pin corrects for both terms. The total is capped at the room the row had above the composer, so a message already sitting near the bar rides up with the bar instead of being buried. On release it animates back to zero rather than being handed to the scroll position, which would have cost the transcript a keyboard's worth of history once the keyboard closed.The pin holds for the whole focus, not just the edit it can lead to. Tapping the composer with the selection bar up raises the keyboard as well, and a selected message pushed off the top is the same message lost from under the buttons acting on it.
Around that:
MessageListhad grown to the point where the per-row rendering obscured this, so the row, the pin, the read reporting and the receipt rules move to their own files.