Skip to content

Conversation

laevandus
Copy link
Contributor

🔗 Issue Links

Related: IOS-1003

🎯 Goal

StreamCollection and LazyCachedMapCollection do not add any value anymore

☑️ 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

@laevandus laevandus requested a review from a team as a code owner October 3, 2025 06:57
@laevandus laevandus added the 💥 Breaking Changes A PR that contains breaking changes label Oct 3, 2025
repositoryURL = "https://github.com/GetStream/stream-chat-swift.git";
requirement = {
branch = v5;
branch = "v5-remove-stream-collection-lazy-cached-map-collection";
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Revert before merge

@Stream-SDK-Bot
Copy link
Collaborator

SDK Size

title develop branch diff status
StreamChatSwiftUI 9.48 MB 9.72 MB +247 KB 🟢

Copy link

github-actions bot commented Oct 3, 2025

1 Message
📖 There seems to be app changes but CHANGELOG wasn't modified.
Please include an entry if the PR includes user-facing changes.
You can find it at CHANGELOG.md.

Generated by 🚫 Danger

Copy link

github-actions bot commented Oct 3, 2025

Public Interface

 public class MuteCommandHandler: TwoStepMentionCommand  
-   override public func executeOnMessageSent(composerCommand: ComposerCommand,completion: @escaping (Error?) -> Void)
+   override public func executeOnMessageSent(composerCommand: ComposerCommand,completion: @escaping @MainActor (Error?) -> Void)

 public struct ChannelList: View  
-   public init(factory: Factory,channels: LazyCachedMapCollection<ChatChannel>,selectedChannel: Binding<ChannelSelectionInfo?>,swipedChannelId: Binding<String?>,scrolledChannelId: Binding<String?> = .constant(nil),scrollable: Bool = true,onlineIndicatorShown: ((ChatChannel) -> Bool)? = nil,imageLoader: ((ChatChannel) -> UIImage)? = nil,onItemTap: @escaping (ChatChannel) -> Void,onItemAppear: @escaping (Int) -> Void,channelNaming: ((ChatChannel) -> String)? = nil,channelDestination: @escaping (ChannelSelectionInfo) -> Factory.ChannelDestination,trailingSwipeRightButtonTapped: @escaping (ChatChannel) -> Void = { _ in },trailingSwipeLeftButtonTapped: @escaping (ChatChannel) -> Void = { _ in },leadingSwipeButtonTapped: @escaping (ChatChannel) -> Void = { _ in })
+   public init(factory: Factory,channels: [ChatChannel],selectedChannel: Binding<ChannelSelectionInfo?>,swipedChannelId: Binding<String?>,scrolledChannelId: Binding<String?> = .constant(nil),scrollable: Bool = true,onlineIndicatorShown: ((ChatChannel) -> Bool)? = nil,imageLoader: ((ChatChannel) -> UIImage)? = nil,onItemTap: @escaping (ChatChannel) -> Void,onItemAppear: @escaping (Int) -> Void,channelNaming: ((ChatChannel) -> String)? = nil,channelDestination: @escaping (ChannelSelectionInfo) -> Factory.ChannelDestination,trailingSwipeRightButtonTapped: @escaping (ChatChannel) -> Void = { _ in },trailingSwipeLeftButtonTapped: @escaping (ChatChannel) -> Void = { _ in },leadingSwipeButtonTapped: @escaping (ChatChannel) -> Void = { _ in })

- open class ChannelHeaderLoader: ObservableObject  
+ @MainActor open class ChannelHeaderLoader: ObservableObject  
-   public init()
+   public nonisolated init()

- public protocol CommandHandler
+ @MainActor public protocol CommandHandler

- public struct AddedVoiceRecording: Identifiable, Equatable  
+ public struct AddedVoiceRecording: Identifiable, Equatable, Sendable  

 public struct ThreadsLazyVStack: View  
-   public init(factory: Factory,threads: LazyCachedMapCollection<ChatThread>,threadDestination: @escaping (ChatThread) -> Factory.ThreadDestination,selectedThread: Binding<ThreadSelectionInfo?>,onItemTap: @escaping (ChatThread) -> Void,onItemAppear: @escaping (Int) -> Void)
+   public init(factory: Factory,threads: [ChatThread],threadDestination: @escaping @MainActor (ChatThread) -> Factory.ThreadDestination,selectedThread: Binding<ThreadSelectionInfo?>,onItemTap: @escaping (ChatThread) -> Void,onItemAppear: @escaping (Int) -> Void)

- open class ChatThreadListViewModel: ObservableObject, ChatThreadListControllerDelegate, EventsControllerDelegate  
+ @MainActor open class ChatThreadListViewModel: ObservableObject, ChatThreadListControllerDelegate, EventsControllerDelegate  

 public class Utils  
-   public lazy var audioSessionFeedbackGenerator: AudioSessionFeedbackGenerator
+   @MainActor public lazy var audioSessionFeedbackGenerator: AudioSessionFeedbackGenerator

- public protocol AudioSessionFeedbackGenerator
+ @MainActor public protocol AudioSessionFeedbackGenerator

 open class NukeImageLoader: ImageLoading  
-   open func loadImage(using urlRequest: URLRequest,cachingKey: String?,completion: @escaping ((Result<UIImage, Error>) -> Void))
+   open func loadImage(using urlRequest: URLRequest,cachingKey: String?,completion: @escaping @MainActor (Result<UIImage, Error>) -> Void)
-   open func loadImages(from urls: [URL],placeholders: [UIImage],loadThumbnails: Bool,thumbnailSize: CGSize,imageCDN: ImageCDN,completion: @escaping (([UIImage]) -> Void))
+   open func loadImages(from urls: [URL],placeholders: [UIImage],loadThumbnails: Bool,thumbnailSize: CGSize,imageCDN: ImageCDN,completion: @escaping @MainActor ([UIImage]) -> Void)
-   open func loadImage(url: URL?,imageCDN: ImageCDN,resize: Bool = true,preferredSize: CGSize? = nil,completion: @escaping ((Result<UIImage, Error>) -> Void))
+   open func loadImage(url: URL?,imageCDN: ImageCDN,resize: Bool = true,preferredSize: CGSize? = nil,completion: @escaping @MainActor (Result<UIImage, Error>) -> Void)

 public struct ChannelsLazyVStack: View  
-   public init(factory: Factory,channels: LazyCachedMapCollection<ChatChannel>,selectedChannel: Binding<ChannelSelectionInfo?>,swipedChannelId: Binding<String?>,onlineIndicatorShown: @escaping (ChatChannel) -> Bool,imageLoader: @escaping (ChatChannel) -> UIImage,onItemTap: @escaping (ChatChannel) -> Void,onItemAppear: @escaping (Int) -> Void,channelNaming: @escaping (ChatChannel) -> String,channelDestination: @escaping (ChannelSelectionInfo) -> Factory.ChannelDestination,trailingSwipeRightButtonTapped: @escaping (ChatChannel) -> Void,trailingSwipeLeftButtonTapped: @escaping (ChatChannel) -> Void,leadingSwipeButtonTapped: @escaping (ChatChannel) -> Void)
+   public init(factory: Factory,channels: [ChatChannel],selectedChannel: Binding<ChannelSelectionInfo?>,swipedChannelId: Binding<String?>,onlineIndicatorShown: @escaping @MainActor (ChatChannel) -> Bool,imageLoader: @escaping @MainActor (ChatChannel) -> UIImage,onItemTap: @escaping @MainActor (ChatChannel) -> Void,onItemAppear: @escaping @MainActor (Int) -> Void,channelNaming: @escaping @MainActor (ChatChannel) -> String,channelDestination: @escaping @MainActor (ChannelSelectionInfo) -> Factory.ChannelDestination,trailingSwipeRightButtonTapped: @escaping @MainActor (ChatChannel) -> Void,trailingSwipeLeftButtonTapped: @escaping @MainActor (ChatChannel) -> Void,leadingSwipeButtonTapped: @escaping @MainActor (ChatChannel) -> Void)

 public struct MessageAction: Identifiable, Equatable  
-   public let action: () -> Void
+   public let action: @MainActor () -> Void
-   public init(id: String = UUID().uuidString,title: String,iconName: String,action: @escaping () -> Void,confirmationPopup: ConfirmationPopup?,isDestructive: Bool)
+   public init(id: String = UUID().uuidString,title: String,iconName: String,action: @escaping @MainActor () -> Void,confirmationPopup: ConfirmationPopup?,isDestructive: Bool)

- public class PinnedMessagesViewModel: ObservableObject  
+ @MainActor public class PinnedMessagesViewModel: ObservableObject  

 public struct ChatChannelSwipeableListItem: View  
-   public init(factory: Factory,channelListItem: ChannelListItem,swipedChannelId: Binding<String?>,channel: ChatChannel,numberOfTrailingItems: Int = 2,widthOfTrailingItem: CGFloat = 60,trailingRightButtonTapped: @escaping (ChatChannel) -> Void,trailingLeftButtonTapped: @escaping (ChatChannel) -> Void,leadingSwipeButtonTapped: @escaping (ChatChannel) -> Void)
+   public init(factory: Factory,channelListItem: ChannelListItem,swipedChannelId: Binding<String?>,channel: ChatChannel,numberOfTrailingItems: Int = 2,widthOfTrailingItem: CGFloat = 60,trailingRightButtonTapped: @escaping @MainActor (ChatChannel) -> Void,trailingLeftButtonTapped: @escaping @MainActor (ChatChannel) -> Void,leadingSwipeButtonTapped: @escaping @MainActor (ChatChannel) -> Void)

- public struct ChannelSelectionInfo: Identifiable  
+ public struct ChannelSelectionInfo: Identifiable, Sendable  

- public class ViewModelsFactory  
+ @MainActor public class ViewModelsFactory  

 public class UnmuteCommandHandler: TwoStepMentionCommand  
-   override public func executeOnMessageSent(composerCommand: ComposerCommand,completion: @escaping (Error?) -> Void)
+   override public func executeOnMessageSent(composerCommand: ComposerCommand,completion: @escaping @MainActor (Error?) -> Void)

- open class MessageActionsViewModel: ObservableObject  
+ @MainActor open class MessageActionsViewModel: ObservableObject  

 public class CommandsHandler: CommandHandler  
-   public func executeOnMessageSent(composerCommand: ComposerCommand,completion: @escaping (Error?) -> Void)
+   public func executeOnMessageSent(composerCommand: ComposerCommand,completion: @escaping @MainActor (Error?) -> Void)

- public struct PollsConfig  
+ public struct PollsConfig: Sendable  

 public struct AppearanceKey: EnvironmentKey  
-   public static let defaultValue: Appearance
+   public static var defaultValue: Appearance

 public struct ThreadList: View  
-   public init(factory: Factory,threads: LazyCachedMapCollection<ChatThread>,threadDestination: @escaping (ChatThread) -> Factory.ThreadDestination,selectedThread: Binding<ThreadSelectionInfo?>,onItemTap: @escaping (ChatThread) -> Void,onItemAppear: @escaping (Int) -> Void,headerView: @escaping () -> HeaderView,footerView: @escaping () -> FooterView)
+   public init(factory: Factory,threads: [ChatThread],threadDestination: @escaping (ChatThread) -> Factory.ThreadDestination,selectedThread: Binding<ThreadSelectionInfo?>,onItemTap: @escaping (ChatThread) -> Void,onItemAppear: @escaping (Int) -> Void,headerView: @escaping () -> HeaderView,footerView: @escaping () -> FooterView)

 open class StreamImageCDN: ImageCDN  
-   public static var streamCDNURL
+   public static let streamCDNURL

- public struct PollsEntryConfig  
+ public struct PollsEntryConfig: Sendable  

 public struct StreamChatError: Error  
-   public let additionalInfo: [String: Any]?
+   public nonisolated let additionalInfo: [String: Any]?

- public struct InjectedChannelInfo  
+ public struct InjectedChannelInfo: Sendable  

 public struct AttachmentPickerView: View  
-   public init(viewFactory: Factory,selectedPickerState: Binding<AttachmentPickerState>,filePickerShown: Binding<Bool>,cameraPickerShown: Binding<Bool>,addedFileURLs: Binding<[URL]>,onPickerStateChange: @escaping (AttachmentPickerState) -> Void,photoLibraryAssets: PHFetchResult<PHAsset>? = nil,onAssetTap: @escaping (AddedAsset) -> Void,onCustomAttachmentTap: @escaping (CustomAttachment) -> Void,isAssetSelected: @escaping (String) -> Bool,addedCustomAttachments: [CustomAttachment],cameraImageAdded: @escaping (AddedAsset) -> Void,askForAssetsAccessPermissions: @escaping () -> Void,isDisplayed: Bool,height: CGFloat)
+   public init(viewFactory: Factory,selectedPickerState: Binding<AttachmentPickerState>,filePickerShown: Binding<Bool>,cameraPickerShown: Binding<Bool>,addedFileURLs: Binding<[URL]>,onPickerStateChange: @escaping @MainActor (AttachmentPickerState) -> Void,photoLibraryAssets: PHFetchResult<PHAsset>? = nil,onAssetTap: @escaping @MainActor (AddedAsset) -> Void,onCustomAttachmentTap: @escaping @MainActor (CustomAttachment) -> Void,isAssetSelected: @escaping @MainActor (String) -> Bool,addedCustomAttachments: [CustomAttachment],cameraImageAdded: @escaping @MainActor (AddedAsset) -> Void,askForAssetsAccessPermissions: @escaping () -> Void,isDisplayed: Bool,height: CGFloat)

- public enum AssetType  
+ public enum AssetType: Sendable  

- public struct PaddingsConfig  
+ public struct PaddingsConfig: Sendable  

 extension ViewFactory  
-   public func supportedMoreChannelActions(for channel: ChatChannel,onDismiss: @escaping () -> Void,onError: @escaping (Error) -> Void)-> [ChannelAction]
+   public func supportedMoreChannelActions(for channel: ChatChannel,onDismiss: @escaping @MainActor () -> Void,onError: @escaping @MainActor (Error) -> Void)-> [ChannelAction]
-   public func makeMoreChannelActionsView(for channel: ChatChannel,swipedChannelId: Binding<String?>,onDismiss: @escaping () -> Void,onError: @escaping (Error) -> Void)-> some View
+   public func makeMoreChannelActionsView(for channel: ChatChannel,swipedChannelId: Binding<String?>,onDismiss: @escaping @MainActor () -> Void,onError: @escaping @MainActor (Error) -> Void)-> some View
-   public func makeChannelListItem(channel: ChatChannel,channelName: String,avatar: UIImage,onlineIndicatorShown: Bool,disabled: Bool,selectedChannel: Binding<ChannelSelectionInfo?>,swipedChannelId: Binding<String?>,channelDestination: @escaping (ChannelSelectionInfo) -> ChannelDestination,onItemTap: @escaping (ChatChannel) -> Void,trailingSwipeRightButtonTapped: @escaping (ChatChannel) -> Void,trailingSwipeLeftButtonTapped: @escaping (ChatChannel) -> Void,leadingSwipeButtonTapped: @escaping (ChatChannel) -> Void)-> some View
+   public func makeChannelListItem(channel: ChatChannel,channelName: String,avatar: UIImage,onlineIndicatorShown: Bool,disabled: Bool,selectedChannel: Binding<ChannelSelectionInfo?>,swipedChannelId: Binding<String?>,channelDestination: @escaping @MainActor (ChannelSelectionInfo) -> ChannelDestination,onItemTap: @escaping @MainActor (ChatChannel) -> Void,trailingSwipeRightButtonTapped: @escaping @MainActor (ChatChannel) -> Void,trailingSwipeLeftButtonTapped: @escaping @MainActor (ChatChannel) -> Void,leadingSwipeButtonTapped: @escaping @MainActor (ChatChannel) -> Void)-> some View
-   public func makeTrailingSwipeActionsView(channel: ChatChannel,offsetX: CGFloat,buttonWidth: CGFloat,swipedChannelId: Binding<String?>,leftButtonTapped: @escaping (ChatChannel) -> Void,rightButtonTapped: @escaping (ChatChannel) -> Void)-> TrailingSwipeActionsView
+   public func makeTrailingSwipeActionsView(channel: ChatChannel,offsetX: CGFloat,buttonWidth: CGFloat,swipedChannelId: Binding<String?>,leftButtonTapped: @escaping @MainActor (ChatChannel) -> Void,rightButtonTapped: @escaping @MainActor (ChatChannel) -> Void)-> TrailingSwipeActionsView
-   public func makeLeadingSwipeActionsView(channel: ChatChannel,offsetX: CGFloat,buttonWidth: CGFloat,swipedChannelId: Binding<String?>,buttonTapped: (ChatChannel) -> Void)-> EmptyView
+   public func makeLeadingSwipeActionsView(channel: ChatChannel,offsetX: CGFloat,buttonWidth: CGFloat,swipedChannelId: Binding<String?>,buttonTapped: @MainActor (ChatChannel) -> Void)-> EmptyView
-   public func makeSearchResultsView(selectedChannel: Binding<ChannelSelectionInfo?>,searchResults: [ChannelSelectionInfo],loadingSearchResults: Bool,onlineIndicatorShown: @escaping (ChatChannel) -> Bool,channelNaming: @escaping (ChatChannel) -> String,imageLoader: @escaping (ChatChannel) -> UIImage,onSearchResultTap: @escaping (ChannelSelectionInfo) -> Void,onItemAppear: @escaping (Int) -> Void)-> some View
+   public func makeSearchResultsView(selectedChannel: Binding<ChannelSelectionInfo?>,searchResults: [ChannelSelectionInfo],loadingSearchResults: Bool,onlineIndicatorShown: @escaping @MainActor (ChatChannel) -> Bool,channelNaming: @escaping @MainActor (ChatChannel) -> String,imageLoader: @escaping @MainActor (ChatChannel) -> UIImage,onSearchResultTap: @escaping @MainActor (ChannelSelectionInfo) -> Void,onItemAppear: @escaping @MainActor (Int) -> Void)-> some View
-   public func makeChannelListSearchResultItem(searchResult: ChannelSelectionInfo,onlineIndicatorShown: Bool,channelName: String,avatar: UIImage,onSearchResultTap: @escaping (ChannelSelectionInfo) -> Void,channelDestination: @escaping (ChannelSelectionInfo) -> ChannelDestination)-> some View
+   public func makeChannelListSearchResultItem(searchResult: ChannelSelectionInfo,onlineIndicatorShown: Bool,channelName: String,avatar: UIImage,onSearchResultTap: @escaping @MainActor (ChannelSelectionInfo) -> Void,channelDestination: @escaping @MainActor (ChannelSelectionInfo) -> ChannelDestination)-> some View
-   public func makeChannelDestination()-> (ChannelSelectionInfo) -> ChatChannelView<Self>
+   public func makeChannelDestination()-> @MainActor (ChannelSelectionInfo) -> ChatChannelView<Self>
-   public func makeMessageThreadDestination()-> (ChatChannel, ChatMessage) -> ChatChannelView<Self>
+   public func makeMessageThreadDestination()-> @MainActor (ChatChannel, ChatMessage) -> ChatChannelView<Self>
-   public func makeMessageContainerView(channel: ChatChannel,message: ChatMessage,width: CGFloat?,showsAllInfo: Bool,isInThread: Bool,scrolledId: Binding<String?>,quotedMessage: Binding<ChatMessage?>,onLongPress: @escaping (MessageDisplayInfo) -> Void,isLast: Bool)-> some View
+   public func makeMessageContainerView(channel: ChatChannel,message: ChatMessage,width: CGFloat?,showsAllInfo: Bool,isInThread: Bool,scrolledId: Binding<String?>,quotedMessage: Binding<ChatMessage?>,onLongPress: @escaping @MainActor (MessageDisplayInfo) -> Void,isLast: Bool)-> some View
-   public func makeScrollToBottomButton(unreadCount: Int,onScrollToBottom: @escaping () -> Void)-> some View
+   public func makeScrollToBottomButton(unreadCount: Int,onScrollToBottom: @escaping @MainActor () -> Void)-> some View
-   public func makeMessageComposerViewType(with channelController: ChatChannelController,messageController: ChatMessageController?,quotedMessage: Binding<ChatMessage?>,editedMessage: Binding<ChatMessage?>,onMessageSent: @escaping () -> Void)-> MessageComposerView<Self>
+   public func makeMessageComposerViewType(with channelController: ChatChannelController,messageController: ChatMessageController?,quotedMessage: Binding<ChatMessage?>,editedMessage: Binding<ChatMessage?>,onMessageSent: @escaping @MainActor () -> Void)-> MessageComposerView<Self>
-   @ViewBuilder public func makeComposerInputView(text: Binding<String>,selectedRangeLocation: Binding<Int>,command: Binding<ComposerCommand?>,addedAssets: [AddedAsset],addedFileURLs: [URL],addedCustomAttachments: [CustomAttachment],quotedMessage: Binding<ChatMessage?>,maxMessageLength: Int?,cooldownDuration: Int,onCustomAttachmentTap: @escaping (CustomAttachment) -> Void,shouldScroll: Bool,removeAttachmentWithId: @escaping (String) -> Void)-> some View
+   @ViewBuilder public func makeComposerInputView(text: Binding<String>,selectedRangeLocation: Binding<Int>,command: Binding<ComposerCommand?>,addedAssets: [AddedAsset],addedFileURLs: [URL],addedCustomAttachments: [CustomAttachment],quotedMessage: Binding<ChatMessage?>,maxMessageLength: Int?,cooldownDuration: Int,onCustomAttachmentTap: @escaping @MainActor (CustomAttachment) -> Void,shouldScroll: Bool,removeAttachmentWithId: @escaping @MainActor (String) -> Void)-> some View
-   public func makeTrailingComposerView(enabled: Bool,cooldownDuration: Int,onTap: @escaping () -> Void)-> some View
+   public func makeTrailingComposerView(enabled: Bool,cooldownDuration: Int,onTap: @escaping @MainActor () -> Void)-> some View
-   public func makeAttachmentPickerView(attachmentPickerState: Binding<AttachmentPickerState>,filePickerShown: Binding<Bool>,cameraPickerShown: Binding<Bool>,addedFileURLs: Binding<[URL]>,onPickerStateChange: @escaping (AttachmentPickerState) -> Void,photoLibraryAssets: PHFetchResult<PHAsset>?,onAssetTap: @escaping (AddedAsset) -> Void,onCustomAttachmentTap: @escaping (CustomAttachment) -> Void,isAssetSelected: @escaping (String) -> Bool,addedCustomAttachments: [CustomAttachment],cameraImageAdded: @escaping (AddedAsset) -> Void,askForAssetsAccessPermissions: @escaping () -> Void,isDisplayed: Bool,height: CGFloat,popupHeight: CGFloat)-> some View
+   public func makeAttachmentPickerView(attachmentPickerState: Binding<AttachmentPickerState>,filePickerShown: Binding<Bool>,cameraPickerShown: Binding<Bool>,addedFileURLs: Binding<[URL]>,onPickerStateChange: @escaping @MainActor (AttachmentPickerState) -> Void,photoLibraryAssets: PHFetchResult<PHAsset>?,onAssetTap: @escaping @MainActor (AddedAsset) -> Void,onCustomAttachmentTap: @escaping @MainActor (CustomAttachment) -> Void,isAssetSelected: @escaping @MainActor (String) -> Bool,addedCustomAttachments: [CustomAttachment],cameraImageAdded: @escaping @MainActor (AddedAsset) -> Void,askForAssetsAccessPermissions: @escaping @MainActor () -> Void,isDisplayed: Bool,height: CGFloat,popupHeight: CGFloat)-> some View
-   public func makeCustomAttachmentView(addedCustomAttachments: [CustomAttachment],onCustomAttachmentTap: @escaping (CustomAttachment) -> Void)-> some View
+   public func makeCustomAttachmentView(addedCustomAttachments: [CustomAttachment],onCustomAttachmentTap: @escaping @MainActor (CustomAttachment) -> Void)-> some View
-   public func makeCustomAttachmentPreviewView(addedCustomAttachments: [CustomAttachment],onCustomAttachmentTap: @escaping (CustomAttachment) -> Void)-> some View
+   public func makeCustomAttachmentPreviewView(addedCustomAttachments: [CustomAttachment],onCustomAttachmentTap: @escaping @MainActor (CustomAttachment) -> Void)-> some View
-   public func makeAttachmentSourcePickerView(selected: AttachmentPickerState,onPickerStateChange: @escaping (AttachmentPickerState) -> Void)-> some View
+   public func makeAttachmentSourcePickerView(selected: AttachmentPickerState,onPickerStateChange: @escaping @MainActor (AttachmentPickerState) -> Void)-> some View
-   public func makePhotoAttachmentPickerView(assets: PHFetchResultCollection,onAssetTap: @escaping (AddedAsset) -> Void,isAssetSelected: @escaping (String) -> Bool)-> some View
+   public func makePhotoAttachmentPickerView(assets: PHFetchResultCollection,onAssetTap: @escaping @MainActor (AddedAsset) -> Void,isAssetSelected: @escaping @MainActor (String) -> Bool)-> some View
-   public func makeCameraPickerView(selected: Binding<AttachmentPickerState>,cameraPickerShown: Binding<Bool>,cameraImageAdded: @escaping (AddedAsset) -> Void)-> some View
+   public func makeCameraPickerView(selected: Binding<AttachmentPickerState>,cameraPickerShown: Binding<Bool>,cameraImageAdded: @escaping @MainActor (AddedAsset) -> Void)-> some View
-   public func supportedMessageActions(for message: ChatMessage,channel: ChatChannel,onFinish: @escaping (MessageActionInfo) -> Void,onError: @escaping (Error) -> Void)-> [MessageAction]
+   public func supportedMessageActions(for message: ChatMessage,channel: ChatChannel,onFinish: @escaping @MainActor (MessageActionInfo) -> Void,onError: @escaping @MainActor (Error) -> Void)-> [MessageAction]
-   public func makeMessageActionsView(for message: ChatMessage,channel: ChatChannel,onFinish: @escaping (MessageActionInfo) -> Void,onError: @escaping (Error) -> Void)-> some View
+   public func makeMessageActionsView(for message: ChatMessage,channel: ChatChannel,onFinish: @escaping @MainActor (MessageActionInfo) -> Void,onError: @escaping @MainActor (Error) -> Void)-> some View
-   public func makeBottomReactionsView(message: ChatMessage,showsAllInfo: Bool,onTap: @escaping () -> Void,onLongPress: @escaping () -> Void)-> some View
+   public func makeBottomReactionsView(message: ChatMessage,showsAllInfo: Bool,onTap: @escaping @MainActor () -> Void,onLongPress: @escaping @MainActor () -> Void)-> some View
-   public func makeMessageReactionView(message: ChatMessage,onTapGesture: @escaping () -> Void,onLongPressGesture: @escaping () -> Void)-> some View
+   public func makeMessageReactionView(message: ChatMessage,onTapGesture: @escaping @MainActor () -> Void,onLongPressGesture: @escaping @MainActor () -> Void)-> some View
-   public func makeReactionsOverlayView(channel: ChatChannel,currentSnapshot: UIImage,messageDisplayInfo: MessageDisplayInfo,onBackgroundTap: @escaping () -> Void,onActionExecuted: @escaping (MessageActionInfo) -> Void)-> some View
+   public func makeReactionsOverlayView(channel: ChatChannel,currentSnapshot: UIImage,messageDisplayInfo: MessageDisplayInfo,onBackgroundTap: @escaping @MainActor () -> Void,onActionExecuted: @escaping @MainActor (MessageActionInfo) -> Void)-> some View
-   public func makeReactionsContentView(message: ChatMessage,contentRect: CGRect,onReactionTap: @escaping (MessageReactionType) -> Void)-> some View
+   public func makeReactionsContentView(message: ChatMessage,contentRect: CGRect,onReactionTap: @escaping @MainActor (MessageReactionType) -> Void)-> some View
-   public func makeCommandsContainerView(suggestions: [String: Any],handleCommand: @escaping ([String: Any]) -> Void)-> some View
+   public func makeCommandsContainerView(suggestions: [String: Any],handleCommand: @escaping @MainActor ([String: Any]) -> Void)-> some View
-   public func makeJumpToUnreadButton(channel: ChatChannel,onJumpToMessage: @escaping () -> Void,onClose: @escaping () -> Void)-> some View
+   public func makeJumpToUnreadButton(channel: ChatChannel,onJumpToMessage: @escaping @MainActor () -> Void,onClose: @escaping @MainActor () -> Void)-> some View
-   public func makeThreadDestination()-> (ChatThread) -> ChatChannelView<Self>
+   public func makeThreadDestination()-> @MainActor (ChatThread) -> ChatChannelView<Self>
-   public func makeThreadListItem(thread: ChatThread,threadDestination: @escaping (ChatThread) -> ThreadDestination,selectedThread: Binding<ThreadSelectionInfo?>)-> some View
+   public func makeThreadListItem(thread: ChatThread,threadDestination: @escaping @MainActor (ChatThread) -> ThreadDestination,selectedThread: Binding<ThreadSelectionInfo?>)-> some View
-   public func makeThreadsListErrorBannerView(onRefreshAction: @escaping () -> Void)-> some View
+   public func makeThreadsListErrorBannerView(onRefreshAction: @escaping @MainActor () -> Void)-> some View
-   public func makeAddUsersView(options: AddUsersOptions,onUserTap: @escaping (ChatUser) -> Void)-> some View
+   public func makeAddUsersView(options: AddUsersOptions,onUserTap: @escaping @MainActor (ChatUser) -> Void)-> some View

- open class ChatChannelListViewModel: ObservableObject, ChatChannelListControllerDelegate, ChatMessageSearchControllerDelegate  
+ @MainActor open class ChatChannelListViewModel: ObservableObject, ChatChannelListControllerDelegate, ChatMessageSearchControllerDelegate  

- open class ChatChannelViewModel: ObservableObject, MessagesDataSource  
+ @MainActor open class ChatChannelViewModel: ObservableObject, MessagesDataSource  
-   public var currentUserMarkedMessageUnread: Bool
+   @Published public private var channel: ChatChannel?
-   @Published public private var channel: ChatChannel?
+   public var isMessageThread: Bool
-   public var isMessageThread: Bool
+   
-   
+ 
- 
+   public init(channelController: ChatChannelController,messageController: ChatMessageController? = nil,scrollToMessage: ChatMessage? = nil)
-   public init(channelController: ChatChannelController,messageController: ChatMessageController? = nil,scrollToMessage: ChatMessage? = nil)
+   
-   
+ 
- 
+   public func scrollToLastMessage()
-   public func scrollToLastMessage()
+   public func messageSentTapped()
-   public func messageSentTapped()
+   public func jumpToMessage(messageId: String)-> Bool
-   public func jumpToMessage(messageId: String)-> Bool
+   open func handleMessageAppear(index: Int,scrollDirection: ScrollDirection)
-   open func handleMessageAppear(index: Int,scrollDirection: ScrollDirection)
+   open func groupMessages()
-   open func groupMessages()
+   public func showReactionOverlay(for view: AnyView)
-   public func showReactionOverlay(for view: AnyView)
+   public func showBouncedActionsView(for message: ChatMessage)
-   public func showBouncedActionsView(for message: ChatMessage)
+   public func deleteMessage(_ message: ChatMessage)
-   public func deleteMessage(_ message: ChatMessage)
+   public func resendMessage(_ message: ChatMessage)
-   public func resendMessage(_ message: ChatMessage)
+   public func editMessage(_ message: ChatMessage)
-   public func editMessage(_ message: ChatMessage)
+   open func messageActionExecuted(_ messageActionInfo: MessageActionInfo)
-   open func messageActionExecuted(_ messageActionInfo: MessageActionInfo)
+   @objc public func onViewAppear()
-   @objc public func onViewAppear()
+   @objc public func onViewDissappear()
-   @objc public func onViewDissappear()
+   public func setActive()
-   public func setActive()

 public class Appearance  
-   public static var localizationProvider: (_ key: String, _ table: String) -> String
+   public nonisolated static var localizationProvider: @Sendable (_ key: String, _ table: String) -> String

 public struct ComposerConfig  
-   public static var defaultAttachmentPayloadConverter: (ChatMessage) -> [AnyAttachmentPayload]
+   public nonisolated static var defaultAttachmentPayloadConverter: (ChatMessage) -> [AnyAttachmentPayload]

 public class InstantCommandsHandler: CommandHandler  
-   public func executeOnMessageSent(composerCommand: ComposerCommand,completion: @escaping (Error?) -> Void)
+   public func executeOnMessageSent(composerCommand: ComposerCommand,completion: @escaping @MainActor (Error?) -> Void)

 public final class DefaultVideoPreviewLoader: VideoPreviewLoader  
-   public func loadPreviewForVideo(at url: URL,completion: @escaping (Result<UIImage, Error>) -> Void)
+   public func loadPreviewForVideo(at url: URL,completion: @escaping @MainActor (Result<UIImage, Error>) -> Void)

 public struct ComposerInputView: View, KeyboardReadable  
-   public init(factory: Factory,text: Binding<String>,selectedRangeLocation: Binding<Int>,command: Binding<ComposerCommand?>,addedAssets: [AddedAsset],addedFileURLs: [URL],addedCustomAttachments: [CustomAttachment],quotedMessage: Binding<ChatMessage?>,maxMessageLength: Int? = nil,cooldownDuration: Int,onCustomAttachmentTap: @escaping (CustomAttachment) -> Void,removeAttachmentWithId: @escaping (String) -> Void)
+   public init(factory: Factory,text: Binding<String>,selectedRangeLocation: Binding<Int>,command: Binding<ComposerCommand?>,addedAssets: [AddedAsset],addedFileURLs: [URL],addedCustomAttachments: [CustomAttachment],quotedMessage: Binding<ChatMessage?>,maxMessageLength: Int? = nil,cooldownDuration: Int,onCustomAttachmentTap: @escaping @MainActor (CustomAttachment) -> Void,removeAttachmentWithId: @escaping (String) -> Void)

- public struct ChannelItemMutedLayoutStyle: Hashable  
+ public struct ChannelItemMutedLayoutStyle: Hashable, Sendable  
-   public static var `default`: ChannelItemMutedLayoutStyle
+   public static let `default`: ChannelItemMutedLayoutStyle
-   public static var topRightCorner: ChannelItemMutedLayoutStyle
+   public static let topRightCorner: ChannelItemMutedLayoutStyle
-   public static var afterChannelName: ChannelItemMutedLayoutStyle
+   public static let afterChannelName: ChannelItemMutedLayoutStyle

- public struct AddedAsset: Identifiable, Equatable  
+ public struct AddedAsset: Identifiable, Equatable, Sendable  

- public struct AudioRecordingInfo: Equatable  
+ public struct AudioRecordingInfo: Equatable, Sendable  

- open class MessageViewModel: ObservableObject  
+ @MainActor open class MessageViewModel: ObservableObject  

- open class MessageComposerViewModel: ObservableObject  
+ @MainActor open class MessageComposerViewModel: ObservableObject  
-   open func sendMessage(quotedMessage: ChatMessage?,editedMessage: ChatMessage?,isSilent: Bool = false,skipPush: Bool = false,skipEnrichUrl: Bool = false,extraData: [String: RawJSON] = [:],completion: @escaping () -> Void)
+   open func sendMessage(quotedMessage: ChatMessage?,editedMessage: ChatMessage?,isSilent: Bool = false,skipPush: Bool = false,skipEnrichUrl: Bool = false,extraData: [String: RawJSON] = [:],completion: @escaping @MainActor () -> Void)

 extension DateFormatter  
-   public static var messageListDateOverlay: DateFormatter
+   @MainActor public static var messageListDateOverlay: DateFormatter

- open class ChatChannelInfoViewModel: ObservableObject, ChatChannelControllerDelegate  
+ @MainActor open class ChatChannelInfoViewModel: ObservableObject, ChatChannelControllerDelegate  
-   public func leaveConversationTapped(completion: @escaping () -> Void)
+   public func leaveConversationTapped(completion: @escaping @MainActor () -> Void)

- public protocol ViewFactory: AnyObject
+ @MainActor public protocol ViewFactory: AnyObject

- open class MoreChannelActionsViewModel: ObservableObject  
+ @MainActor open class MoreChannelActionsViewModel: ObservableObject  

- public protocol ChannelAvatarsMerging
+ public protocol ChannelAvatarsMerging: Sendable

 open class WaveformView: UIView  
-   public struct Content: Equatable  
+   public struct Content: Equatable, Sendable  

 public struct MessageListView: View, KeyboardReadable  
-   public init(factory: Factory,channel: ChatChannel,messages: LazyCachedMapCollection<ChatMessage>,messagesGroupingInfo: [String: [String]],scrolledId: Binding<String?>,showScrollToLatestButton: Binding<Bool>,quotedMessage: Binding<ChatMessage?>,currentDateString: String? = nil,listId: String,isMessageThread: Bool = false,shouldShowTypingIndicator: Bool = false,scrollPosition: Binding<String?> = .constant(nil),loadingNextMessages: Bool = false,firstUnreadMessageId: Binding<MessageId?> = .constant(nil),onMessageAppear: @escaping (Int, ScrollDirection) -> Void,onScrollToBottom: @escaping () -> Void,onLongPress: @escaping (MessageDisplayInfo) -> Void,onJumpToMessage: ((String) -> Bool)? = nil)
+   public init(factory: Factory,channel: ChatChannel,messages: [ChatMessage],messagesGroupingInfo: [String: [String]],scrolledId: Binding<String?>,showScrollToLatestButton: Binding<Bool>,quotedMessage: Binding<ChatMessage?>,currentDateString: String? = nil,listId: String,isMessageThread: Bool = false,shouldShowTypingIndicator: Bool = false,scrollPosition: Binding<String?> = .constant(nil),loadingNextMessages: Bool = false,firstUnreadMessageId: Binding<MessageId?> = .constant(nil),onMessageAppear: @escaping @MainActor (Int, ScrollDirection) -> Void,onScrollToBottom: @escaping @MainActor () -> Void,onLongPress: @escaping @MainActor (MessageDisplayInfo) -> Void,onJumpToMessage: ((String) -> Bool)? = nil)

- public struct ConfirmationPopup  
+ public struct ConfirmationPopup: Sendable  

 extension CommandHandler  
-   public func executeOnMessageSent(composerCommand: ComposerCommand,completion: @escaping (Error?) -> Void)
+   public func executeOnMessageSent(composerCommand: ComposerCommand,completion: @escaping @MainActor (Error?) -> Void)

- public struct ChannelListSearchType: Equatable  
+ public struct ChannelListSearchType: Equatable, Sendable  
-   public static var channels
+   public static let channels
-   public static var messages
+   public static let messages

- public enum StreamChatErrorCode: Int  
+ public enum StreamChatErrorCode: Int, Sendable  

- public class ChannelAvatarsMerger: ChannelAvatarsMerging  
+ public final class ChannelAvatarsMerger: ChannelAvatarsMerging  

- public class PollAttachmentViewModel: ObservableObject, PollControllerDelegate  
+ @MainActor public class PollAttachmentViewModel: ObservableObject, PollControllerDelegate  

- public struct TypingSuggestion  
+ public struct TypingSuggestion: Sendable  

- open class ReactionsOverlayViewModel: ObservableObject, ChatMessageControllerDelegate  
+ @MainActor open class ReactionsOverlayViewModel: ObservableObject, ChatMessageControllerDelegate  

- public struct ChannelAction: Identifiable  
+ public struct ChannelAction: Identifiable, @unchecked Sendable  
-   public let action: () -> Void
+   public let action: @MainActor () -> Void
-   public init(title: String,iconName: String,action: @escaping () -> Void,confirmationPopup: ConfirmationPopup?,isDestructive: Bool)
+   public init(title: String,iconName: String,action: @escaping @MainActor () -> Void,confirmationPopup: ConfirmationPopup?,isDestructive: Bool)

 open class TwoStepMentionCommand: CommandHandler  
-   open func executeOnMessageSent(composerCommand: ComposerCommand,completion: @escaping (Error?) -> Void)
+   open func executeOnMessageSent(composerCommand: ComposerCommand,completion: @escaping @MainActor (Error?) -> Void)

- public struct MessageActionInfo  
+ public struct MessageActionInfo: Sendable  

 extension ChannelAction  
-   public static func defaultActions(for channel: ChatChannel,chatClient: ChatClient,onDismiss: @escaping () -> Void,onError: @escaping (Error) -> Void)-> [ChannelAction]
+   @MainActor public static func defaultActions(for channel: ChatChannel,chatClient: ChatClient,onDismiss: @escaping @MainActor () -> Void,onError: @escaping @MainActor (Error) -> Void)-> [ChannelAction]

- public struct CustomAttachment: Identifiable, Equatable  
+ public struct CustomAttachment: Identifiable, Equatable, Sendable  

Copy link

sonarqubecloud bot commented Oct 3, 2025

Quality Gate Failed Quality Gate failed

Failed conditions
65.3% Coverage on New Code (required ≥ 80%)

See analysis details on SonarQube Cloud

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
💥 Breaking Changes A PR that contains breaking changes
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants