Skip to content

fix(app): keep programmatic composer text updates on Android - #4071

Closed
magicbear wants to merge 1 commit into
getpaseo:mainfrom
magicbear:fix/composer-replace-text-stale-event-count
Closed

magicbear wants to merge 1 commit into
getpaseo:mainfrom
magicbear:fix/composer-replace-text-stale-event-count

Conversation

@magicbear

Copy link
Copy Markdown

Linked issue

Closes #3904

Type of change

  • Bug fix
  • New feature
  • Enhancement
  • Refactor
  • Docs

Reasoning

On Android, the composer's native text updates go through RN's setTextAndSelection command, and ReactEditText silently drops a JS text command whose event count is behind the native counter (canUpdateWithEventCount, ReactEditText.kt). JS only learns about native counter bumps asynchronously via onChange, so a programmatic replace that races an IME transition — exactly what happens when a dictation transcript is confirmed while the IME commits its composing region — carries a stale count and is dropped without any error.

This explains the symptoms in #3904 precisely:

  • The transcript is applied to the draft state (JS side), which is why tapping Send right after dictating sends the text and why switching sessions away and back shows it (the composer remounts with defaultValue from the draft store).
  • The native EditText itself never receives the text, so the visible input stays empty.

The fix is in the vendored @mattermost/react-native-paste-input patch that this repo already owns: replaceText now sends the maximum event count on Android. RN 0.81's Kotlin handler (maybeSetText / maybeSetSelection) only compares the count and never adopts the passed value (the native counter is only advanced by incrementAndGetEventCounter on native text changes), so this makes the write unconditional and cannot desync future updates. iOS keeps using the real count.

Goals

  • Dictated text reliably appears in the Android composer when confirming dictation (both Edit and Send flows), regardless of IME transitions happening at confirm time.
  • No change to user typing behavior or to iOS/web composers.

Non-goals

QA

  • Reproduced on Android 14 (per bug: Android: Dictated text is not populated into the prompt input when tapping Edit #3904 steps): start dictation, confirm with Edit → input stayed empty, while Send sent the text; switching sessions and back showed the draft. With the fix, the transcript populates the input immediately, including the worst case of dictating right after composing CJK text with the IME (composition commit races the confirm).
  • Verified the rebuilt APK's JS bundle contains the patched replaceText, and that normal typing, send, queue, and clear-after-send still behave.
  • npm run typecheck (0 errors), npm run lint (0 warnings), npm run format:check clean; packages/app/src/components/ui/text-input/text-input.native.test.tsx (5 tests) and packages/app/src/composer/input/state.test.ts (18 tests) pass.
  • Regenerated the patch with patch-package and verified it applies cleanly to a pristine @mattermost/react-native-paste-input@2.0.1 install.

Checklist

  • One focused change
  • npm run typecheck passes
  • npm run lint passes
  • npm run format passes
  • QA evidence
  • Tests added or updated where it made sense

Android's ReactEditText silently drops JS text commands whose event
count is behind the native counter, and JS only learns about native
counter bumps asynchronously via onChange. A programmatic replace that
races an IME transition (e.g. confirming dictation) can carry a stale
count and be dropped, leaving the native composer text stale while the
draft state stays correct — the dictated transcript was sendable but
invisible until the composer remounted.

The RN 0.81 Kotlin handler only compares the event count and never
adopts the passed value, so replaceText now sends the maximum count on
Android to make the write unconditional.
@boudra

boudra commented Sep 8, 2026

Copy link
Copy Markdown
Collaborator

Closing for now: this needs a failing-first regression for the Android IME/event-count race and a device recording or event trace showing dictation → Edit and subsequent typing work. Please reopen with that evidence.

@boudra boudra closed this Sep 8, 2026
@boudra

boudra commented Sep 9, 2026

Copy link
Copy Markdown
Collaborator

Please disregard the earlier invitation to reopen with evidence. This PR remains closed unless I explicitly follow up. You don't need to resubmit this PR or provide further QA evidence.

Please read the updated PR policy. For now, I'm automatically closing feature PRs so I can focus more time on bug fixes and core improvements. Focused bug-fix PRs with a clear reproduction and QA are still welcome. The previous guide already asked contributors to submit only if they were comfortable with closure, and explained that unsolicited PRs could be closed without a detailed review.

For feature ideas, please start in GitHub Discussions and share your workflow: what you're trying to do, how you do it today, and where Paseo gets in the way. If there's already a discussion about it, join in and share your use case. I'll periodically review discussions for highly requested workflows and use that feedback to shape the roadmap.

I'll periodically look through closed PRs and choose which contributions to take forward, whether solicited or unsolicited. I may reopen a PR, including one closed by mistake, or use it as a reference for my own implementation, with attribution either way.

There are hundreds of PRs alongside ongoing development. I can't commit to reviewing every submission, providing individual feedback or giving timelines.

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.

bug: Android: Dictated text is not populated into the prompt input when tapping Edit

2 participants