Skip to content

Conversation

@laevandus
Copy link
Contributor

@laevandus laevandus commented Oct 22, 2025

🔗 Issue Links

Resolves: IOS-1194

🎯 Goal

Keep channel hidden state unchanged wen receiving campaign message

📝 Summary

  • If new message is from campaign, do not change hidden status because campaign API does that automatically through show_channels: true/false configuration

🛠 Implementation

Campaign API has a setting called show_channels. If it is true, channels are automatically shown, if false, hidden state is not changed. On the other hand SDKs support "Hiding a channel will remove it from query channel requests for that user until a new message is added." (docs). Only way for supporting both is opting out of showing channels on the SDK side when receiving a new message if the message is from campaign API.

🎨 Showcase

🧪 Manual Testing Notes

Download the script

  1. Log in with anakin (hide the existing campaign channel if it is visible from previous testing)
  2. Send a message with campaign API script when show_channels: false - channel does not appear in the channel list
  3. Send a message with campaign API script when show_channels: true - channel appears in the channel list

☑️ 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 incorrectly displayed when receiving campaign messages with visibility settings set to false. Channels now properly maintain their hidden state when handling campaign-related messages.

@laevandus laevandus requested a review from a team as a code owner October 22, 2025 11:31
@laevandus laevandus added the 🐞 Bug An issue or PR related to a bug label Oct 22, 2025
@coderabbitai
Copy link

coderabbitai bot commented Oct 22, 2025

Walkthrough

The PR adds a campaignId field to the MessagePayload structure and modifies channel visibility logic to prevent campaign messages from unhiding user-hidden channels. Campaign messages with the show_channels: false setting now respect the user's channel visibility preferences.

Changes

