Skip to content

fix(chat): release the active chat only if it is still ours - #1517

Merged
bmc08gt merged 1 commit into
code/cashfrom
fix/active-chat-handoff
Sep 21, 2026
Merged

bmc08gt merged 1 commit into
code/cashfrom
fix/active-chat-handoff

Conversation

@bmc08gt

@bmc08gt bmc08gt commented Sep 21, 2026

Copy link
Copy Markdown
Collaborator

Opening a chat directly from another chat left notifications firing for the chat on screen — tap a push for chat B while chat A is open, land in B, and every subsequent message in B notifies.

Cause

The active chat id suppresses notifications for the conversation on screen (NotificationService.kt:261). Each chat screen claimed it on open and released it in onCleared — unconditionally, which is the bug. Navigation 3 keeps both entries alive across a chat-to-chat switch and disposes the outgoing one after the incoming one has already claimed the chat, so the outgoing screen's teardown cleared the chat the user was by then looking at.

An on-device trace caught the window:

13:58:55.368  Navigating to Chat[VDbei…]
13:58:55.892  disposeOwner: Chat[W4rX…]     <- 524ms later, clears VDbei

Going back to the chat list first puts the dispose ahead of the open, which is why the same chat behaved correctly when reached that way and made this look chat-specific. It is not — any chat opened straight from another one hits it, DM or group. The notification-tap route (AppRouter resolving TipChat to [Tips, Chat]) is the common way in.

Change

setActiveChatId(null) in ChatViewModel.onCleared becomes clearActiveChat(chatId), a compare-and-clear on the coordinator that releases the chat only if it is still the active one. Correct in either dispose order, so it does not depend on the timing that varies by route.

RealChatCoordinator also drops the backgrounded stash on a match: onStop saves the active chat for onStart to restore, and a screen destroyed while the app is away would otherwise come back as the active chat with nothing on screen, silencing it permanently.

Tests

ActiveChatHandoffTest covers the handoff, ordinary teardown, an unresolved chat id, and the backgrounded case. The handoff test discriminates: reverting the conditional to an unconditional clear fails it and leaves the other three green.

Opening a chat directly from another chat left notifications firing for the
chat on screen. ChatViewModel.onCleared cleared the active chat id
unconditionally, and Navigation 3 keeps both entries alive across that kind of
switch: the outgoing entry is disposed after the incoming one has already
claimed the chat, so the outgoing screen's teardown cleared the chat the user
was by then looking at.

An on-device trace caught the window — `Navigating to Chat[VDbei…]` at
13:58:55.368, the outgoing `[W4rX…]` screen's dispose at 13:58:55.892. Going
back to the chat list first puts the dispose ahead of the open, which is why
the same chat notified correctly when reached that way and made this look
chat-specific. It is not: any chat opened straight from another one hits it.

Replace the unconditional clear with clearActiveChat(chatId), a compare-and-
clear that releases the chat only if it is still the active one. Correct in
either dispose order. RealChatCoordinator also drops the backgrounded stash on
a match, so a screen destroyed while the app is away is not restored as the
active chat with nothing on screen.
@bmc08gt bmc08gt self-assigned this Sep 21, 2026
@github-actions github-actions Bot added the type: fix Bug fix label Sep 21, 2026
@bmc08gt
bmc08gt merged commit 5033183 into code/cash Sep 21, 2026
3 checks passed
@bmc08gt
bmc08gt deleted the fix/active-chat-handoff branch September 23, 2026 16:45
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