Skip to content

Conversation

@Stream-SDK-Bot
Copy link
Collaborator

StreamChat

✅ Added

  • Add support for push preferences #3820
    • Add CurrentChatUserController.setPushPreference(level:)
    • Add CurrentChatUserController.snoozePushNotifications(until:)
    • Add ChatChannelController.setPushPreference(level:)
    • Add ChatChannelController.snoozePushNotifications(until:)

Stream Bot and others added 5 commits September 22, 2025 16:20
* Add Push Preference Payloads and Endpoint

* Add domain models and `CurrentUserController.setUserPushPreferences`

* Add user profile push preference UI to the Demo App

* Fix parsing push preference response

* Improve the interface of the current user push preference

* Add disablePushNotifications to CurrentUserController

* Fix channel preferences payload parsing

* Add push preference feature to channel controller

* Fix push preference payload parsing when channel is empty

* Fix nested hell parsing for channel preferences

* Reuse preferences view for both channel and user preferences

* Improve the UX of the PushPreferencesView

* Make the parsing of channel preferences easier to read

* Merge UserPushPreference and ChannelPushPreference into one

* Update Demo App min version

* Add push preference to both Channel and CurrentUser models

* Add initial data to user preferences view

* Fix PushPreferencesDTO not creating in the local DB

* Remove top right save button in preferences view

* Trigger currentUser and channel updates when push pref is changed

* Remove userId from the Request Payload since the backend automatically uses the current user

* Change the name from disablePushNotifications to snoozePushNotifications

* Change button name to Snooze Notifications

* Review changes

* Add payload parsing test coverage

* Fix existing tests so that it compiles

* Add endpoint test coverage

* Add ChannelDTO and CurrentUserDTO test coverage

* Add test coverage to controllers and updaters

* Fix push preference payload tests

* Update CHANGELOG.md

* Update CHANGELOG.md

* Fix failing new tests
@Stream-SDK-Bot Stream-SDK-Bot requested a review from a team as a code owner October 7, 2025 06:22
@coderabbitai
Copy link

coderabbitai bot commented Oct 7, 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.90.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

github-actions bot commented Oct 7, 2025

1 Warning
⚠️ Big PR

Generated by 🚫 Danger

@github-actions
Copy link

github-actions bot commented Oct 7, 2025

Public Interface

+ public struct PushPreferenceLevel: RawRepresentable, Equatable, ExpressibleByStringLiteral  
+ 
+   public let rawValue: String
+   public static var none: PushPreferenceLevel
+   public static var mentions: PushPreferenceLevel
+   public static var all: PushPreferenceLevel
+   
+ 
+   public init(rawValue: String)
+   public init(stringLiteral value: StringLiteralType)

+ public struct PushPreference: Equatable  
+ 
+   public let level: PushPreferenceLevel
+   public let disabledUntil: Date?



 public class LivestreamChannelController: DataStoreProvider, EventsControllerDelegate, AppStateObserverDelegate  