Cohort / File(s) Change Summary
Changelog
CHANGELOG.md
Adds entry documenting fix for campaign messages incorrectly unhiding hidden channels (issue #3851).
Campaign ID Support
Sources/StreamChat/APIClient/Endpoints/Payloads/MessagePayloads.swift
Introduces new optional campaignId: String? field to MessagePayload with corresponding coding key mapping to "created_by_campaign_id"; includes decoder and initializer updates.
Middleware Logic
Sources/StreamChat/WebSocketClient/EventMiddlewares/ChannelVisibilityEventMiddleware.swift
Adds condition to prevent channel unhiding for messages with campaignId (only unhides when message is not shadowed AND has no campaignId).
Test Utilities
TestTools/StreamChatTestTools/TestData/DummyData/MessagePayload.swift
Adds campaignId: String? = nil parameter to MessagePayload.dummy() helper function for test data generation.
Middleware Tests
Tests/StreamChatTests/WebSocketClient/EventMiddlewares/ChannelVisibilityEventMiddleware_Tests.swift
Adds two new tests verifying that MessageNewEvent and NotificationMessageNewEvent with campaignId do not unhide hidden channels.

Sequence Diagram

sequenceDiagram
    participant Client
    participant Middleware as ChannelVisibilityEventMiddleware
    participant ChannelDB as Channel Database

    rect rgb(200, 220, 255)
    Note over Client,ChannelDB: Regular Message Flow
    Client->>Middleware: MessageNewEvent (no campaignId)
    Middleware->>ChannelDB: Check isHidden & isShadowed
    alt Not shadowed
        Middleware->>ChannelDB: Set isHidden = false
    end
    end

    rect rgb(220, 255, 200)
    Note over Client,ChannelDB: Campaign Message Flow (NEW)
    Client->>Middleware: MessageNewEvent (campaignId present)
    Middleware->>ChannelDB: Check isHidden, isShadowed, & campaignId
    alt Has campaignId
        Middleware->>ChannelDB: Keep isHidden unchanged
    else No campaignId and not shadowed
        Middleware->>ChannelDB: Set isHidden = false
    end
    end
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Possibly related PRs

Suggested labels

🌐 SDK: StreamChat (LLC)

Suggested reviewers

  • martinmitrevski

Poem

🐰 A campaign whispers through the wire,
Yet hidden channels stay unseen!
With campaignId as our guide,
No unwanted reveals between,
The user's privacy runs true. 🤫✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 14.29% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (3 passed)
Check name Status Explanation
Title Check ✅ Passed The PR title "Keep hidden state unchanged when receiving campaign message" directly and clearly describes the primary objective of the changeset. The title is concise, specific, and accurately reflects the key behavioral change being implemented—preventing channels from being automatically unhidden when receiving campaign API messages. A developer scanning the repository history would immediately understand the purpose of this change without needing to examine the details.
Linked Issues Check ✅ Passed The code changes fully implement the objectives from IOS-1194. The PR adds a campaignId field to MessagePayload to identify campaign-originated messages, modifies ChannelVisibilityEventMiddleware to skip unhiding channels when campaignId is present (allowing Campaign API's show_channels setting to control visibility), includes corresponding test helper updates, and adds unit tests verifying that campaign messages do not reset the hidden state. All coding-related requirements from the linked issue have been addressed through these implementation changes.
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/keeping-channel-hidden-for-campaign-messages

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.

@laevandus laevandus force-pushed the fix/keeping-channel-hidden-for-campaign-messages branch from de4aede to 813bab4 Compare October 22, 2025 11:33
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)
Sources/StreamChat/WebSocketClient/EventMiddlewares/ChannelVisibilityEventMiddleware.swift (1)

37-39: Consider adding inline documentation for campaign message exclusion

The logic correctly prevents campaign messages from unhiding channels, which aligns with the Campaign API's show_channels configuration controlling visibility. However, the reasoning might not be immediately obvious to future maintainers.

Consider adding a brief comment explaining why campaign messages are excluded:

// Campaign messages don't unhide channels because visibility is controlled 
// by the Campaign API's show_channels configuration
if !event.message.isShadowed && event.message.campaignId == nil && !channelDTO.isBlocked {
    channelDTO.isHidden = false
}

Also applies to: 48-50

📜 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 9178258 and 813bab4.

📒 Files selected for processing (5)
  • CHANGELOG.md (1 hunks)
  • Sources/StreamChat/APIClient/Endpoints/Payloads/MessagePayloads.swift (5 hunks)
  • Sources/StreamChat/WebSocketClient/EventMiddlewares/ChannelVisibilityEventMiddleware.swift (2 hunks)
  • TestTools/StreamChatTestTools/TestData/DummyData/MessagePayload.swift (2 hunks)
  • Tests/StreamChatTests/WebSocketClient/EventMiddlewares/ChannelVisibilityEventMiddleware_Tests.swift (2 hunks)
🧰 Additional context used
📓 Path-based instructions (5)
**/*.swift

📄 CodeRabbit inference engine (AGENTS.md)

**/*.swift: Respect .swiftlint.yml rules; do not suppress SwiftLint rules broadly—scope and justify any exceptions
Adhere to the project’s zero warnings policy—fix new warnings and avoid introducing any

Files:

  • Sources/StreamChat/WebSocketClient/EventMiddlewares/ChannelVisibilityEventMiddleware.swift
  • Tests/StreamChatTests/WebSocketClient/EventMiddlewares/ChannelVisibilityEventMiddleware_Tests.swift
  • TestTools/StreamChatTestTools/TestData/DummyData/MessagePayload.swift
  • Sources/StreamChat/APIClient/Endpoints/Payloads/MessagePayloads.swift
Sources/{StreamChat,StreamChatUI}/**/*.swift

📄 CodeRabbit inference engine (AGENTS.md)

When altering public API, update inline documentation comments in source

Files:

  • Sources/StreamChat/WebSocketClient/EventMiddlewares/ChannelVisibilityEventMiddleware.swift
  • Sources/StreamChat/APIClient/Endpoints/Payloads/MessagePayloads.swift
CHANGELOG.md

📄 CodeRabbit inference engine (AGENTS.md)

Update CHANGELOG for user-visible SDK changes

Files:

  • CHANGELOG.md
Tests/{StreamChatTests,StreamChatUITests}/**/*.swift

📄 CodeRabbit inference engine (AGENTS.md)

Tests/{StreamChatTests,StreamChatUITests}/**/*.swift: Add or extend tests in the matching module’s Tests folder
Prefer using provided test fakes/mocks in tests when possible

Files:

  • Tests/StreamChatTests/WebSocketClient/EventMiddlewares/ChannelVisibilityEventMiddleware_Tests.swift
Tests/StreamChatTests/**/*.swift

📄 CodeRabbit inference engine (AGENTS.md)

Ensure tests cover core models and API surface of StreamChat

Files:

  • Tests/StreamChatTests/WebSocketClient/EventMiddlewares/ChannelVisibilityEventMiddleware_Tests.swift
🧬 Code graph analysis (1)
Tests/StreamChatTests/WebSocketClient/EventMiddlewares/ChannelVisibilityEventMiddleware_Tests.swift (5)
TestTools/StreamChatTestTools/TestData/DummyData/MessagePayload.swift (2)
  • dummy (11-106)
  • dummy (124-142)
Sources/StreamChat/Database/DatabaseSession.swift (1)
  • saveChannel (713-716)
Sources/StreamChat/Database/DTOs/ChannelDTO.swift (3)
  • saveChannel (237-322)
  • saveChannel (324-425)
  • channel (427-429)
TestTools/StreamChatTestTools/TestData/DummyData/XCTestCase+Dummy.swift (1)
  • dummyPayload (122-219)
Sources/StreamChat/WebSocketClient/EventMiddlewares/ChannelVisibilityEventMiddleware.swift (1)
  • handle (9-60)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Metrics
🔇 Additional comments (4)
TestTools/StreamChatTestTools/TestData/DummyData/MessagePayload.swift (1)

57-58: LGTM - Test helper properly extended for campaignId

The test helper correctly adds support for the new campaignId field with an appropriate default value and properly propagates it to the MessagePayload initializer.

Also applies to: 103-104

CHANGELOG.md (1)

15-15: LGTM - Changelog entry properly documents the fix

The changelog entry clearly describes the fix and is properly categorized under the "Fixed" section.

Tests/StreamChatTests/WebSocketClient/EventMiddlewares/ChannelVisibilityEventMiddleware_Tests.swift (1)

240-267: LGTM - Comprehensive test coverage for campaign messages

The tests properly verify that campaign messages do not reset the isHidden flag for both MessageNewEvent and NotificationMessageNewEvent. The test structure is clear and follows the existing patterns in the test suite.

Also applies to: 329-357

Sources/StreamChat/APIClient/Endpoints/Payloads/MessagePayloads.swift (1)

61-61: LGTM - campaignId field properly integrated into MessagePayload

The campaignId field is correctly added to the payload structure:

  • Properly mapped to the backend field created_by_campaign_id
  • Uses appropriate optional type
  • Handled in all necessary locations (coding keys, property declaration, decoding, and initialization)

Also applies to: 125-126, 198-198, 244-245, 290-290

@github-actions
Copy link

Public Interface

🚀 No changes affecting the public interface.

@Stream-SDK-Bot
Copy link
Collaborator

SDK Size

title develop branch diff status
StreamChat 8.26 MB 8.26 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.54 s 2.31% 🔼 🟢
Hitch time ratio 4 ms per s 1.32 ms per s 67.0% 🔼 🟢
Frame rate 75 fps 77.93 fps 3.91% 🔼 🟢
Number of hitches 1 0.4 60.0% 🔼 🟢

@Stream-SDK-Bot
Copy link
Collaborator

StreamChat XCSize

Object Diff (bytes)
MessagePayloads.o +259
ReminderPayloads.o +47

@sonarqubecloud
Copy link

@nuno-vieira nuno-vieira merged commit fd5bbd8 into develop Oct 22, 2025
14 checks passed
@nuno-vieira nuno-vieira deleted the fix/keeping-channel-hidden-for-campaign-messages branch October 22, 2025 12:22
@Stream-SDK-Bot Stream-SDK-Bot mentioned this pull request Oct 22, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

🐞 Bug An issue or PR related to a bug

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants