fix: message parts - use partIds and helpers instead of unstable indices (1/7) - #3152
Open
DeveloperBlue wants to merge 8 commits into
Open
fix: message parts - use partIds and helpers instead of unstable indices (1/7)#3152DeveloperBlue wants to merge 8 commits into
DeveloperBlue wants to merge 8 commits into
Conversation
Contributor
Author
DeveloperBlue
marked this pull request as ready for review
August 1, 2026 06:06
Contributor
Author
|
Ready to go, let me know if the PR changes are a good size |
DeveloperBlue
force-pushed
the
developerblue/fix/messageParts
branch
from
August 8, 2026 05:48
db171a5 to
fe09630
Compare
DeveloperBlue
force-pushed
the
developerblue/fix/messageParts
branch
from
August 10, 2026 04:27
8e9712e to
1b690c8
Compare
…ecent, and gallery cards
…ttachments (swipe-to-reply, popover, reply preview)
…ollapsed galleries via coversPartId
DeveloperBlue
force-pushed
the
developerblue/fix/messageParts
branch
from
August 10, 2026 04:49
1b690c8 to
f948391
Compare
DeveloperBlue
force-pushed
the
developerblue/fix/messageParts
branch
2 times, most recently
from
August 15, 2026 08:14
9571988 to
f948391
Compare
…to pr/DeveloperBlue/3152
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.
Message-parts APIs currently incorrectly treat
partslist indices as if they were iMessage part IDs. After edits, unsends, or gallery collapse, anything that keys off those values (replies, threads, swipe-to-reply, bubble chrome, and reactions) can target the wrong part or break.This PR adds helpers to look up parts by id (
partById,coversPartId),attachmentGuidfor replies to a specific gallery attachment, and leading/trailing helpers (isLeadingMessagePart/isTrailingMessagePart) so collapsed galleries still get the correct tails, connect styling, and reaction/sticker placement.Bugs Addressed:
Each architecture change is commit-by-commit, so you can review each commit individually for the scoped changes:
partByIdimplementation →partByIdcall sites →attachmentGuidfor reply contexts→ null guards for missing messageParts→ leading/trailing part helpers → per-part/per-attachment reaction and sticker matching →threadsForPartsso reply threads match any part id in a collapsed gallery span.see file changes
1. add partById to resolve message parts by id instead of unstable list index
Adds
MessageState.partByIdand switches reply/thread UI fromparts[index]to lookup byMessagePart.part, so targeting survives edits, unsends, and gallery collapse.lib/app/state/message_state.dart— AddpartById(lookup byMessagePart.part)lib/app/layouts/conversation_view/widgets/message/message_holder.dart— Resolve reply-target parts by idlib/app/layouts/conversation_view/widgets/message/reply/reply_bubble.dart— Load the replied-to part by idlib/app/layouts/conversation_view/widgets/text_field/reply_holder.dart— Reply composer preview uses id lookuplib/app/layouts/conversation_view/widgets/message/popup/actions/navigation_actions.dart— Thread originator resolved by id2. fix: use message-part ids for swipe-to-reply, bubble effects, reply-recent, and gallery cards
Propagates part ids through the remaining interaction surfaces, and records original part ids per attachment when consecutive media parts collapse into a gallery.
lib/database/global/message_part.dart—partIndexForAttachment/attachmentPartIndicesfor collapsed gallerieslib/app/layouts/conversation_view/widgets/message/attachment/message_image_gallery.dart— Per-card swipe/reply uses each attachment’s original part idlib/app/layouts/conversation_view/widgets/message/message_holder.dart— Swipe-to-reply / bubble effects use part idslib/app/layouts/conversation_view/widgets/message/misc/message_part_content.dart— Pass part id through content wrapperlib/services/backend_ui_interop/intents.dart— Reply Recent targetsparts.last.part, notparts.length - 13. fix: plumb attachmentGuid through reply context to resolve specific attachments
Extends reply context so a reply can target a specific attachment inside a multi-attachment part/gallery, not just the part id.
lib/models/message_reply_context.dart— OptionalattachmentGuidon reply contextlib/app/layouts/conversation_view/widgets/message/misc/swipe_to_reply_wrapper.dart— CarryattachmentGuidintoMessageReplyContextlib/app/layouts/conversation_view/widgets/message/popup/actions/navigation_actions.dart— Popover reply sets guid when the part has a single attachmentlib/app/layouts/conversation_view/widgets/text_field/reply_holder.dart— Preview resolves by guid first, then falls back topartById4. fix: guard reply/thread paths when a reply targets a missing message part
Makes reply/thread paths null-safe when
partByIdmisses (deleted, unsent, or out-of-sync parts) instead of force-unwrapping.lib/app/layouts/conversation_view/widgets/message/message_holder.dart— Null-safe matched part when rendering a reply targetlib/app/layouts/conversation_view/widgets/message/reply/reply_bubble.dart— Nullable part; skip/fallback instead of!lib/app/layouts/conversation_view/widgets/message/popup/actions/navigation_actions.dart— Guard thread open when originator part is missinglib/app/layouts/conversation_view/widgets/message/misc/swipe_to_reply_wrapper.dart— Align with safer reply-context constructionlib/models/message_reply_context.dart— ClarifypartIndexas message-part id5. fix: add isLeading/isTrailingMessagePart helpers for multipart layouts
Replaces list-position leading/trailing checks with span-aware helpers so bubble tails, connect styling, and chrome stay correct for collapsed galleries.
lib/database/global/message_part.dart—coversPartIdfor single parts and gallery spanslib/app/state/message_state.dart—isLeadingMessagePart/isTrailingMessagePartviacoversPartIdlib/app/layouts/conversation_view/widgets/message/message_holder.dart— Stickers, effects, connectUpper, tails use leading/trailing helperslib/app/layouts/conversation_view/widgets/message/parts/message_part_wrapper.dart— Same for bubble wrapper chromelib/app/layouts/conversation_view/widgets/message/attachment/attachment_holder.dart— Tail only on trailing partlib/app/layouts/conversation_view/widgets/message/message_holder/message_holder_timestamps.dart— Edit-history bubble chrome matches leading/trailing6. fix: target correct message parts for bubble reactions/stickers for collapsed galleries via coversPartId
Switches reaction/sticker matching to
coversPartIdso associations against any id in a collapsed gallery span still render on that bubble.lib/app/layouts/conversation_view/widgets/message/message_holder.dart—reactionsForParttakesMessagePartand filters viacoversPartIdlib/app/layouts/conversation_view/widgets/message/message_holder/message_holder_reactions.dart— Reactions, stickers, and spacing use span-aware matchinglib/app/layouts/conversation_view/widgets/message/message_holder/message_holder_timestamps.dart— Samsung timestamp padding uses the updated callbacklib/app/layouts/conversation_view/widgets/message/message_holder/message_reactions.dart— Reaction widget callback signature matches7. fix: resolve reply threads by message-part id across collapsed gallery part spans
Adds a multi-part thread lookup so replies keyed to any id covered by a collapsed gallery are found together, and keeps gallery reply UX per-attachment (native iMessage).
lib/database/global/chat_messages.dart—threadsForPartsmatchesnormalizedThreadPartagainst any originator part id in the setlib/app/layouts/conversation_view/widgets/message/message_holder.dart— Reply line decoration usesthreadsForPartswithattachmentPartIndiceslib/app/layouts/conversation_view/widgets/message/misc/message_properties.dart— Skip aggregate reply count on media galleries; otherwise usethreadsForPartslib/app/layouts/conversation_view/widgets/message/reply/reply_thread_popup.dart— Opening a thread from a gallery originator unions replies across covered part idsGroundwork for addressing #3122, #2605, and #2812