-   public func synchronize(_ completion: (@MainActor(_ error: Error?) -> Void)? = nil)
+   public func synchronize(_ completion: (@MainActor (_ error: Error?) -> Void)? = nil)
-   public func loadPreviousMessages(before messageId: MessageId? = nil,limit: Int? = nil,completion: (@MainActor(Error?) -> Void)? = nil)
+   public func loadPreviousMessages(before messageId: MessageId? = nil,limit: Int? = nil,completion: (@MainActor (Error?) -> Void)? = nil)
-   public func loadNextMessages(after messageId: MessageId? = nil,limit: Int? = nil,completion: (@MainActor(Error?) -> Void)? = nil)
+   public func loadNextMessages(after messageId: MessageId? = nil,limit: Int? = nil,completion: (@MainActor (Error?) -> Void)? = nil)
-   public func loadPageAroundMessageId(_ messageId: MessageId,limit: Int? = nil,completion: (@MainActor(Error?) -> Void)? = nil)
+   public func loadPageAroundMessageId(_ messageId: MessageId,limit: Int? = nil,completion: (@MainActor (Error?) -> Void)? = nil)
-   public func loadFirstPage(_ completion: (@MainActor(_ error: Error?) -> Void)? = nil)
+   public func loadFirstPage(_ completion: (@MainActor (_ error: Error?) -> Void)? = nil)
-   public func createNewMessage(messageId: MessageId? = nil,text: String,pinning: MessagePinning? = nil,isSilent: Bool = false,attachments: [AnyAttachmentPayload] = [],mentionedUserIds: [UserId] = [],quotedMessageId: MessageId? = nil,skipPush: Bool = false,skipEnrichUrl: Bool = false,restrictedVisibility: [UserId] = [],location: NewLocationInfo? = nil,extraData: [String: RawJSON] = [:],completion: (@MainActor(Result<MessageId, Error>) -> Void)? = nil)
+   public func createNewMessage(messageId: MessageId? = nil,text: String,pinning: MessagePinning? = nil,isSilent: Bool = false,attachments: [AnyAttachmentPayload] = [],mentionedUserIds: [UserId] = [],quotedMessageId: MessageId? = nil,skipPush: Bool = false,skipEnrichUrl: Bool = false,restrictedVisibility: [UserId] = [],location: NewLocationInfo? = nil,extraData: [String: RawJSON] = [:],completion: (@MainActor (Result<MessageId, Error>) -> Void)? = nil)
-   public func deleteMessage(messageId: MessageId,hard: Bool = false,completion: (@MainActor(Error?) -> Void)? = nil)
+   public func deleteMessage(messageId: MessageId,hard: Bool = false,completion: (@MainActor (Error?) -> Void)? = nil)
-   public func loadReactions(for messageId: MessageId,limit: Int = 25,offset: Int = 0,completion: @escaping @MainActor(Result<[ChatMessageReaction], Error>) -> Void)
+   public func loadReactions(for messageId: MessageId,limit: Int = 25,offset: Int = 0,completion: @escaping @MainActor (Result<[ChatMessageReaction], Error>) -> Void)
-   public func flag(messageId: MessageId,reason: String? = nil,extraData: [String: RawJSON]? = nil,completion: (@MainActor(Error?) -> Void)? = nil)
+   public func flag(messageId: MessageId,reason: String? = nil,extraData: [String: RawJSON]? = nil,completion: (@MainActor (Error?) -> Void)? = nil)
-   public func unflag(messageId: MessageId,completion: (@MainActor(Error?) -> Void)? = nil)
+   public func unflag(messageId: MessageId,completion: (@MainActor (Error?) -> Void)? = nil)
-   public func addReaction(_ type: MessageReactionType,to messageId: MessageId,score: Int = 1,enforceUnique: Bool = false,skipPush: Bool = false,pushEmojiCode: String? = nil,extraData: [String: RawJSON] = [:],completion: (@MainActor(Error?) -> Void)? = nil)
+   public func addReaction(_ type: MessageReactionType,to messageId: MessageId,score: Int = 1,enforceUnique: Bool = false,skipPush: Bool = false,pushEmojiCode: String? = nil,extraData: [String: RawJSON] = [:],completion: (@MainActor (Error?) -> Void)? = nil)
-   public func deleteReaction(_ type: MessageReactionType,from messageId: MessageId,completion: (@MainActor(Error?) -> Void)? = nil)
+   public func deleteReaction(_ type: MessageReactionType,from messageId: MessageId,completion: (@MainActor (Error?) -> Void)? = nil)
-   public func pin(messageId: MessageId,pinning: MessagePinning = .noExpiration,completion: (@MainActor(Error?) -> Void)? = nil)
+   public func pin(messageId: MessageId,pinning: MessagePinning = .noExpiration,completion: (@MainActor (Error?) -> Void)? = nil)
-   public func unpin(messageId: MessageId,completion: (@MainActor(Error?) -> Void)? = nil)
+   public func unpin(messageId: MessageId,completion: (@MainActor (Error?) -> Void)? = nil)
-   public func loadPinnedMessages(pageSize: Int = .messagesPageSize,sorting: [Sorting<PinnedMessagesSortingKey>] = [],pagination: PinnedMessagesPagination? = nil,completion: @escaping @MainActor(Result<[ChatMessage], Error>) -> Void)
+   public func loadPinnedMessages(pageSize: Int = .messagesPageSize,sorting: [Sorting<PinnedMessagesSortingKey>] = [],pagination: PinnedMessagesPagination? = nil,completion: @escaping @MainActor (Result<[ChatMessage], Error>) -> Void)
-   public func enableSlowMode(cooldownDuration: Int,completion: (@MainActor(Error?) -> Void)? = nil)
+   public func enableSlowMode(cooldownDuration: Int,completion: (@MainActor (Error?) -> Void)? = nil)
-   public func disableSlowMode(completion: (@MainActor(Error?) -> Void)? = nil)
+   public func disableSlowMode(completion: (@MainActor (Error?) -> Void)? = nil)
-   public func resume(completion: (@MainActor(Error?) -> Void)? = nil)
+   public func resume(completion: (@MainActor (Error?) -> Void)? = nil)

 public class CurrentChatUser: ChatUser  
