Sitelet https://github.com/GetStream/stream-chat-android/pull/6702
Skip to content

Keep hidden channels out of the channel list when member or channel updates arrive - #6702

Merged
gpunto merged 2 commits into
developfrom
port/develop/hidden-channel-not-removed
Sep 17, 2026
Merged

gpunto merged 2 commits into
developfrom
port/develop/hidden-channel-not-removed

Conversation

@gpunto

@gpunto gpunto commented Sep 15, 2026 •

Copy link
Copy Markdown
Contributor

Goal

A channel hidden via channel.hidden is put back into the channel list by a channel.updated or
member.updated for the same channel, and stays there until the app restarts. Neither add path checks whether the
channel is hidden.

Port of #6697 to develop.

Part of AND-1530

Implementation

  • Skip the add in DefaultChatEventHandler.addIfMembershipUpdated when the cached channel is hidden. This is the
    member.updated path, and the only one that applies to plain channel lists, since the base handler already skips
    channel.updated.
  • Skip it in GroupAwareChatEventHandler.routeByGroup when the cached channel is hidden, and remove the channel if
    it is still listed. This is the channel.updated path; the default group resolver always resolves a channel into
    the all sentinel group, so an all grouped query took the add unconditionally.
  • ChannelStateLegacyImpl.toChannel() resolves the current user from the userFlow it already holds instead of the
    ChatClient singleton. Same value, and it lets the state layer be exercised without a built client.
    ChannelStateImpl needs no equivalent change, it does not sync unread counts there.

hidden is per-user and absent from channel.updated payloads, so both guards read the cached channel. Per-channel
event handling runs before query handling in the same batch, so for a channel whose state is active in memory the flag
is current. parseChatEventResults falls back to the database for channels that are not active, and the database is
only written after query handling, so on that fallback the guard sees the pre-batch value and does not fire.

The new-message add paths stay unguarded: a non-shadowed message clears hidden in ChannelEventHandler, which is
what makes a hidden channel resurface legitimately. iOS does the same in ChannelVisibilityEventMiddleware, since the
backend sends no channel.visible in that case.

Testing

  • EventHandlerSequentialHiddenChannelTest drives EventHandlerSequential over the real StateRegistry and
    LogicRegistry. It replays the reported batch (notification.mark_read, channel.hidden, channel.updated,
    member.updated) against a grouped query, and covers a plain query hidden in one batch and updated in the next.
    Both fail without the guards. A third case asserts the same batch without the hidden event still adds the channel,
    and a fourth asserts a new message brings a hidden channel back.
  • Unit coverage for each guard in DefaultChatEventHandlerTest and GroupAwareChatEventHandlerTest, including a
    hidden channel already in the list being removed.
  • The behaviour was verified on a device on the v6 branch, comparing builds that differ only by the fix: without it a
    hidden channel returns to the list on the following member.updated, with it the channel stays out and a new
    message still brings it back. This port carries no behavioural difference from that build.

Summary by CodeRabbit

  • Bug Fixes
    • Hidden channels are no longer added to channel queries through membership updates.
    • Hidden channels are removed or excluded from grouped channel lists until they become visible again.
    • New messages can correctly bring hidden channels back into standard queries.
    • Unread counts now remain accurate when no user is connected.

@gpunto gpunto added the pr:bug Bug fix label Sep 15, 2026
@github-actions

Copy link
Copy Markdown
Contributor

PR checklist ✅

All required conditions are satisfied:

  • Title length is OK (or ignored by label).
  • At least one pr: label exists.
  • Sections ### Goal, ### Implementation, and ### Testing are filled, or the PR is bot-authored.
  • An issue is linked (Linear ticket or GitHub issue), or the PR is bot-authored.

🎉 Great job! This PR is ready for review.

@github-actions

github-actions Bot commented Sep 15, 2026 •

Copy link
Copy Markdown
Contributor

SDK Size Comparison 📏

SDK Before After Difference Status
stream-chat-android-client 6.08 MB 6.08 MB 0.00 MB 🟢
stream-chat-android-ui-components 11.39 MB 11.39 MB 0.00 MB 🟢
stream-chat-android-compose 13.07 MB 13.07 MB 0.00 MB 🟢

@gpunto
gpunto marked this pull request as ready for review September 15, 2026 12:27
@gpunto
gpunto requested a review from a team as a code owner September 15, 2026 12:27
@coderabbitai

coderabbitai Bot commented Sep 15, 2026 •

Copy link
Copy Markdown

Review Change StackReview Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Advanced

Run ID: ceabcb23-a879-4046-ab63-02f0b821b2c1

📥 Commits

Reviewing files that changed from the base of the PR and between 929fd8c and b98e22a.

