Skip to content

fix(chat): expire stale typing indicators locally - #1602

Merged
bmc08gt merged 1 commit into
code/cashfrom
fix/typing-indicator-expiry
Sep 28, 2026
Merged

bmc08gt merged 1 commit into
code/cashfrom
fix/typing-indicator-expiry

Conversation

@bmc08gt

@bmc08gt bmc08gt commented Sep 28, 2026

Copy link
Copy Markdown
Collaborator

A typing indicator could stay up in a chat indefinitely. EventStreamDelegate added a typist on STARTED/STILL and removed them only on STOPPED/TIMED_OUT, and nothing else ever wrote typingIndicators. The server relays typing best-effort with no timeout of its own, so a STOPPED lost to a backgrounded or killed sender, a network drop, or a stream reconnect left the typist on screen. This showed up in the "Moony" group: Android kept an indicator up while iOS showed nothing for the same chat.

iOS already expires typists locally (ConversationTyping, code-payments/code-ios-app#475). This matches it:

  • Typing state moves into TypingIndicatorTracker, now the only writer of ChatState.typingIndicators.
  • Each STARTED/STILL sets the typist's deadline to 10s out. A STILL keeps the original since, so a heartbeat no longer moves the typist to the back of the avatar row. Before this change every STILL restamped since.
  • One job is armed for the earliest deadline across all chats. It drops expired typists and re-arms for the next.
  • Notifications carrying the signed-in user's id are ignored.
  • clearAll() drops all typists and cancels the job.

The tracker takes a TimeSource, so the tests run on the test scheduler's virtual time. TypingIndicatorTrackerTest covers expiry at 10s, STILL extending the deadline without reordering, STOPPED/TIMED_OUT removal, self filtering, independent expiry across typists and chats, and clear(). EventStreamTypingTest checks the delegate wiring.

The server relays typing best-effort with no timeout, and the delegate
only removed a typist on STOPPED/TIMED_OUT. A lost STOPPED (sender
backgrounded or killed, network drop, stream reconnect) left the
indicator up for good.

Typing state moves into TypingIndicatorTracker, matching iOS's
ConversationTyping: each STARTED/STILL sets a 10s deadline while keeping
the typist's original `since`, one job re-armed for the earliest deadline
drops expired typists, the signed-in user's own notifications are
ignored, and clearAll() drops every typist.
@bmc08gt bmc08gt self-assigned this Sep 28, 2026
@github-actions github-actions Bot added the type: fix Bug fix label Sep 28, 2026
@bmc08gt
bmc08gt merged commit 0f49785 into code/cash Sep 28, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

type: fix Bug fix

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant