Skip to content

Conversation

@nuno-vieira
Copy link
Member

@nuno-vieira nuno-vieira commented Nov 18, 2025

🔗 Issue Links

https://linear.app/stream/issue/IOS-1217

🎯 Goal

Fix marking channel read when scrolling to bottom without unread count.

We were not checking whether there were unreads or not before marking the channel read. The SwiftUI SDK is already doing this, so there is no issue there.

🧪 Manual Testing Notes

(Requires using Proxyman to verify the requests)

  • Open a channel without unreads
  • Keep scrolling up and to the bottom
  • Should not mark a channel read

☑️ Contributor Checklist

  • I have signed the Stream CLA (required)
  • This change should be manually QAed
  • Changelog is updated with client-facing changes
  • Changelog is updated with new localization keys
  • New code is covered by unit tests
  • Documentation has been updated in the docs-content repo

Summary by CodeRabbit

  • Bug Fixes
    • Fixed an issue where channels were marked as read when scrolling to the bottom, even when there were no unread messages.

@nuno-vieira nuno-vieira requested a review from a team as a code owner November 18, 2025 17:13
@coderabbitai
Copy link

coderabbitai bot commented Nov 18, 2025

Walkthrough

This pull request fixes a bug where channels were being marked as read on every scroll to the bottom, regardless of unread message count. The solution adds a guard condition requiring at least one unread message before allowing channels to be marked as read, along with comprehensive test coverage.

Changes

Cohort / File(s) Summary
Bug Fix: Channel Read Logic
Sources/StreamChatUI/ChatChannel/ChatChannelVC.swift
Added guard condition requiring unreadMessageCount > 0 in shouldMarkChannelRead to prevent marking channels as read when no unread messages exist. Preserves all existing conditions.
Test Coverage for Channel Read Logic
Tests/StreamChatUITests/SnapshotTests/ChatChannel/ChatChannelVC_Tests.swift
Added two new test cases verifying shouldMarkChannelRead returns true when unread messages exist and false when none exist, with jump-to-unread enabled and all preconditions met.
Documentation
CHANGELOG.md
Added StreamChatUI subsection documenting the bug fix for marking channels read when scrolling without unread counts.

Sequence Diagram

sequenceDiagram
    participant User as User
    participant VC as ChatChannelVC
    participant Channel as Channel Model
    
    User->>VC: Scrolls to bottom
    VC->>VC: shouldMarkChannelRead() called
    
    rect rgb(200, 220, 240)
    Note over VC: Check existing conditions<br/>(isLastMessageVisible,<br/>hasSeenFirstUnreadMessage, etc.)
    end
    
    rect rgb(240, 200, 200)
    Note over VC: NEW: Verify unreadCount > 0
    VC->>Channel: Get unreadCount.messages
    Channel-->>VC: unreadCount
    alt Has unread messages
        rect rgb(200, 240, 200)
        VC->>VC: Mark channel as read ✓
        end
    else No unread messages
        rect rgb(240, 200, 200)
        VC->>VC: Skip marking as read ✗
        end
    end
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • ChatChannelVC.swift: Core logic change in frequently-called read-state path; verify the guard condition placement doesn't introduce regressions
  • ChatChannelVC_Tests.swift: Two comprehensive test cases with multiple setup steps; ensure test assertions align with the intended behavior and cover edge cases
  • CHANGELOG.md: Verify the documentation accurately reflects the fix and PR reference

Suggested labels

🐞 Bug, 🎨 SDK: StreamChatUI

Suggested reviewers

  • martinmitrevski

Poem

🐰 A scroll to the bottom, once read-marked with glee,
Now checks if there's mail before setting it free.
No unread? Don't shout! Keep it quiet, be wise—
Read events aplenty? That's gone! Surprise, surprise!

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title directly describes the main change: preventing marking a channel read when there are no unread counts during scroll-to-bottom, which matches the primary code modification.
Linked Issues check ✅ Passed The code changes implement the requirement from IOS-1217 by adding a guard condition that prevents marking channel read when unread message count is zero, directly addressing the regression of read events being triggered on every scroll.
Out of Scope Changes check ✅ Passed All changes are scoped to the linked issue: the logic fix in ChatChannelVC.swift, corresponding test cases, and CHANGELOG update are all directly related to preventing read events when no unread count exists.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/marking-channel-read-when-no-unread-count

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

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

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
Tests/StreamChatUITests/SnapshotTests/ChatChannel/ChatChannelVC_Tests.swift (1)

907-939: New shouldMarkChannelRead tests cover the unread-count guard but could be made more explicit

