Include the originator when assembling a reply thread - #230
Open
Xare123 wants to merge 1 commit into
Open
Conversation
threads() returned the originator only when addMessages had already registered it, which happens only if a reply reached the thread map first. A thread whose originator loaded before its replies rendered without the message being replied to. getThreadOriginator already registers it on demand, so call it before filtering. Also parse threadOriginatorPart properly. int.parse(part[0]) read a single character, so '12:0:0' resolved to 1 and matched the reply against the wrong part. A non-numeric leading character also threw from a plain int getter. Split on ':' and fall back to 0.
Xare123
marked this pull request as ready for review
July 26, 2026 00:04
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.
Two related defects in reply thread assembly. Both are present on
v2-rustpushtoday and both are reproducible by hand.1. The thread omits the message being replied to
ChatMessages.threads()returns the originator only if it is already present in_threads[originatorGuid]. The only place that registers it isaddMessages:That branch requires the map entry to already exist, which is true only when a reply was added first. So the behavior depends on load order:
The second ordering is the common one, because the originator is older than its replies. In practice, opening a threaded reply shows the reply with no context — you cannot see what it was a reply to.
The class already has the fix.
getThreadOriginator()registers the originator on demand and its comment describes exactly this case:threads()just never calls it. This change calls it before filtering, so the fix reuses existing behavior rather than adding a new mechanism.The
returnOriginator ? ... : falseternary is also simplified toreturnOriginator && ..., which is equivalent.2. Multi-digit reply part indexes are truncated
threadOriginatorPartis a colon-delimited string such as"12:0:0". Indexing[0]takes a single character, so part 12 resolves to 1 and the reply is matched against the wrong part of the originating message. Any message with more than ten parts can attach a reply to the wrong bubble.int.parsealso throws on a non-numeric leading character, from what reads as a plainintgetter with a safe default.Fixed by splitting on
:and taking the first field, withtryParseand a0fallback so the getter cannot throw. Applied to both theioandhtmlvariants, which carried identical code.Scope
Deliberately narrow: three files, no behavior changes outside thread assembly. This does not touch the thread popup's rendering, keyboard handling, or the delivery path.
I also have a lazy-rendering change for the thread popup that helps noticeably on chains of a few hundred messages, but it is an enhancement rather than a correctness fix, so I left it out to keep this reviewable. Happy to open it separately.
Testing
Both defects are demonstrated, not just described. Seven tests, run twice on
v2-rustpush— once against the branch unmodified, once with this change applied. Nothing else differed between the runs.Unmodified
v2-rustpush— 4 passed, 3 failed:With this change — 7 passed.
The four that already passed unmodified are the control: originator-loads-after-replies (the ordering that happens to work today),
returnOriginator: false, a single-digit part, and a null part. They still pass, so existing behavior is unchanged.flutter analyzeon Dart 3.12.2: 36 issues before this change, the same 36 after. No new errors or warnings.v2-rustpushhas notest/directory andflutter_testis commented out inpubspec.yaml, so I kept the harness out of this PR rather than add test infrastructure inside a bug fix. The seven tests are written and ready — happy to add them in a follow-up commit if you want the harness enabled.A note on CI
CI on this branch will still fail, for reasons unrelated to this change:
v2-rustpushcannot resolve dependencies at all right now. Its pinned Flutter 3.24.0 predates three dependency constraints, and the pinnedtelephony_plusrequirespermission_handler ^11.3.1while this branch requires^12.0.1. The companion PR fixes the version blockers and diagnoses the rest. The test runs above used that workflow fix plus a temporarypermission_handleroverride.A full APK build with these three files also succeeds under the same conditions.
Behavior was not re-tested on-device against v2, only unit-tested and compiled. The same two defects were observed and fixed on a
rustpush-based build running on a Pixel 10 Pro.