diff --git a/CHANGELOG.md b/CHANGELOG.md index dc1a1d052..123e67fca 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,19 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ### 🔄 Changed +# [4.93.0](https://github.com/GetStream/stream-chat-swiftui/releases/tag/4.93.0) +_November 18, 2025_ + +### ✅ Added +- Expose `AddedVoiceRecordingsView` [#1049](https://github.com/GetStream/stream-chat-swiftui/pull/1049) +- Expose `FilePickerView.init(fileURLs:)` [#1049](https://github.com/GetStream/stream-chat-swiftui/pull/1049) +- Add `MessageComposerViewModel.updateAddedAssets()` [#1049](https://github.com/GetStream/stream-chat-swiftui/pull/1049) + +### 🐞 Fixed +- Fix `Throttler` crash in `ChatChannelViewModel.handleMessageAppear()` [#1050](https://github.com/GetStream/stream-chat-swiftui/pull/1050) +- Remove unnecessary channel query call when leaving the channel view in a mid-page [#1050](https://github.com/GetStream/stream-chat-swiftui/pull/1050) +- Fix crash when force unwrapping `messageDisplayInfo` in `ChatChannelView` [#1052](https://github.com/GetStream/stream-chat-swiftui/pull/1052) + # [4.92.0](https://github.com/GetStream/stream-chat-swiftui/releases/tag/4.92.0) _November 07, 2025_ diff --git a/Gemfile.lock b/Gemfile.lock index 300196b57..277f76f8d 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -211,8 +211,8 @@ GEM fastlane-plugin-stream_actions (0.3.101) xctest_list (= 1.2.1) fastlane-plugin-versioning (0.7.1) - fastlane-plugin-xcsize (1.1.0) - xcsize (= 1.1.0) + fastlane-plugin-xcsize (1.2.0) + xcsize (= 1.2.0) fastlane-sirp (1.0.0) sysrandom (~> 1.0) ffi (1.17.2) @@ -415,7 +415,7 @@ GEM rouge (~> 3.28.0) xcpretty-travis-formatter (1.0.1) xcpretty (~> 0.2, >= 0.0.7) - xcsize (1.1.0) + xcsize (1.2.0) commander (>= 4.6, < 6.0) xctest_list (1.2.1) @@ -432,7 +432,7 @@ DEPENDENCIES fastlane-plugin-sonarcloud_metric_kit fastlane-plugin-stream_actions (= 0.3.101) fastlane-plugin-versioning - fastlane-plugin-xcsize (= 1.1.0) + fastlane-plugin-xcsize (= 1.2.0) json lefthook plist diff --git a/Package.swift b/Package.swift index ddd1fb18e..28246de09 100644 --- a/Package.swift +++ b/Package.swift @@ -16,7 +16,7 @@ let package = Package( ) ], dependencies: [ - .package(url: "https://github.com/GetStream/stream-chat-swift.git", from: "4.92.0") + .package(url: "https://github.com/GetStream/stream-chat-swift.git", from: "4.93.0") ], targets: [ .target( diff --git a/Sources/StreamChatSwiftUI/ChatChannel/ChatChannelView.swift b/Sources/StreamChatSwiftUI/ChatChannel/ChatChannelView.swift index 17cb54766..1e4ee9c39 100644 --- a/Sources/StreamChatSwiftUI/ChatChannel/ChatChannelView.swift +++ b/Sources/StreamChatSwiftUI/ChatChannel/ChatChannelView.swift @@ -145,7 +145,7 @@ public struct ChatChannelView: View, KeyboardReadable { .opacity(0) // Fixes showing accessibility button shape } .overlay( - viewModel.reactionsShown ? + viewModel.currentSnapshot != nil && messageDisplayInfo != nil && viewModel.reactionsShown ? factory.makeReactionsOverlayView( channel: channel, currentSnapshot: viewModel.currentSnapshot!, diff --git a/Sources/StreamChatSwiftUI/ChatChannel/ChatChannelViewModel.swift b/Sources/StreamChatSwiftUI/ChatChannel/ChatChannelViewModel.swift index 5b40308e5..5e5d90c50 100644 --- a/Sources/StreamChatSwiftUI/ChatChannel/ChatChannelViewModel.swift +++ b/Sources/StreamChatSwiftUI/ChatChannel/ChatChannelViewModel.swift @@ -50,7 +50,7 @@ open class ChatChannelViewModel: ObservableObject, MessagesDataSource { private var channelName = "" private var onlineIndicatorShown = false private var lastReadMessageId: String? - var throttler = Throttler(interval: 3, broadcastLatestEvent: true) + var throttler = Throttler(interval: 3, broadcastLatestEvent: true, queue: .main) public var channelController: ChatChannelController public var messageController: ChatMessageController? @@ -833,14 +833,12 @@ open class ChatChannelViewModel: ObservableObject, MessagesDataSource { } deinit { + throttler.cancel() messageCachingUtils.clearCache() if messageController == nil { utils.channelControllerFactory.clearCurrentController() cleanupAudioPlayer() ImageCache.shared.trim(toCost: utils.messageListConfig.cacheSizeOnChatDismiss) - if !channelDataSource.hasLoadedAllNextMessages { - channelDataSource.loadFirstPage { _ in } - } } } } diff --git a/Sources/StreamChatSwiftUI/ChatChannel/Composer/FilePickerView.swift b/Sources/StreamChatSwiftUI/ChatChannel/Composer/FilePickerView.swift index 2604ef2a7..ced4647ed 100644 --- a/Sources/StreamChatSwiftUI/ChatChannel/Composer/FilePickerView.swift +++ b/Sources/StreamChatSwiftUI/ChatChannel/Composer/FilePickerView.swift @@ -9,6 +9,10 @@ import UniformTypeIdentifiers public struct FilePickerView: UIViewControllerRepresentable { @Injected(\.chatClient) var client @Binding var fileURLs: [URL] + + public init(fileURLs: Binding<[URL]>) { + self._fileURLs = fileURLs + } public func makeUIViewController(context: Context) -> UIDocumentPickerViewController { let picker = UIDocumentPickerViewController(forOpeningContentTypes: openingContentTypes) diff --git a/Sources/StreamChatSwiftUI/ChatChannel/Composer/MessageComposerViewModel.swift b/Sources/StreamChatSwiftUI/ChatChannel/Composer/MessageComposerViewModel.swift index 545b5a57d..813e7796e 100644 --- a/Sources/StreamChatSwiftUI/ChatChannel/Composer/MessageComposerViewModel.swift +++ b/Sources/StreamChatSwiftUI/ChatChannel/Composer/MessageComposerViewModel.swift @@ -874,6 +874,10 @@ open class MessageComposerViewModel: ObservableObject { return checkAttachmentSize(with: url) } + public func updateAddedAssets(_ assets: [AddedAsset]) { + addedAssets = assets + } + private func checkAttachmentSize(with url: URL?) -> Bool { guard let url = url else { return true } diff --git a/Sources/StreamChatSwiftUI/ChatChannel/Composer/VoiceRecording/AddedVoiceRecordingsView.swift b/Sources/StreamChatSwiftUI/ChatChannel/Composer/VoiceRecording/AddedVoiceRecordingsView.swift index e38726c58..88850d6a9 100644 --- a/Sources/StreamChatSwiftUI/ChatChannel/Composer/VoiceRecording/AddedVoiceRecordingsView.swift +++ b/Sources/StreamChatSwiftUI/ChatChannel/Composer/VoiceRecording/AddedVoiceRecordingsView.swift @@ -5,7 +5,7 @@ import StreamChat import SwiftUI -struct AddedVoiceRecordingsView: View { +public struct AddedVoiceRecordingsView: View { @Injected(\.colors) private var colors @Injected(\.utils) private var utils diff --git a/Sources/StreamChatSwiftUI/ChatChannel/MessageList/MessageListView.swift b/Sources/StreamChatSwiftUI/ChatChannel/MessageList/MessageListView.swift index 2bfe8a96b..c2c0e6d05 100644 --- a/Sources/StreamChatSwiftUI/ChatChannel/MessageList/MessageListView.swift +++ b/Sources/StreamChatSwiftUI/ChatChannel/MessageList/MessageListView.swift @@ -114,6 +114,49 @@ public struct MessageListView: View, KeyboardReadable { ) } } + + public init( + factory: Factory = DefaultViewFactory.shared, + channel: ChatChannel, + viewModel: ChatChannelViewModel, + onLongPress: @escaping (MessageDisplayInfo) -> Void = { _ in } + ) { + self.init( + factory: factory, + channel: channel, + messages: viewModel.messages, + messagesGroupingInfo: viewModel.messagesGroupingInfo, + scrolledId: Binding( + get: { viewModel.scrolledId }, + set: { viewModel.scrolledId = $0 } + ), + showScrollToLatestButton: Binding( + get: { viewModel.showScrollToLatestButton }, + set: { viewModel.showScrollToLatestButton = $0 } + ), + quotedMessage: Binding( + get: { viewModel.quotedMessage }, + set: { viewModel.quotedMessage = $0 } + ), + currentDateString: viewModel.currentDateString, + listId: viewModel.listId, + isMessageThread: viewModel.isMessageThread, + shouldShowTypingIndicator: viewModel.shouldShowTypingIndicator, + scrollPosition: Binding( + get: { viewModel.scrollPosition }, + set: { viewModel.scrollPosition = $0 } + ), + loadingNextMessages: viewModel.loadingNextMessages, + firstUnreadMessageId: Binding( + get: { viewModel.firstUnreadMessageId }, + set: { viewModel.firstUnreadMessageId = $0 } + ), + onMessageAppear: viewModel.handleMessageAppear(index:scrollDirection:), + onScrollToBottom: viewModel.scrollToLastMessage, + onLongPress: onLongPress, + onJumpToMessage: viewModel.jumpToMessage(messageId:) + ) + } public var body: some View { ZStack { diff --git a/Sources/StreamChatSwiftUI/Generated/SystemEnvironment+Version.swift b/Sources/StreamChatSwiftUI/Generated/SystemEnvironment+Version.swift index 7f2ac48c5..3265af9b8 100644 --- a/Sources/StreamChatSwiftUI/Generated/SystemEnvironment+Version.swift +++ b/Sources/StreamChatSwiftUI/Generated/SystemEnvironment+Version.swift @@ -7,5 +7,5 @@ import Foundation enum SystemEnvironment { /// A Stream Chat version. - public static let version: String = "4.92.0" + public static let version: String = "4.93.0" } diff --git a/Sources/StreamChatSwiftUI/Info.plist b/Sources/StreamChatSwiftUI/Info.plist index 6bc4b9c01..3e93a0a5f 100644 --- a/Sources/StreamChatSwiftUI/Info.plist +++ b/Sources/StreamChatSwiftUI/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString - 4.92.0 + 4.93.0 CFBundleVersion $(CURRENT_PROJECT_VERSION) NSPhotoLibraryUsageDescription diff --git a/StreamChatSwiftUI-XCFramework.podspec b/StreamChatSwiftUI-XCFramework.podspec index bef1bf4d7..0cf888058 100644 --- a/StreamChatSwiftUI-XCFramework.podspec +++ b/StreamChatSwiftUI-XCFramework.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |spec| spec.name = 'StreamChatSwiftUI-XCFramework' - spec.version = '4.92.0' + spec.version = '4.93.0' spec.summary = 'StreamChat SwiftUI Chat Components' spec.description = 'StreamChatSwiftUI SDK offers flexible SwiftUI components able to display data provided by StreamChat SDK.' @@ -19,7 +19,7 @@ Pod::Spec.new do |spec| spec.framework = 'Foundation', 'UIKit', 'SwiftUI' - spec.dependency 'StreamChat-XCFramework', '~> 4.92.0' + spec.dependency 'StreamChat-XCFramework', '~> 4.93.0' spec.cocoapods_version = '>= 1.11.0' end diff --git a/StreamChatSwiftUI.podspec b/StreamChatSwiftUI.podspec index 1f38e2e6c..5b25b08fd 100644 --- a/StreamChatSwiftUI.podspec +++ b/StreamChatSwiftUI.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |spec| spec.name = 'StreamChatSwiftUI' - spec.version = '4.92.0' + spec.version = '4.93.0' spec.summary = 'StreamChat SwiftUI Chat Components' spec.description = 'StreamChatSwiftUI SDK offers flexible SwiftUI components able to display data provided by StreamChat SDK.' @@ -19,5 +19,5 @@ Pod::Spec.new do |spec| spec.framework = 'Foundation', 'UIKit', 'SwiftUI' - spec.dependency 'StreamChat', '~> 4.92.0' + spec.dependency 'StreamChat', '~> 4.93.0' end diff --git a/StreamChatSwiftUI.xcodeproj/project.pbxproj b/StreamChatSwiftUI.xcodeproj/project.pbxproj index cb726deb8..9eb15a08d 100644 --- a/StreamChatSwiftUI.xcodeproj/project.pbxproj +++ b/StreamChatSwiftUI.xcodeproj/project.pbxproj @@ -3946,7 +3946,7 @@ repositoryURL = "https://github.com/GetStream/stream-chat-swift.git"; requirement = { kind = upToNextMajorVersion; - minimumVersion = 4.92.0; + minimumVersion = 4.93.0; }; }; E3A1C01A282BAC66002D1E26 /* XCRemoteSwiftPackageReference "sentry-cocoa" */ = { diff --git a/StreamChatSwiftUIArtifacts.json b/StreamChatSwiftUIArtifacts.json index 59343d470..af7772a8b 100644 --- a/StreamChatSwiftUIArtifacts.json +++ b/StreamChatSwiftUIArtifacts.json @@ -1 +1 @@ -{"4.40.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.40.0/StreamChatSwiftUI.zip","4.41.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.41.0/StreamChatSwiftUI.zip","4.42.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.42.0/StreamChatSwiftUI.zip","4.43.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.43.0/StreamChatSwiftUI.zip","4.44.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.44.0/StreamChatSwiftUI.zip","4.45.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.45.0/StreamChatSwiftUI.zip","4.46.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.46.0/StreamChatSwiftUI.zip","4.47.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.47.0/StreamChatSwiftUI.zip","4.47.1":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.47.1/StreamChatSwiftUI.zip","4.48.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.48.0/StreamChatSwiftUI.zip","4.49.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.49.0/StreamChatSwiftUI.zip","4.50.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.50.0/StreamChatSwiftUI.zip","4.50.1":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.50.1/StreamChatSwiftUI.zip","4.51.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.51.0/StreamChatSwiftUI.zip","4.52.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.52.0/StreamChatSwiftUI.zip","4.53.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.53.0/StreamChatSwiftUI.zip","4.54.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.54.0/StreamChatSwiftUI.zip","4.55.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.55.0/StreamChatSwiftUI.zip","4.56.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.56.0/StreamChatSwiftUI.zip","4.57.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.57.0/StreamChatSwiftUI.zip","4.58.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.58.0/StreamChatSwiftUI.zip","4.59.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.59.0/StreamChatSwiftUI.zip","4.60.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.60.0/StreamChatSwiftUI.zip","4.61.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.61.0/StreamChatSwiftUI.zip","4.62.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.62.0/StreamChatSwiftUI.zip","4.63.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.63.0/StreamChatSwiftUI.zip","4.64.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.64.0/StreamChatSwiftUI.zip","4.65.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.65.0/StreamChatSwiftUI.zip","4.66.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.66.0/StreamChatSwiftUI.zip","4.67.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.67.0/StreamChatSwiftUI.zip","4.68.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.68.0/StreamChatSwiftUI.zip","4.69.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.69.0/StreamChatSwiftUI.zip","4.70.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.70.0/StreamChatSwiftUI.zip","4.71.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.71.0/StreamChatSwiftUI.zip","4.72.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.72.0/StreamChatSwiftUI.zip","4.73.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.73.0/StreamChatSwiftUI.zip","4.74.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.74.0/StreamChatSwiftUI.zip","4.75.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.75.0/StreamChatSwiftUI.zip","4.76.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.76.0/StreamChatSwiftUI.zip","4.77.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.77.0/StreamChatSwiftUI.zip","4.78.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.78.0/StreamChatSwiftUI.zip","4.79.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.79.0/StreamChatSwiftUI.zip","4.79.1":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.79.1/StreamChatSwiftUI.zip","4.80.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.80.0/StreamChatSwiftUI.zip","4.81.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.81.0/StreamChatSwiftUI.zip","4.82.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.82.0/StreamChatSwiftUI.zip","4.83.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.83.0/StreamChatSwiftUI.zip","4.84.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.84.0/StreamChatSwiftUI.zip","4.85.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.85.0/StreamChatSwiftUI.zip","4.86.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.86.0/StreamChatSwiftUI.zip","4.87.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.87.0/StreamChatSwiftUI.zip","4.88.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.88.0/StreamChatSwiftUI.zip","4.89.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.89.0/StreamChatSwiftUI.zip","4.89.1":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.89.1/StreamChatSwiftUI.zip","4.90.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.90.0/StreamChatSwiftUI.zip","4.91.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.91.0/StreamChatSwiftUI.zip","4.92.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.92.0/StreamChatSwiftUI.zip"} \ No newline at end of file +{"4.40.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.40.0/StreamChatSwiftUI.zip","4.41.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.41.0/StreamChatSwiftUI.zip","4.42.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.42.0/StreamChatSwiftUI.zip","4.43.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.43.0/StreamChatSwiftUI.zip","4.44.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.44.0/StreamChatSwiftUI.zip","4.45.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.45.0/StreamChatSwiftUI.zip","4.46.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.46.0/StreamChatSwiftUI.zip","4.47.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.47.0/StreamChatSwiftUI.zip","4.47.1":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.47.1/StreamChatSwiftUI.zip","4.48.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.48.0/StreamChatSwiftUI.zip","4.49.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.49.0/StreamChatSwiftUI.zip","4.50.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.50.0/StreamChatSwiftUI.zip","4.50.1":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.50.1/StreamChatSwiftUI.zip","4.51.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.51.0/StreamChatSwiftUI.zip","4.52.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.52.0/StreamChatSwiftUI.zip","4.53.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.53.0/StreamChatSwiftUI.zip","4.54.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.54.0/StreamChatSwiftUI.zip","4.55.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.55.0/StreamChatSwiftUI.zip","4.56.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.56.0/StreamChatSwiftUI.zip","4.57.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.57.0/StreamChatSwiftUI.zip","4.58.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.58.0/StreamChatSwiftUI.zip","4.59.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.59.0/StreamChatSwiftUI.zip","4.60.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.60.0/StreamChatSwiftUI.zip","4.61.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.61.0/StreamChatSwiftUI.zip","4.62.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.62.0/StreamChatSwiftUI.zip","4.63.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.63.0/StreamChatSwiftUI.zip","4.64.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.64.0/StreamChatSwiftUI.zip","4.65.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.65.0/StreamChatSwiftUI.zip","4.66.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.66.0/StreamChatSwiftUI.zip","4.67.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.67.0/StreamChatSwiftUI.zip","4.68.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.68.0/StreamChatSwiftUI.zip","4.69.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.69.0/StreamChatSwiftUI.zip","4.70.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.70.0/StreamChatSwiftUI.zip","4.71.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.71.0/StreamChatSwiftUI.zip","4.72.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.72.0/StreamChatSwiftUI.zip","4.73.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.73.0/StreamChatSwiftUI.zip","4.74.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.74.0/StreamChatSwiftUI.zip","4.75.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.75.0/StreamChatSwiftUI.zip","4.76.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.76.0/StreamChatSwiftUI.zip","4.77.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.77.0/StreamChatSwiftUI.zip","4.78.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.78.0/StreamChatSwiftUI.zip","4.79.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.79.0/StreamChatSwiftUI.zip","4.79.1":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.79.1/StreamChatSwiftUI.zip","4.80.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.80.0/StreamChatSwiftUI.zip","4.81.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.81.0/StreamChatSwiftUI.zip","4.82.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.82.0/StreamChatSwiftUI.zip","4.83.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.83.0/StreamChatSwiftUI.zip","4.84.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.84.0/StreamChatSwiftUI.zip","4.85.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.85.0/StreamChatSwiftUI.zip","4.86.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.86.0/StreamChatSwiftUI.zip","4.87.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.87.0/StreamChatSwiftUI.zip","4.88.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.88.0/StreamChatSwiftUI.zip","4.89.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.89.0/StreamChatSwiftUI.zip","4.89.1":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.89.1/StreamChatSwiftUI.zip","4.90.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.90.0/StreamChatSwiftUI.zip","4.91.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.91.0/StreamChatSwiftUI.zip","4.92.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.92.0/StreamChatSwiftUI.zip","4.93.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.93.0/StreamChatSwiftUI.zip"} \ No newline at end of file diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChatChannelViewModel_Tests.swift b/StreamChatSwiftUITests/Tests/ChatChannel/ChatChannelViewModel_Tests.swift index ace127d72..8ac70038e 100644 --- a/StreamChatSwiftUITests/Tests/ChatChannel/ChatChannelViewModel_Tests.swift +++ b/StreamChatSwiftUITests/Tests/ChatChannel/ChatChannelViewModel_Tests.swift @@ -772,6 +772,31 @@ class ChatChannelViewModel_Tests: StreamChatTestCase { XCTAssertEqual(0, channelController.markReadCallCount) } + func test_chatChannelVM_handleMessageAppear_doesNotCrashWhenDeallocated() { + let message = ChatMessage.mock() + let channelController = makeChannelController(messages: [message]) + channelController.hasLoadedAllNextMessages_mock = nil + channelController.channel_mock = .mock( + cid: .unique, + unreadCount: ChannelUnreadCount(messages: 1, mentions: 0) + ) + + for _ in 0..<1000 { + autoreleasepool { + let viewModel = ChatChannelViewModel(channelController: channelController) + viewModel.handleMessageAppear(index: 0, scrollDirection: .down) + viewModel.handleMessageAppear(index: 0, scrollDirection: .down) + viewModel.handleMessageAppear(index: 0, scrollDirection: .down) + viewModel.handleMessageAppear(index: 0, scrollDirection: .down) + viewModel.handleMessageAppear(index: 0, scrollDirection: .down) + viewModel.handleMessageAppear(index: 0, scrollDirection: .down) + } + } + + // Then - Should not crash + XCTAssert(true) + } + // MARK: - highlightMessage Tests func test_highlightMessage_highlightsWhenSkipHighlightMessageIdIsNotSet() { diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChatChannelView_Tests.swift b/StreamChatSwiftUITests/Tests/ChatChannel/ChatChannelView_Tests.swift index 8ee7f36e7..530106b72 100644 --- a/StreamChatSwiftUITests/Tests/ChatChannel/ChatChannelView_Tests.swift +++ b/StreamChatSwiftUITests/Tests/ChatChannel/ChatChannelView_Tests.swift @@ -167,4 +167,76 @@ class ChatChannelView_Tests: StreamChatTestCase { // Then assertSnapshot(matching: view, as: .image(perceptualPrecision: precision)) } + + // MARK: - Reactions Overlay Tests + + func test_chatChannelView_doesNotCrash_whenCurrentSnapshotIsNil_andReactionsShownIsTrue() { + // Given + let controller = ChatChannelController_Mock.mock( + channelQuery: .init(cid: .unique), + channelListQuery: nil, + client: chatClient + ) + let mockChannel = ChatChannel.mock(cid: .unique, name: "Test channel") + let message = ChatMessage.mock( + id: .unique, + cid: mockChannel.cid, + text: "Test message", + author: .mock(id: .unique, name: "User") + ) + controller.simulateInitial(channel: mockChannel, messages: [message], state: .remoteDataFetched) + + let viewModel = ChatChannelViewModel(channelController: controller) + + // When + viewModel.currentSnapshot = nil + viewModel.reactionsShown = true + + let view = ChatChannelView( + viewFactory: DefaultViewFactory.shared, + viewModel: viewModel, + channelController: controller + ) + + // Then - Should not crash when rendering + let hostingController = UIHostingController(rootView: view) + XCTAssertNotNil(hostingController.view) + XCTAssertNil(viewModel.currentSnapshot) + XCTAssertTrue(viewModel.reactionsShown) + } + + func test_chatChannelView_doesNotCrash_whenMessageDisplayInfoIsNil_andReactionsShownIsTrue() { + // Given + let controller = ChatChannelController_Mock.mock( + channelQuery: .init(cid: .unique), + channelListQuery: nil, + client: chatClient + ) + let mockChannel = ChatChannel.mock(cid: .unique, name: "Test channel") + let message = ChatMessage.mock( + id: .unique, + cid: mockChannel.cid, + text: "Test message", + author: .mock(id: .unique, name: "User") + ) + controller.simulateInitial(channel: mockChannel, messages: [message], state: .remoteDataFetched) + + let viewModel = ChatChannelViewModel(channelController: controller) + + // When + viewModel.showReactionOverlay(for: AnyView(EmptyView())) + // messageDisplayInfo remains nil (not set) + + let view = ChatChannelView( + viewFactory: DefaultViewFactory.shared, + viewModel: viewModel, + channelController: controller + ) + + // Then - Should not crash when rendering + let hostingController = UIHostingController(rootView: view) + XCTAssertNotNil(hostingController.view) + XCTAssertNotNil(viewModel.currentSnapshot) + XCTAssertTrue(viewModel.reactionsShown) + } } diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/MessageListView_Tests.swift b/StreamChatSwiftUITests/Tests/ChatChannel/MessageListView_Tests.swift index d11c2fc42..b322c8bb0 100644 --- a/StreamChatSwiftUITests/Tests/ChatChannel/MessageListView_Tests.swift +++ b/StreamChatSwiftUITests/Tests/ChatChannel/MessageListView_Tests.swift @@ -98,6 +98,40 @@ class MessageListView_Tests: StreamChatTestCase { assertSnapshot(matching: view, as: .image(perceptualPrecision: precision)) } + // MARK: - Init with ChatChannelViewModel snapshot tests + + func test_messageListView_viewModelInit_withReactions() { + // Given + let channel = ChatChannel.mockDMChannel(config: .init(reactionsEnabled: true)) + let view = makeMessageListViewWithViewModel(channel: channel, messages: [.mock(id: .unique, cid: channel.cid, text: "Hello", author: .mock(id: .unique), reactionScores: [MessageReactionType(rawValue: "like"): 1])]) + .applyDefaultSize() + + // Then + assertSnapshot(matching: view, as: .image(perceptualPrecision: precision)) + } + + func test_messageListView_viewModelInit_noReactions() { + // Given + let channel = ChatChannel.mockDMChannel(config: .init(reactionsEnabled: false)) + let view = makeMessageListViewWithViewModel(channel: channel, messages: [.mock(id: .unique, cid: channel.cid, text: "Hello", author: .mock(id: .unique))]) + .applyDefaultSize() + + // Then + assertSnapshot(matching: view, as: .image(perceptualPrecision: precision)) + } + + func test_messageListView_viewModelInit_unreadIndicator() { + // Given + var channel = ChatChannel.mockDMChannel() + // Set unread count on the channel + channel = ChatChannel.mockDMChannel(unreadCount: .mock(messages: 2)) + let view = makeMessageListViewWithViewModel(channel: channel, messages: [.mock(id: .unique, cid: channel.cid, text: "Unread 1", author: .mock(id: .unique))]) + .applyDefaultSize() + + // Then + assertSnapshot(matching: view, as: .image(perceptualPrecision: precision)) + } + // MARK: - private func makeMessageListView( @@ -138,4 +172,26 @@ class MessageListView_Tests: StreamChatTestCase { return messageListView } + + private func makeMessageListViewWithViewModel( + channel: ChatChannel, + messages: [ChatMessage] + ) -> MessageListView { + // Create a mock channel controller seeded with channel and messages + let controller = ChatChannelTestHelpers.makeChannelController( + chatClient: chatClient, + chatChannel: channel, + messages: messages + ) + + // Build the view model + let viewModel = ChatChannelViewModel(channelController: controller) + + // Return the view using the new initializer + return MessageListView( + factory: DefaultViewFactory.shared, + channel: channel, + viewModel: viewModel + ) + } } diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_messageListView_viewModelInit_noReactions.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_messageListView_viewModelInit_noReactions.1.png new file mode 100644 index 000000000..7ffa0e3c0 Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_messageListView_viewModelInit_noReactions.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_messageListView_viewModelInit_unreadIndicator.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_messageListView_viewModelInit_unreadIndicator.1.png new file mode 100644 index 000000000..2d864f294 Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_messageListView_viewModelInit_unreadIndicator.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_messageListView_viewModelInit_withReactions.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_messageListView_viewModelInit_withReactions.1.png new file mode 100644 index 000000000..f5c834eb6 Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_messageListView_viewModelInit_withReactions.1.png differ diff --git a/fastlane/Pluginfile b/fastlane/Pluginfile index 772a05733..cda526588 100644 --- a/fastlane/Pluginfile +++ b/fastlane/Pluginfile @@ -6,4 +6,4 @@ gem 'fastlane-plugin-versioning' gem 'fastlane-plugin-sonarcloud_metric_kit' gem 'fastlane-plugin-create_xcframework' gem 'fastlane-plugin-stream_actions', '0.3.101' -gem 'fastlane-plugin-xcsize', '1.1.0' +gem 'fastlane-plugin-xcsize', '1.2.0'