The two new tests correctly validate that:

  • With jump-to-unread enabled and unreadCount.messages == 1, shouldMarkChannelRead returns true under the expected preconditions.
  • With the same preconditions but unreadCount.messages == 0, shouldMarkChannelRead returns false.

This gives good coverage of the new guard. However, the tests currently depend on subtle internal behavior (hasSeenFirstUnreadMessage being flipped via willDisplayMessageAt when both message?.id and firstUnreadMessageId are nil, with vc.messages still empty).

To make these tests more robust against future refactors, consider:

  • Initializing vc.messages with at least one concrete ChatMessage.
  • Setting channelControllerMock.mockFirstUnreadMessageId to that message’s id and invoking vc.channelController(channelControllerMock, didUpdateMessages: []) so firstUnreadMessageId is populated through the normal code path.
  • Then calling willDisplayMessageAt/scrollViewDidScroll so hasSeenFirstUnreadMessage and hasSeenLastMessage are set in a way that mirrors production behavior.

Functionally the tests are correct as-is; this would just reduce their reliance on optional-equality quirks and improve maintainability.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between e275c6b and 4c6744d.

📒 Files selected for processing (3)
  • CHANGELOG.md (1 hunks)
  • Sources/StreamChatUI/ChatChannel/ChatChannelVC.swift (1 hunks)
  • Tests/StreamChatUITests/SnapshotTests/ChatChannel/ChatChannelVC_Tests.swift (2 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
Tests/StreamChatUITests/SnapshotTests/ChatChannel/ChatChannelVC_Tests.swift (3)
Tests/StreamChatUITests/Helpers/UIView+Helpers.swift (1)
  • mockIsViewVisible (23-27)
TestTools/StreamChatTestTools/Mocks/Models + Extensions/ChatChannel_Mock.swift (3)
  • mock (10-52)
  • mock (57-73)
  • mock (78-151)
Sources/StreamChatUI/ChatChannel/ChatChannelVC.swift (9)
  • chatMessageListVC (362-364)
  • chatMessageListVC (366-378)
  • chatMessageListVC (380-396)
  • chatMessageListVC (406-416)
  • chatMessageListVC (418-448)
  • chatMessageListVC (458-470)
  • chatMessageListVC (472-478)
  • chatMessageListVC (480-501)
  • chatMessageListVC (503-509)
🔇 Additional comments (2)
CHANGELOG.md (1)

6-8: Changelog entry accurately documents the bug fix

The new StreamChatUI “Fixed” bullet is consistent with existing style and clearly describes the behavioral change tied to this PR.

Sources/StreamChatUI/ChatChannel/ChatChannelVC.swift (1)

92-97: Unread-count guard in shouldMarkChannelRead looks correct

Adding unreadMessageCount > 0 to the jump-to-unread path is a minimal, targeted way to avoid issuing read events when the channel has no unread messages, while preserving existing behavior and throttling in other cases.

One thing to double-check: for isJumpToUnreadEnabled == false we still mark the channel read whenever the last message is fully visible and the first page is loaded, even if the unread count is zero. If the intent is to suppress no-op read events across all configurations (not just when jump-to-unread is enabled), you might want to reuse the same unread-count guard in the non-jump-to-unread branch as well; otherwise, this looks like an intentional scope limitation of the fix.

@Stream-SDK-Bot
Copy link
Collaborator

SDK Size

title develop branch diff status
StreamChat 7.25 MB 7.25 MB 0 KB 🟢
StreamChatUI 4.89 MB 4.89 MB 0 KB 🟢

@Stream-SDK-Bot
Copy link
Collaborator

SDK Performance

target metric benchmark branch performance status
MessageList Hitches total duration 10 ms 3.34 ms 66.6% 🔼 🟢
Duration 2.6 s 2.55 s 1.92% 🔼 🟢
Hitch time ratio 4 ms per s 1.32 ms per s 67.0% 🔼 🟢
Frame rate 75 fps 78.02 fps 4.03% 🔼 🟢
Number of hitches 1 0.4 60.0% 🔼 🟢

@Stream-SDK-Bot
Copy link
Collaborator

StreamChatUI XCSize

Object Diff (bytes)
ChatChannelVC.o +224

@github-actions
Copy link

Public Interface

🚀 No changes affecting the public interface.

@sonarqubecloud
Copy link

@nuno-vieira nuno-vieira merged commit 571a488 into develop Nov 18, 2025
32 of 34 checks passed
@nuno-vieira nuno-vieira deleted the fix/marking-channel-read-when-no-unread-count branch November 18, 2025 23:28
@Stream-SDK-Bot Stream-SDK-Bot mentioned this pull request Dec 2, 2025
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.

4 participants