📒 Files selected for processing (7)
  • stream-chat-android-client/src/main/java/io/getstream/chat/android/client/api/event/DefaultChatEventHandler.kt
  • stream-chat-android-client/src/main/java/io/getstream/chat/android/client/internal/state/event/handler/grouped/internal/GroupAwareChatEventHandler.kt
  • stream-chat-android-client/src/main/java/io/getstream/chat/android/client/internal/state/plugin/state/channel/internal/ChannelStateLegacyImpl.kt
  • stream-chat-android-client/src/test/java/io/getstream/chat/android/client/internal/state/event/handler/grouped/internal/GroupAwareChatEventHandlerTest.kt
  • stream-chat-android-client/src/test/java/io/getstream/chat/android/client/internal/state/event/handler/internal/EventHandlerSequentialHiddenChannelTest.kt
  • stream-chat-android-client/src/test/java/io/getstream/chat/android/client/internal/state/plugin/state/channel/internal/ChannelStateLegacyImplTest.kt
  • stream-chat-android-client/src/test/java/io/getstream/chat/android/client/internal/state/querychannels/DefaultChatEventHandlerTest.kt

Included review availability: Your plan provides up to 4 included reviews per hour; 3 remain after this review.


Walkthrough

The PR prevents hidden channels from being re-added by membership and grouped event handlers. It adds sequential event regression tests. It also passes the current user ID to unread-count synchronization and verifies behavior without a connected user.

Changes

Hidden channel routing

Layer / File(s) Summary
Hidden channel routing guards
stream-chat-android-client/src/main/java/io/getstream/chat/android/client/api/event/DefaultChatEventHandler.kt, stream-chat-android-client/src/main/java/io/getstream/chat/android/client/internal/state/event/handler/grouped/internal/GroupAwareChatEventHandler.kt, stream-chat-android-client/src/test/java/io/getstream/chat/android/client/internal/state/event/handler/grouped/internal/GroupAwareChatEventHandlerTest.kt, stream-chat-android-client/src/test/java/io/getstream/chat/android/client/internal/state/querychannels/DefaultChatEventHandlerTest.kt
Membership and grouped handlers skip hidden channels. Tests cover visible, hidden, missing, and other-user membership cases.
Sequential hidden-channel regressions
stream-chat-android-client/src/test/java/io/getstream/chat/android/client/internal/state/event/handler/internal/EventHandlerSequentialHiddenChannelTest.kt
Tests verify that hidden-channel events prevent later updates from re-adding channels, while qualifying message or non-hidden event batches can re-add them.

Unread user context

Layer / File(s) Summary
Unread-count user context
stream-chat-android-client/src/main/java/io/getstream/chat/android/client/internal/state/plugin/state/channel/internal/ChannelStateLegacyImpl.kt, stream-chat-android-client/src/test/java/io/getstream/chat/android/client/internal/state/plugin/state/channel/internal/ChannelStateLegacyImplTest.kt
toChannel() passes the current user ID to unread-count synchronization. A test verifies an unread count of zero when no user is connected.

Priority: ⬇️ Low

Estimated code review effort: 3 (Moderate) | ~25 minutes

Change: Bug fix

Suggested reviewers: velikovpetar

Merge Risk: ⚪ Minimal · up to b98e2

The change keeps hidden channels out of query results after update events and avoids disconnected-user unread-count failures. No merge-blocking risk was identified.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 15.63% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 32 functions across 7 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly describes the main change: preventing hidden channels from returning to channel lists after member or channel updates.
Description check ✅ Passed The description includes complete Goal, Implementation, and Testing sections. It explains the affected code paths, preserved new-message behavior, and test coverage. UI and checklist items are not com…
  • Fix all pre-merge checks with AI
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch port/develop/hidden-channel-not-removed

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

A rabbit guards the hidden stream,
No secret channel joins the dream.
The unread counts know whose they are,
Even when no user is near or far.
Tests hop softly, proving each theme.

Comment @coderabbitai help to get the list of available commands.

@gpunto
gpunto marked this pull request as draft September 15, 2026 13:30
@gpunto
gpunto marked this pull request as ready for review September 15, 2026 14:44

@andremion andremion left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Looks good. One optional nit inline.

@gpunto
gpunto enabled auto-merge September 17, 2026 10:31
@sonarqubecloud

Copy link
Copy Markdown

@gpunto
gpunto added this pull request to the merge queue Sep 17, 2026
Merged via the queue into develop with commit eef655d Sep 17, 2026
19 checks passed
@gpunto
gpunto deleted the port/develop/hidden-channel-not-removed branch September 17, 2026 11:43
@stream-public-bot stream-public-bot added the released Included in a release label Sep 24, 2026
@stream-public-bot

Copy link
Copy Markdown
Contributor

🚀 Available in v7.12.0

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

Labels

pr:bug Bug fix released Included in a release

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants