Skip to content

Conversation

@Stream-SDK-Bot
Copy link
Collaborator

StreamChat

✅ Added

  • Add support for deleting messages only for the current user #3836
    • Add ChatMessageController.deleteMessageForMe()
    • Add ChatMessage.deletedForMe
  • Allow observing poll changes in PollVoteListController #3849

🐞 Fixed

  • Fix logout not clearing token when current user had no device registered #3838
  • Fix PollVoteListController not updating votes on the vote cast event #3849
  • Fix showing channel when receiving a campaign message with show_channels false #3851

StreamChatUI

🐞 Fixed

  • Fix PollResultsVoteListVC not updating the vote count #3849

Stream Bot and others added 13 commits October 7, 2025 15:03
* Remove trailing_whitespace from SwiftLint rules due to multi-line string issues

* Lint everything

* Fix linting issues

* Fix podspecs linting

* Fix issue

* Rename deprecated rule name

* Remove isEmpty because it does not work with XCUIElementQuery

---------

Co-authored-by: Alexey Alter-Pesotskiy <alex@testableapple.com>
* Add `deletedForMe` property to `ChatMessage`

* Handle `deletedForMe` in `MessageDeletedEvent`

* Add `ChatMessageController.deleteMessageForMe()`

* Fix `ChatMessage.isDeleted` not accounting for `deletedForMe`

* Add demo app example to test the feature

* Update CHANGELOG.md

* Fix forgotten deletedForMe in ChatMessage Equality

* Only update deletedForMe in MessageDTO if payload exists
#3838)

* Fix logout not clearing current user token if does not have a device registered

* Update CHANGELOG.md
Bumps [rack](https://github.com/rack/rack) from 3.2.2 to 3.2.3.
- [Release notes](https://github.com/rack/rack/releases)
- [Changelog](https://github.com/rack/rack/blob/main/CHANGELOG.md)
- [Commits](rack/rack@v3.2.2...v3.2.3)

---
updated-dependencies:
- dependency-name: rack
  dependency-version: 3.2.3
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
* Fix poll vote not being updated in the vote list controller

* Observe poll data changes in the `PollVoteListController`

* Fix `PollResultsVoteListVC` not updating votes count

* Update CHANGELOG.md

* Apply suggestion from @nuno-vieira

* Fix flaky test
@Stream-SDK-Bot Stream-SDK-Bot requested a review from a team as a code owner October 22, 2025 12:48
@coderabbitai
Copy link

coderabbitai bot commented Oct 22, 2025

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch release/4.91.0

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.

@github-actions
Copy link

1 Warning
⚠️ Big PR

Generated by 🚫 Danger

@github-actions
Copy link

Public Interface

+ public extension PollVoteListControllerDelegate



 extension PollVoteListController.ObservableObject: PollVoteListControllerDelegate  
-   public func controller(_ controller: DataController,didChangeState state: DataController.State)
+   public func controller(_ controller: PollVoteListController,didUpdatePoll poll: Poll)
+   public func controller(_ controller: DataController,didChangeState state: DataController.State)

 public class ChatMessageController: DataController, DelegateCallable, DataStoreProvider  
-   public func createNewReply(messageId: MessageId? = nil,text: String,pinning: MessagePinning? = nil,attachments: [AnyAttachmentPayload] = [],mentionedUserIds: [UserId] = [],showReplyInChannel: Bool = false,isSilent: Bool = false,quotedMessageId: MessageId? = nil,skipPush: Bool = false,skipEnrichUrl: Bool = false,extraData: [String: RawJSON] = [:],completion: ((Result<MessageId, Error>) -> Void)? = nil)
+   public func deleteMessageForMe(completion: ((Error?) -> Void)? = nil)
-   public func loadPreviousReplies(before replyId: MessageId? = nil,limit: Int? = nil,completion: ((Error?) -> Void)? = nil)
+   public func createNewReply(messageId: MessageId? = nil,text: String,pinning: MessagePinning? = nil,attachments: [AnyAttachmentPayload] = [],mentionedUserIds: [UserId] = [],showReplyInChannel: Bool = false,isSilent: Bool = false,quotedMessageId: MessageId? = nil,skipPush: Bool = false,skipEnrichUrl: Bool = false,extraData: [String: RawJSON] = [:],completion: ((Result<MessageId, Error>) -> Void)? = nil)
-   public func loadPageAroundReplyId(_ replyId: MessageId,limit: Int? = nil,completion: ((Error?) -> Void)? = nil)
+   public func loadPreviousReplies(before replyId: MessageId? = nil,limit: Int? = nil,completion: ((Error?) -> Void)? = nil)
-   public func loadNextReplies(after replyId: MessageId? = nil,limit: Int? = nil,completion: ((Error?) -> Void)? = nil)
+   public func loadPageAroundReplyId(_ replyId: MessageId,limit: Int? = nil,completion: ((Error?) -> Void)? = nil)
-   public func loadFirstPage(limit: Int? = nil,_ completion: ((_ error: Error?) -> Void)? = nil)
+   public func loadNextReplies(after replyId: MessageId? = nil,limit: Int? = nil,completion: ((Error?) -> Void)? = nil)
-   public func loadNextReactions(limit: Int = 25,completion: ((Error?) -> Void)? = nil)
+   public func loadFirstPage(limit: Int? = nil,_ completion: ((_ error: Error?) -> Void)? = nil)
-   public func loadReactions(limit: Int,offset: Int = 0,completion: @escaping (Result<[ChatMessageReaction], Error>) -> Void)
+   public func loadNextReactions(limit: Int = 25,completion: ((Error?) -> Void)? = nil)
-   public func flag(reason: String? = nil,extraData: [String: RawJSON]? = nil,completion: ((Error?) -> Void)? = nil)
+   public func loadReactions(limit: Int,offset: Int = 0,completion: @escaping (Result<[ChatMessageReaction], Error>) -> Void)
-   public func unflag(completion: ((Error?) -> Void)? = nil)
+   public func flag(reason: String? = nil,extraData: [String: RawJSON]? = nil,completion: ((Error?) -> Void)? = nil)
-   public func addReaction(_ type: MessageReactionType,score: Int = 1,enforceUnique: Bool = false,skipPush: Bool = false,pushEmojiCode: String? = nil,extraData: [String: RawJSON] = [:],completion: ((Error?) -> Void)? = nil)
+   public func unflag(completion: ((Error?) -> Void)? = nil)
-   public func deleteReaction(_ type: MessageReactionType,completion: ((Error?) -> Void)? = nil)
+   public func addReaction(_ type: MessageReactionType,score: Int = 1,enforceUnique: Bool = false,skipPush: Bool = false,pushEmojiCode: String? = nil,extraData: [String: RawJSON] = [:],completion: ((Error?) -> Void)? = nil)
-   public func pin(_ pinning: MessagePinning,completion: ((Error?) -> Void)? = nil)
+   public func deleteReaction(_ type: MessageReactionType,completion: ((Error?) -> Void)? = nil)
-   public func unpin(completion: ((Error?) -> Void)? = nil)
+   public func pin(_ pinning: MessagePinning,completion: ((Error?) -> Void)? = nil)
-   public func downloadAttachment(_ attachment: ChatMessageAttachment<Payload>,completion: @escaping (Result<ChatMessageAttachment<Payload>, Error>) -> Void)
+   public func unpin(completion: ((Error?) -> Void)? = nil)
-   public func deleteLocalAttachmentDownload(for attachmentId: AttachmentId,completion: ((Error?) -> Void)? = nil)
+   public func downloadAttachment(_ attachment: ChatMessageAttachment<Payload>,completion: @escaping (Result<ChatMessageAttachment<Payload>, Error>) -> Void)
-   public func restartFailedAttachmentUploading(with id: AttachmentId,completion: ((Error?) -> Void)? = nil)
+   public func deleteLocalAttachmentDownload(for attachmentId: AttachmentId,completion: ((Error?) -> Void)? = nil)
-   public func resendMessage(completion: ((Error?) -> Void)? = nil)
+   public func restartFailedAttachmentUploading(with id: AttachmentId,completion: ((Error?) -> Void)? = nil)
-   public func dispatchEphemeralMessageAction(_ action: AttachmentAction,completion: ((Error?) -> Void)? = nil)
+   public func resendMessage(completion: ((Error?) -> Void)? = nil)
-   public func translate(to language: TranslationLanguage,completion: ((Error?) -> Void)? = nil)
+   public func dispatchEphemeralMessageAction(_ action: AttachmentAction,completion: ((Error?) -> Void)? = nil)
-   public func markThreadRead(completion: ((Error?) -> Void)? = nil)
+   public func translate(to language: TranslationLanguage,completion: ((Error?) -> Void)? = nil)
-   public func markThreadUnread(completion: ((Error?) -> Void)? = nil)
+   public func markThreadRead(completion: ((Error?) -> Void)? = nil)
-   public func loadThread(replyLimit: Int? = nil,participantLimit: Int? = nil,completion: @escaping ((Result<ChatThread, Error>) -> Void))
+   public func markThreadUnread(completion: ((Error?) -> Void)? = nil)
-   public func updateThread(title: String?,extraData: [String: RawJSON]? = nil,unsetProperties: [String]? = nil,completion: @escaping ((Result<ChatThread, Error>) -> Void))
+   public func loadThread(replyLimit: Int? = nil,participantLimit: Int? = nil,completion: @escaping ((Result<ChatThread, Error>) -> Void))
-   public func stopLiveLocationSharing(completion: ((Result<SharedLocation, Error>) -> Void)? = nil)
+   public func updateThread(title: String?,extraData: [String: RawJSON]? = nil,unsetProperties: [String]? = nil,completion: @escaping ((Result<ChatThread, Error>) -> Void))
-   public func updateDraftReply(text: String,isSilent: Bool = false,attachments: [AnyAttachmentPayload] = [],mentionedUserIds: [UserId] = [],quotedMessageId: MessageId? = nil,showReplyInChannel: Bool = false,command: Command? = nil,extraData: [String: RawJSON] = [:],completion: ((Result<DraftMessage, Error>) -> Void)? = nil)
+   public func stopLiveLocationSharing(completion: ((Result<SharedLocation, Error>) -> Void)? = nil)
-   public func loadDraftReply(completion: ((Result<DraftMessage?, Error>) -> Void)? = nil)
+   public func updateDraftReply(text: String,isSilent: Bool = false,attachments: [AnyAttachmentPayload] = [],mentionedUserIds: [UserId] = [],quotedMessageId: MessageId? = nil,showReplyInChannel: Bool = false,command: Command? = nil,extraData: [String: RawJSON] = [:],completion: ((Result<DraftMessage, Error>) -> Void)? = nil)
-   public func deleteDraftReply(completion: ((Error?) -> Void)? = nil)
+   public func loadDraftReply(completion: ((Result<DraftMessage?, Error>) -> Void)? = nil)
-   public func createReminder(remindAt: Date? = nil,completion: ((Result<MessageReminder, Error>) -> Void)? = nil)
+   public func deleteDraftReply(completion: ((Error?) -> Void)? = nil)
-   public func updateReminder(remindAt: Date?,completion: ((Result<MessageReminder, Error>) -> Void)? = nil)
+   public func createReminder(remindAt: Date? = nil,completion: ((Result<MessageReminder, Error>) -> Void)? = nil)
-   public func deleteReminder(completion: ((Error?) -> Void)? = nil)
+   public func updateReminder(remindAt: Date?,completion: ((Result<MessageReminder, Error>) -> Void)? = nil)
+   public func deleteReminder(completion: ((Error?) -> Void)? = nil)

 public class PollVoteListController: DataController, DelegateCallable, DataStoreProvider  
-   public private var hasLoadedAllVotes: Bool
+   public var poll: Poll?
-   public weak var delegate: PollVoteListControllerDelegate?
+   public private var hasLoadedAllVotes: Bool
-   
+   public weak var delegate: PollVoteListControllerDelegate?
- 
+   
-   override public func synchronize(_ completion: ((_ error: Error?) -> Void)? = nil)
+ 
-   public func loadMoreVotes(limit: Int? = nil,completion: ((Error?) -> Void)? = nil)
+   override public func synchronize(_ completion: ((_ error: Error?) -> Void)? = nil)
+   public func loadMoreVotes(limit: Int? = nil,completion: ((Error?) -> Void)? = nil)

 open class PollResultsVoteListVC: _ViewController, ThemeProvider, PollVoteListControllerDelegate, UITableViewDelegate, GroupedSectionListStyling  
-   public func controller(_ controller: PollVoteListController,didChangeVotes changes: [ListChange<PollVote>])
+   open func loadMoreVotes()
-   open func loadMoreVotes()
+   open func didFinishLoadingMoreVotes(with error: Error?)
-   open func didFinishLoadingMoreVotes(with error: Error?)
+   public func controller(_ controller: PollVoteListController,didChangeVotes changes: [ListChange<PollVote>])
+   public func controller(_ controller: PollVoteListController,didUpdatePoll poll: Poll)

 public struct ChatMessage  
-   public let reactionScores: [MessageReactionType: Int]
+   public let deletedForMe: Bool
-   public let reactionCounts: [MessageReactionType: Int]
+   public let reactionScores: [MessageReactionType: Int]
-   public let reactionGroups: [MessageReactionType: ChatMessageReactionGroup]
+   public let reactionCounts: [MessageReactionType: Int]
-   public let author: ChatUser
+   public let reactionGroups: [MessageReactionType: ChatMessageReactionGroup]
-   public let mentionedUsers: Set<ChatUser>
+   public let author: ChatUser
-   public let threadParticipants: [ChatUser]
+   public let mentionedUsers: Set<ChatUser>
-   public var threadParticipantsCount: Int
+   public let threadParticipants: [ChatUser]
-   public var attachmentCounts: [AttachmentType: Int]
+   public var threadParticipantsCount: Int
-   public let latestReplies: [ChatMessage]
+   public var attachmentCounts: [AttachmentType: Int]
-   public let localState: LocalMessageState?
+   public let latestReplies: [ChatMessage]
-   public let isFlaggedByCurrentUser: Bool
+   public let localState: LocalMessageState?
-   public let latestReactions: Set<ChatMessageReaction>
+   public let isFlaggedByCurrentUser: Bool
-   public let currentUserReactions: Set<ChatMessageReaction>
+   public let latestReactions: Set<ChatMessageReaction>
-   public var currentUserReactionsCount: Int
+   public let currentUserReactions: Set<ChatMessageReaction>
-   public let isSentByCurrentUser: Bool
+   public var currentUserReactionsCount: Int
-   public let pinDetails: MessagePinDetails?
+   public let isSentByCurrentUser: Bool
-   public let translations: [TranslationLanguage: String]?
+   public let pinDetails: MessagePinDetails?
-   public let originalLanguage: TranslationLanguage?
+   public let translations: [TranslationLanguage: String]?
-   public let moderationDetails: MessageModerationDetails?
+   public let originalLanguage: TranslationLanguage?
-   public let readBy: Set<ChatUser>
+   public let moderationDetails: MessageModerationDetails?
-   public var readByCount: Int
+   public let readBy: Set<ChatUser>
-   public let poll: Poll?
+   public var readByCount: Int
-   public let sharedLocation: SharedLocation?
+   public let poll: Poll?
-   public let channelRole: MemberRole?
+   public let sharedLocation: SharedLocation?
-   
+   public let channelRole: MemberRole?
- 
+   
-   public func translatedText(for language: TranslationLanguage)-> String?
+ 
-   public func changing(text: String? = nil,type: MessageType? = nil,state: LocalMessageState? = nil,command: String? = nil,arguments: String? = nil,attachments: [AnyChatMessageAttachment]? = nil,translations: [TranslationLanguage: String]? = nil,originalLanguage: TranslationLanguage? = nil,moderationDetails: MessageModerationDetails? = nil,readBy: Set<ChatUser>? = nil,deletedAt: Date? = nil,extraData: [String: RawJSON]? = nil)-> ChatMessage
+   public func translatedText(for language: TranslationLanguage)-> String?
-   public func replacing(text: String?,extraData: [String: RawJSON]?,attachments: [AnyChatMessageAttachment]?)-> ChatMessage
+   public func changing(text: String? = nil,type: MessageType? = nil,state: LocalMessageState? = nil,command: String? = nil,arguments: String? = nil,attachments: [AnyChatMessageAttachment]? = nil,translations: [TranslationLanguage: String]? = nil,originalLanguage: TranslationLanguage? = nil,moderationDetails: MessageModerationDetails? = nil,readBy: Set<ChatUser>? = nil,deletedAt: Date? = nil,extraData: [String: RawJSON]? = nil)-> ChatMessage
-   public func replacing(text: String?,type: MessageType,state: LocalMessageState?,command: String?,arguments: String?,attachments: [AnyChatMessageAttachment]?,translations: [TranslationLanguage: String]?,originalLanguage: TranslationLanguage?,moderationDetails: MessageModerationDetails?,extraData: [String: RawJSON]?)-> ChatMessage
+   public func replacing(text: String?,extraData: [String: RawJSON]?,attachments: [AnyChatMessageAttachment]?)-> ChatMessage
+   public func replacing(text: String?,type: MessageType,state: LocalMessageState?,command: String?,arguments: String?,attachments: [AnyChatMessageAttachment]?,translations: [TranslationLanguage: String]?,originalLanguage: TranslationLanguage?,moderationDetails: MessageModerationDetails?,extraData: [String: RawJSON]?)-> ChatMessage

 public struct MessageDeletedEvent: ChannelSpecificEvent  
+   public let deletedForMe: Bool

@Stream-SDK-Bot
Copy link
Collaborator Author

SDK Size

title previous release current release diff status
StreamChat 8.25 MB 8.26 MB +17 KB 🟢
StreamChatUI 4.89 MB 4.89 MB 0 KB 🟢

@Stream-SDK-Bot
Copy link
Collaborator Author

StreamChat XCSize

Object Diff (bytes)
PollVoteListController.o +2711
PollVoteListController+SwiftUI.o +2026
PollVoteListController+Combine.o +1081
PollController+Combine.o -598
PollController+SwiftUI.o -368
MessagePayloads.o +256
ReminderPayloads.o +51

@Stream-SDK-Bot
Copy link
Collaborator Author

StreamChatUI XCSize

Object Diff (bytes)
PollResultsVoteListVC.o +540

@Stream-SDK-Bot
Copy link
Collaborator Author

SDK Performance

target metric benchmark branch performance status
MessageList Hitches total duration 10 ms 0.0 ms 100.0% 🔼 🟢
Duration 2.6 s 2.55 s 1.92% 🔼 🟢
Hitch time ratio 4 ms per s 0.0 ms per s 100.0% 🔼 🟢
Frame rate 75 fps 78.1 fps 4.13% 🔼 🟢
Number of hitches 1 0.0 100.0% 🔼 🟢

@sonarqubecloud
Copy link

sonarqubecloud bot commented Oct 22, 2025

@testableapple
Copy link
Contributor

/merge release

@testableapple
Copy link
Contributor

Publication of the release has been launched 👍

@github-actions github-actions bot merged commit 61ee0eb into main Oct 22, 2025
15 of 17 checks passed
@github-actions github-actions bot deleted the release/4.91.0 branch October 22, 2025 14:58
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