+   public let pushPreference: PushPreference?

 public struct ChatChannel  
-   
+   public let pushPreference: PushPreference?
- 
+   
-   public func replacing(name: String?,imageURL: URL?,extraData: [String: RawJSON]?)-> ChatChannel
+ 
-   public func changing(name: String? = nil,imageURL: URL? = nil,lastMessageAt: Date? = nil,createdAt: Date? = nil,deletedAt: Date? = nil,updatedAt: Date? = nil,truncatedAt: Date? = nil,isHidden: Bool? = nil,createdBy: ChatUser? = nil,config: ChannelConfig? = nil,ownCapabilities: Set<ChannelCapability>? = nil,isFrozen: Bool? = nil,isDisabled: Bool? = nil,isBlocked: Bool? = nil,reads: [ChatChannelRead]? = nil,members: [ChatChannelMember]? = nil,membership: ChatChannelMember? = nil,memberCount: Int? = nil,watchers: [ChatUser]? = nil,watcherCount: Int? = nil,team: TeamId? = nil,cooldownDuration: Int? = nil,pinnedMessages: [ChatMessage]? = nil,extraData: [String: RawJSON]? = nil)-> ChatChannel
+   public func replacing(name: String?,imageURL: URL?,extraData: [String: RawJSON]?)-> ChatChannel
+   public func changing(name: String? = nil,imageURL: URL? = nil,lastMessageAt: Date? = nil,createdAt: Date? = nil,deletedAt: Date? = nil,updatedAt: Date? = nil,truncatedAt: Date? = nil,isHidden: Bool? = nil,createdBy: ChatUser? = nil,config: ChannelConfig? = nil,ownCapabilities: Set<ChannelCapability>? = nil,isFrozen: Bool? = nil,isDisabled: Bool? = nil,isBlocked: Bool? = nil,reads: [ChatChannelRead]? = nil,members: [ChatChannelMember]? = nil,membership: ChatChannelMember? = nil,memberCount: Int? = nil,watchers: [ChatUser]? = nil,watcherCount: Int? = nil,team: TeamId? = nil,cooldownDuration: Int? = nil,pinnedMessages: [ChatMessage]? = nil,pushPreference: PushPreference? = nil,extraData: [String: RawJSON]? = nil)-> ChatChannel

 public class ChatChannelController: DataController, DelegateCallable, DataStoreProvider  
+   public func setPushPreference(level: PushPreferenceLevel,completion: ((Result<PushPreference, Error>) -> Void)? = nil)
+   public func snoozePushNotifications(until date: Date,completion: ((Result<PushPreference, Error>) -> Void)? = nil)

@Stream-SDK-Bot
Copy link
Collaborator Author

SDK Size

title previous release current release diff status
StreamChat 8.13 MB 8.25 MB +123 KB 🟢
StreamChatUI 4.88 MB 4.89 MB +16 KB 🟢

@github-actions
Copy link

github-actions bot commented Oct 7, 2025

Build for regression testing №123457099 has been uploaded to TestFlight 🎁

@Stream-SDK-Bot
Copy link
Collaborator Author

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.09 fps 4.12% 🔼 🟢
Number of hitches 1 0.4 60.0% 🔼 🟢

@sonarqubecloud
Copy link

sonarqubecloud bot commented Oct 7, 2025

Quality Gate Failed Quality Gate failed

Failed conditions
C Reliability Rating on New Code (required ≥ A)

See analysis details on SonarQube Cloud

Catch issues before they fail your Quality Gate with our IDE extension SonarQube for IDE

@laevandus
Copy link
Contributor

/merge release

@testableapple
Copy link
Contributor

Publication of the release has been launched 👍

@github-actions github-actions bot merged commit 8108798 into main Oct 7, 2025
33 of 36 checks passed
@github-actions github-actions bot deleted the release/4.90.0 branch October 7, 2025 14:07
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