Skip to content

fix(chat): return the jump arrow to the message the reader left, not the chat bottom - #233

Merged
iebb merged 1 commit into
iebb:masterfrom
TiaraBasori:fix/reply-jump-return-origin
Oct 17, 2026
Merged

iebb merged 1 commit into
iebb:masterfrom
TiaraBasori:fix/reply-jump-return-origin

Conversation

@TiaraBasori

@TiaraBasori TiaraBasori commented Oct 17, 2026 •

Copy link
Copy Markdown
Contributor

Change

Tapping a message's replied-to quote jumps to the replied message. The floating arrow at the bottom right then returned to the chat bottom, which is not where the reader came from.

The arrow now returns to the message the reader was standing on before the jump:

  • An in-transcript jump (reply quote tap, the post-fix(chat): resolve and preserve reply anchors in channel post comment threads #224 reply-tap path, View in Chat, same-chat "view replies") records one origin: the topmost visible row and its viewport-local offset, measured the same way the session scroll anchor already is.
  • The origin is recorded once. A chain of jumps keeps the first one, because that is the place the reader actually left; and none is recorded when the reader is already at the newest edge, where the arrow's existing meaning is still correct.
  • Tapping the arrow consumes the origin and puts that row back at its recorded offset (restored by measurement, then corrected once more after layout, since the row may land in a different sliver window). If the row is no longer loaded, the tap falls through to the previous behavior instead of being swallowed. A second tap therefore goes to the bottom.
  • The origin is dropped when: it is consumed; a real drag carries the viewport at least max(120 px, 35% of the viewport) away from the drag baseline (a small nudge to read the quoted neighbourhood keeps it); the chat or topic changes; the session is prepared to exit, reopened or restored; the first-unread jump runs; or any explicit return-to-latest runs.
  • The unread pill keeps meaning "newest message" and bypasses the origin, so the two controls stay distinct.

The arrow's position, size, key and glyph are unchanged. _restoreSessionScrollAnchor now delegates to the same measured restore helper the jump return uses, so the two paths share one measurement instead of two.

Telegram API Terms classification

  • Compliant/unchanged: this change complies with applicable Telegram API Terms, preserves Telegram's basic functionality, and does not introduce behavior covered by section 1.4.
  • Section 1.4 exception: the entire feature is guarded by allowTelegramTosViolations (I_DONT_FUCKING_CARE_ABOUT_TOS), disabled in official builds, and available only in an explicitly enabled self-build.
  • Disallowed or unresolved: this PR must not be approved or merged until its classification and implementation are resolved.

Reason and affected Telegram behavior:

Scroll-position bookkeeping inside one open conversation; no request, no state persisted to Telegram, no new data flow.

Basic checks (every PR)

  • I reviewed the diff for correctness, unintended behavior, secrets, and unrelated changes.
  • Formatting passed: ~/.cache/dart3122/bin/dart format --output=none --set-exit-if-changed lib/chat/chat_view.dart test/chat_jump_origin_test.dart → Formatted 2 files (0 changed).
  • Analysis passed: /tmp/flutter-3.44.2/bin/flutter analyze lib/chat/chat_view.dart test/chat_jump_origin_test.dart → No issues found!.
  • Relevant tests passed: flutter test --no-pub -j 1 test/chat_jump_origin_test.dart → +6: All tests passed!. Neighbours, one invocation each, all pass: desktop_utility_window (+17), system_picture_in_picture_routing (+2), chat_view_exit_controller (+2), message_replies_sheet (+19) — the first three are the source-pinning suites that read chat_view.dart.
  • I checked affected build/platform paths and applicable localization/generated files: Dart-only, no string added or changed, generated l10n untouched. No new platform channel or native surface is involved (the button is the same Flutter widget).
  • I completed the Terms classification above and verified that official builds cannot enable section 1.4 exceptions.

Commands, results, platform/build/UI evidence, and reasons for inapplicable checks:

test/chat_jump_origin_test.dart drives the real ChatView against a TdClient proxy fixture (history returned newest→oldest; a positive getChatHistory offset throws, as TDLib would):

  1. the arrow returns to the message the reader left, not the bottom — after jumping to a quoted parent and tapping the arrow, the origin row sits at its recorded offset (±1.5 px), its neighbours are in place, and pixels < maxScrollExtent − 200 proves the viewport is not at the bottom.
  2. without a preceding jump the arrow still goes to the bottom — guards the old behavior.
  3. a chain of jumps returns to the first origin.
  4. a second tap after the origin is consumed goes to the bottom.
  5. a long user drag away from the jump target drops the origin.
  6. the history fixture keeps TDLib history semantics — the fixture itself honours the request contract.

Mutation checks: reverting only chat_view.dart to master fails the new suite, and disabling the drag release fails case 5.

Line counts (git show --numstat d6dfaa89):

161	4	lib/chat/chat_view.dart
467	0	test/chat_jump_origin_test.dart

Section 1.4 exception checks

Not applicable

Agentic reviewer confirmation

Agentic code reviewer only: record this confirmation in the PR review or check these boxes before approval.

  • I independently confirmed the Terms classification and inspected all required guards and evidence.
  • Applicable checks and Quality CI pass; no unresolved classification or unguarded section 1.4 behavior remains.

@TiaraBasori
TiaraBasori force-pushed the fix/reply-jump-return-origin branch from ca94eb9 to d6dfaa8 Compare October 17, 2026 16:24
@iebb
iebb merged commit f42118b into iebb:master Oct 17, 2026
1 check passed

@iebb iebb left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Merged as f42118b with cancellation repair abf9084. Review reproduced a pending origin return overriding a newer reply jump and jumping to the newest messages. The follow-up keeps restoration, its post-layout corrections and its fallback within the original navigation intent. Added the failing-first reply-cancellation case, a second-arrow/latest case, and a real negative-offset history fixture assertion. All 25 focused origin/search/reply boundary tests passed; the combined candidate focused run passed 54.

Independent reviewer confirmation: actual implementation and Telegram API Terms classification checked (compliant; no exception-gate expansion). Every selected exact PR head had passing applicable Quality before publication. The complete integrated result was published on master at abf9084: 3,654 unit/widget tests passed, one existing Linux-only test skipped on macOS; full analysis, formatting, all localization/generated assets and registration-anchor checks passed. Guard-state matrix: false 14, invalid 14, enabled 116 passing, plus a separate enabled-feature interaction and 13 independent search/reply checks. Validation used Flutter 3.44.2/Dart 3.12.2 and example credentials only. Native/build/release configuration is unchanged; no signing, release dispatch or physical-device QA was performed. Post-merge remote Quality is tracked separately from these local results.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants