diff --git a/CHANGELOG.md b/CHANGELOG.md index 890d06db6..ab8faa467 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.77.0](https://github.com/GetStream/stream-chat-swiftui/releases/tag/4.77.0) +_April 10, 2025_ + +### ✅ Added +- Allow pasting images to the composer [#797](https://github.com/GetStream/stream-chat-swiftui/pull/797) +- Add `ChatChannelListViewModel.setChannelAlertType` for setting the alert type [#801](https://github.com/GetStream/stream-chat-swiftui/pull/801) +### 🐞 Fixed +- Fix allowing to send Polls when the current user does not have the capability [#798](https://github.com/GetStream/stream-chat-swiftui/pull/798) +- Fix showing a double error indicator when sending attachments without any text [#799](https://github.com/GetStream/stream-chat-swiftui/pull/799) +- Fix showing read indicator when message failed to be sent [#799](https://github.com/GetStream/stream-chat-swiftui/pull/799) +- Fix not showing sending indicator when message is in sending state [#799](https://github.com/GetStream/stream-chat-swiftui/pull/799) +- Fix empty accessibility button shapes shown in navigation link views [#800](https://github.com/GetStream/stream-chat-swiftui/pull/800) + # [4.76.0](https://github.com/GetStream/stream-chat-swiftui/releases/tag/4.76.0) _March 31, 2025_ diff --git a/DemoAppSwiftUI/ChannelHeader/CustomChannelHeader.swift b/DemoAppSwiftUI/ChannelHeader/CustomChannelHeader.swift index b941bbe8c..c91c87874 100644 --- a/DemoAppSwiftUI/ChannelHeader/CustomChannelHeader.swift +++ b/DemoAppSwiftUI/ChannelHeader/CustomChannelHeader.swift @@ -78,6 +78,7 @@ struct CustomChannelModifier: ChannelListHeaderViewModifier { } label: { EmptyView() } + .opacity(0) // Fixes showing accessibility button shape NavigationLink(isActive: $isNewChatShown) { NewChatView(isNewChatShown: $isNewChatShown) @@ -85,6 +86,7 @@ struct CustomChannelModifier: ChannelListHeaderViewModifier { EmptyView() } .isDetailLink(UIDevice.current.userInterfaceIdiom == .pad) + .opacity(0) // Fixes showing accessibility button shape .alert(isPresented: $logoutAlertShown) { Alert( title: Text("Sign out"), diff --git a/DemoAppSwiftUI/PinChannelHelpers.swift b/DemoAppSwiftUI/PinChannelHelpers.swift index 495d1bf28..434bb46e1 100644 --- a/DemoAppSwiftUI/PinChannelHelpers.swift +++ b/DemoAppSwiftUI/PinChannelHelpers.swift @@ -57,7 +57,8 @@ struct DemoAppChatChannelListItem: View { currentUserId: chatClient.currentUserId, message: channel.latestMessages.first ), - showReadCount: false + showReadCount: false, + localState: channel.latestMessages.first?.localState ) } SubtitleText(text: injectedChannelInfo?.timestamp ?? channel.timestampText) @@ -168,6 +169,7 @@ struct DemoAppChatChannelNavigatableListItem: View { } label: { EmptyView() } + .opacity(0) // Fixes showing accessibility button shape } } diff --git a/Package.swift b/Package.swift index 74d46e699..bdcc59f11 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.76.0"), + .package(url: "https://github.com/GetStream/stream-chat-swift.git", from: "4.77.0"), ], targets: [ .target( diff --git a/Sources/StreamChatSwiftUI/ChatChannel/ChatChannelView.swift b/Sources/StreamChatSwiftUI/ChatChannel/ChatChannelView.swift index 4013d866c..a0e866366 100644 --- a/Sources/StreamChatSwiftUI/ChatChannel/ChatChannelView.swift +++ b/Sources/StreamChatSwiftUI/ChatChannel/ChatChannelView.swift @@ -134,6 +134,7 @@ public struct ChatChannelView: View, KeyboardReadable { } label: { EmptyView() } + .opacity(0) // Fixes showing accessibility button shape } .accentColor(colors.tintColor) .overlay( diff --git a/Sources/StreamChatSwiftUI/ChatChannel/Composer/AttachmentPickerView.swift b/Sources/StreamChatSwiftUI/ChatChannel/Composer/AttachmentPickerView.swift index 2b1545b53..173c99bfe 100644 --- a/Sources/StreamChatSwiftUI/ChatChannel/Composer/AttachmentPickerView.swift +++ b/Sources/StreamChatSwiftUI/ChatChannel/Composer/AttachmentPickerView.swift @@ -170,7 +170,7 @@ public struct AttachmentSourcePickerView: View { ) .accessibilityIdentifier("attachmentPickerCamera") - if viewModel.channelController.channel?.config.pollsEnabled == true && viewModel.messageController == nil { + if viewModel.canSendPoll { AttachmentPickerButton( icon: images.attachmentPickerPolls, pickerType: .polls, diff --git a/Sources/StreamChatSwiftUI/ChatChannel/Composer/ComposerTextInputView.swift b/Sources/StreamChatSwiftUI/ChatChannel/Composer/ComposerTextInputView.swift index 48fea75a0..f1f0ce5c7 100644 --- a/Sources/StreamChatSwiftUI/ChatChannel/Composer/ComposerTextInputView.swift +++ b/Sources/StreamChatSwiftUI/ChatChannel/Composer/ComposerTextInputView.swift @@ -7,7 +7,7 @@ import UIKit /// SwiftUI wrapper for a text field with multiple rows. struct ComposerTextInputView: UIViewRepresentable { - + @EnvironmentObject var composerViewModel: MessageComposerViewModel @Injected(\.utils) private var utils @Binding var text: String @@ -33,6 +33,9 @@ struct ComposerTextInputView: UIViewRepresentable { inputTextView.placeholderLabel.text = placeholder inputTextView.contentInsetAdjustmentBehavior = .never inputTextView.setContentCompressionResistancePriority(.streamLow, for: .horizontal) + inputTextView.onImagePasted = { + composerViewModel.imagePasted($0) + } if utils.messageListConfig.becomesFirstResponderOnOpen { inputTextView.becomeFirstResponder() diff --git a/Sources/StreamChatSwiftUI/ChatChannel/Composer/MessageComposerView.swift b/Sources/StreamChatSwiftUI/ChatChannel/Composer/MessageComposerView.swift index 694a84d5a..591a6847a 100644 --- a/Sources/StreamChatSwiftUI/ChatChannel/Composer/MessageComposerView.swift +++ b/Sources/StreamChatSwiftUI/ChatChannel/Composer/MessageComposerView.swift @@ -374,6 +374,7 @@ public struct ComposerInputView: View, KeyboardReadable { maxMessageLength: maxMessageLength, currentHeight: textFieldHeight ) + .environmentObject(viewModel) .accessibilityIdentifier("ComposerTextInputView") .accessibilityElement(children: .contain) .frame(height: textFieldHeight) diff --git a/Sources/StreamChatSwiftUI/ChatChannel/Composer/MessageComposerViewModel.swift b/Sources/StreamChatSwiftUI/ChatChannel/Composer/MessageComposerViewModel.swift index 3d80d3e13..b6ad2af13 100644 --- a/Sources/StreamChatSwiftUI/ChatChannel/Composer/MessageComposerViewModel.swift +++ b/Sources/StreamChatSwiftUI/ChatChannel/Composer/MessageComposerViewModel.swift @@ -183,7 +183,13 @@ open class MessageComposerViewModel: ObservableObject { public var quotedMessage: Binding? public var waveformTargetSamples: Int = 100 public internal(set) var pendingAudioRecording: AddedVoiceRecording? - + + public var canSendPoll: Bool { + channelController.channel?.config.pollsEnabled == true + && channelController.channel?.canSendPoll == true + && messageController == nil + } + internal lazy var audioRecorder: AudioRecording = { let audioRecorder = utils.audioRecorder audioRecorder.subscribe(self) @@ -510,6 +516,20 @@ open class MessageComposerViewModel: ObservableObject { addedAssets = images } + public func imagePasted(_ image: UIImage) { + guard let imageURL = try? image.saveAsJpgToTemporaryUrl() else { + log.error("Failed to write image to local temporary file") + return + } + let addedImage = AddedAsset( + image: image, + id: UUID().uuidString, + url: imageURL, + type: .image + ) + addedAssets.append(addedImage) + } + public func removeAttachment(with id: String) { if id.isURL, let url = URL(string: id) { var urls = [URL]() diff --git a/Sources/StreamChatSwiftUI/ChatChannel/MessageList/MessageContainerView.swift b/Sources/StreamChatSwiftUI/ChatChannel/MessageList/MessageContainerView.swift index 8e517c02d..21ae47c17 100644 --- a/Sources/StreamChatSwiftUI/ChatChannel/MessageList/MessageContainerView.swift +++ b/Sources/StreamChatSwiftUI/ChatChannel/MessageList/MessageContainerView.swift @@ -106,7 +106,8 @@ public struct MessageContainerView: View { ) : nil - (message.localState == .sendingFailed || message.isBounced) ? SendFailureIndicator() : nil + ((message.localState == .sendingFailed || message.isBounced) && !message.text.isEmpty) ? + SendFailureIndicator() : nil } ) .background( diff --git a/Sources/StreamChatSwiftUI/ChatChannel/MessageList/MessageListHelperViews.swift b/Sources/StreamChatSwiftUI/ChatChannel/MessageList/MessageListHelperViews.swift index 675a83adb..03f6a8d99 100644 --- a/Sources/StreamChatSwiftUI/ChatChannel/MessageList/MessageListHelperViews.swift +++ b/Sources/StreamChatSwiftUI/ChatChannel/MessageList/MessageListHelperViews.swift @@ -124,6 +124,7 @@ public struct MessageReadIndicatorView: View { .customizable() .foregroundColor(!readUsers.isEmpty ? colors.tintColor : Color(colors.textLowEmphasis)) .frame(height: 16) + .opacity(localState == .sendingFailed ? 0.0 : 1) .accessibilityLabel( Text( readUsers.isEmpty ? L10n.Message.ReadStatus.seenByNoOne : L10n.Message.ReadStatus.seenByOthers @@ -136,7 +137,12 @@ public struct MessageReadIndicatorView: View { } private var image: UIImage { - !readUsers.isEmpty ? images.readByAll : (localState == .pendingSend ? images.messageReceiptSending : images.messageSent) + !readUsers.isEmpty ? images.readByAll : (isMessageSending ? images.messageReceiptSending : images.messageSent) + } + + private var isMessageSending: Bool { + localState == .sending + || localState == .pendingSend } } diff --git a/Sources/StreamChatSwiftUI/ChatChannelList/ChatChannelListViewModel.swift b/Sources/StreamChatSwiftUI/ChatChannelList/ChatChannelListViewModel.swift index 5073afe48..f2017faa5 100644 --- a/Sources/StreamChatSwiftUI/ChatChannelList/ChatChannelListViewModel.swift +++ b/Sources/StreamChatSwiftUI/ChatChannelList/ChatChannelListViewModel.swift @@ -202,7 +202,7 @@ open class ChatChannelListViewModel: ObservableObject, ChatChannelListController } public func onDeleteTapped(channel: ChatChannel) { - channelAlertType = .deleteChannel(channel) + setChannelAlertType(.deleteChannel(channel)) } public func onMoreTapped(channel: ChatChannel) { @@ -217,13 +217,17 @@ open class ChatChannelListViewModel: ObservableObject, ChatChannelListController controller.deleteChannel { [weak self] error in if error != nil { // handle error - self?.channelAlertType = .error + self?.setChannelAlertType(.error) } } } open func showErrorPopup(_ error: Error?) { - channelAlertType = .error + setChannelAlertType(.error) + } + + open func setChannelAlertType(_ channelAlertType: ChannelAlertType) { + self.channelAlertType = channelAlertType } // MARK: - ChatChannelListControllerDelegate @@ -328,7 +332,7 @@ open class ChatChannelListViewModel: ObservableObject, ChatChannelListController self.loading = false if error != nil { // handle error - self.channelAlertType = .error + self.setChannelAlertType(.error) } else { // access channels self.updateChannels() diff --git a/Sources/StreamChatSwiftUI/ChatChannelList/ChatChannelNavigatableListItem.swift b/Sources/StreamChatSwiftUI/ChatChannelList/ChatChannelNavigatableListItem.swift index 105c029bc..38289155d 100644 --- a/Sources/StreamChatSwiftUI/ChatChannelList/ChatChannelNavigatableListItem.swift +++ b/Sources/StreamChatSwiftUI/ChatChannelList/ChatChannelNavigatableListItem.swift @@ -61,6 +61,7 @@ public struct ChatChannelNavigatableListItem: View { } label: { EmptyView() } + .opacity(0) // Fixes showing accessibility button shape } } } diff --git a/Sources/StreamChatSwiftUI/ChatThreadList/ChatThreadListNavigatableItem.swift b/Sources/StreamChatSwiftUI/ChatThreadList/ChatThreadListNavigatableItem.swift index 07d80cd9e..770684172 100644 --- a/Sources/StreamChatSwiftUI/ChatThreadList/ChatThreadListNavigatableItem.swift +++ b/Sources/StreamChatSwiftUI/ChatThreadList/ChatThreadListNavigatableItem.swift @@ -44,6 +44,7 @@ public struct ChatThreadListNavigatableItemCFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString - 4.76.0 + 4.77.0 CFBundleVersion $(CURRENT_PROJECT_VERSION) NSPhotoLibraryUsageDescription diff --git a/Sources/StreamChatSwiftUI/Utils/Common/InputTextView.swift b/Sources/StreamChatSwiftUI/Utils/Common/InputTextView.swift index d12a6edb8..daa44079d 100644 --- a/Sources/StreamChatSwiftUI/Utils/Common/InputTextView.swift +++ b/Sources/StreamChatSwiftUI/Utils/Common/InputTextView.swift @@ -52,6 +52,8 @@ class InputTextView: UITextView, AccessibilityView { } } } + + var onImagePasted: ((UIImage) -> Void)? override open func didMoveToSuperview() { super.didMoveToSuperview() @@ -143,9 +145,22 @@ class InputTextView: UITextView, AccessibilityView { override open func paste(_ sender: Any?) { super.paste(sender) + if let pastedImage = UIPasteboard.general.image, + let onImagePasted { + onImagePasted(pastedImage) + return + } handleTextChange() DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) { [weak self] in self?.scrollToBottom() } } + + override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool { + if action == #selector(paste(_:)) && onImagePasted != nil && UIPasteboard.general.image != nil { + return true + } else { + return super.canPerformAction(action, withSender: sender) + } + } } diff --git a/StreamChatSwiftUI-XCFramework.podspec b/StreamChatSwiftUI-XCFramework.podspec index b0de44b88..ec4507e72 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.76.0' + spec.version = '4.77.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.76.0' + spec.dependency 'StreamChat-XCFramework', '~> 4.77.0' spec.cocoapods_version = '>= 1.11.0' end diff --git a/StreamChatSwiftUI.podspec b/StreamChatSwiftUI.podspec index 2e3b4ce28..faa018d68 100644 --- a/StreamChatSwiftUI.podspec +++ b/StreamChatSwiftUI.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |spec| spec.name = 'StreamChatSwiftUI' - spec.version = '4.76.0' + spec.version = '4.77.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.76.0' + spec.dependency 'StreamChat', '~> 4.77.0' end diff --git a/StreamChatSwiftUI.xcodeproj/project.pbxproj b/StreamChatSwiftUI.xcodeproj/project.pbxproj index 4f1fd17e3..7749b5609 100644 --- a/StreamChatSwiftUI.xcodeproj/project.pbxproj +++ b/StreamChatSwiftUI.xcodeproj/project.pbxproj @@ -3880,7 +3880,7 @@ repositoryURL = "https://github.com/GetStream/stream-chat-swift.git"; requirement = { kind = upToNextMajorVersion; - minimumVersion = 4.76.0; + minimumVersion = 4.77.0; }; }; E3A1C01A282BAC66002D1E26 /* XCRemoteSwiftPackageReference "sentry-cocoa" */ = { diff --git a/StreamChatSwiftUIArtifacts.json b/StreamChatSwiftUIArtifacts.json index b2621f37f..fc04839db 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"} \ 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"} \ No newline at end of file diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChatChannelTestHelpers.swift b/StreamChatSwiftUITests/Tests/ChatChannel/ChatChannelTestHelpers.swift index c2bb39f05..86fe29410 100644 --- a/StreamChatSwiftUITests/Tests/ChatChannel/ChatChannelTestHelpers.swift +++ b/StreamChatSwiftUITests/Tests/ChatChannel/ChatChannelTestHelpers.swift @@ -70,6 +70,27 @@ class ChatChannelTestHelpers { return imageAttachments }() + static func imageAttachment(state: LocalAttachmentState) -> AnyChatMessageAttachment { + let attachmentFile = AttachmentFile(type: .png, size: 0, mimeType: "image/png") + let uploadingState = AttachmentUploadingState( + localFileURL: testURL, + state: state, + file: attachmentFile + ) + return ChatMessageImageAttachment( + id: .unique, + type: .image, + payload: ImageAttachmentPayload( + title: "test", + imageRemoteURL: testURL, + extraData: [:] + ), + downloadingState: nil, + uploadingState: uploadingState + ) + .asAnyAttachment + } + static var giphyAttachments: [AnyChatMessageAttachment] = { let attachmentFile = AttachmentFile(type: .gif, size: 0, mimeType: "image/gif") let uploadingState = AttachmentUploadingState( diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/MessageComposerViewModel_Tests.swift b/StreamChatSwiftUITests/Tests/ChatChannel/MessageComposerViewModel_Tests.swift index a5166a541..fc8501058 100644 --- a/StreamChatSwiftUITests/Tests/ChatChannel/MessageComposerViewModel_Tests.swift +++ b/StreamChatSwiftUITests/Tests/ChatChannel/MessageComposerViewModel_Tests.swift @@ -573,7 +573,92 @@ class MessageComposerViewModel_Tests: StreamChatTestCase { // Then XCTAssert(viewModel.mentionedUsers.isEmpty) } - + + func test_messageComposerVM_canSendPoll() { + // Given + let channelController = makeChannelController() + let viewModel = MessageComposerViewModel( + channelController: channelController, + messageController: nil + ) + + // When + let channelConfig = ChannelConfig(pollsEnabled: true) + channelController.channel_mock = .mock( + cid: .unique, + config: channelConfig, + ownCapabilities: [.sendPoll] + ) + + // Then + XCTAssertTrue(viewModel.canSendPoll) + } + + func test_messageComposerVM_canSendPoll_whenDoesNotHaveCapability() { + // Given + let channelController = makeChannelController() + let viewModel = MessageComposerViewModel( + channelController: channelController, + messageController: nil + ) + + // When + let channelConfig = ChannelConfig(pollsEnabled: true) + channelController.channel_mock = .mock( + cid: .unique, + config: channelConfig, + ownCapabilities: [.banChannelMembers] + ) + + // Then + XCTAssertFalse(viewModel.canSendPoll) + } + + func test_messageComposerVM_canSendPoll_whenNotEnabled() { + // Given + let channelController = makeChannelController() + let viewModel = MessageComposerViewModel( + channelController: channelController, + messageController: nil + ) + + // When + let channelConfig = ChannelConfig(pollsEnabled: false) + channelController.channel_mock = .mock( + cid: .unique, + config: channelConfig, + ownCapabilities: [.sendPoll] + ) + + // Then + XCTAssertFalse(viewModel.canSendPoll) + } + + func test_messageComposerVM_canSendPoll_whenInsideThread() { + // Given + let channelController = makeChannelController() + let messageController = ChatMessageControllerSUI_Mock.mock( + chatClient: chatClient, + cid: .unique, + messageId: .unique + ) + let viewModel = MessageComposerViewModel( + channelController: channelController, + messageController: messageController + ) + + // When + let channelConfig = ChannelConfig(pollsEnabled: true) + channelController.channel_mock = .mock( + cid: .unique, + config: channelConfig, + ownCapabilities: [.sendPoll] + ) + + // Then + XCTAssertFalse(viewModel.canSendPoll) + } + func test_addedAsset_extraData() { // Given let image = UIImage(systemName: "person")! diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/MessageContainerView_Tests.swift b/StreamChatSwiftUITests/Tests/ChatChannel/MessageContainerView_Tests.swift index 8fd705a8d..21a1cdb7f 100644 --- a/StreamChatSwiftUITests/Tests/ChatChannel/MessageContainerView_Tests.swift +++ b/StreamChatSwiftUITests/Tests/ChatChannel/MessageContainerView_Tests.swift @@ -261,7 +261,43 @@ class MessageContainerView_Tests: StreamChatTestCase { // Then assertSnapshot(matching: view, as: .image(perceptualPrecision: precision)) } - + + func test_imageAttachments_failed_snapshot() { + // Given + let message = ChatMessage.mock( + id: .unique, + cid: .unique, + text: "Test message", + author: .mock(id: .unique), + attachments: [ChatChannelTestHelpers.imageAttachment(state: .uploadingFailed)], + localState: .sendingFailed + ) + + // When + let view = testMessageViewContainer(message: message) + + // Then + assertSnapshot(matching: view, as: .image(perceptualPrecision: precision)) + } + + func test_imageAttachments_failedWhenMessageTextIsEmpty_snapshot() { + // Given + let message = ChatMessage.mock( + id: .unique, + cid: .unique, + text: "", + author: .mock(id: .unique), + attachments: [ChatChannelTestHelpers.imageAttachment(state: .uploadingFailed)], + localState: .sendingFailed + ) + + // When + let view = testMessageViewContainer(message: message) + + // Then + assertSnapshot(matching: view, as: .image(perceptualPrecision: precision)) + } + func test_translatedText_participant_snapshot() { // Given let message = ChatMessage.mock( diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/MessageReadIndicatorView_Tests.swift b/StreamChatSwiftUITests/Tests/ChatChannel/MessageReadIndicatorView_Tests.swift index 667f3942c..9d709e433 100644 --- a/StreamChatSwiftUITests/Tests/ChatChannel/MessageReadIndicatorView_Tests.swift +++ b/StreamChatSwiftUITests/Tests/ChatChannel/MessageReadIndicatorView_Tests.swift @@ -58,4 +58,30 @@ class MessageReadIndicatorView_Tests: StreamChatTestCase { // Then assertSnapshot(matching: view, as: .image(perceptualPrecision: precision)) } + + func test_messageReadIndicatorView_snapshotSending() { + // Given + let view = MessageReadIndicatorView( + readUsers: [], + showReadCount: false, + localState: .sending + ) + .frame(width: 50, height: 16) + + // Then + assertSnapshot(matching: view, as: .image(perceptualPrecision: precision)) + } + + func test_messageReadIndicatorView_snapshotMessageFailed() { + // Given + let view = MessageReadIndicatorView( + readUsers: [], + showReadCount: false, + localState: .sendingFailed + ) + .frame(width: 50, height: 16) + + // Then + assertSnapshot(matching: view, as: .image(perceptualPrecision: precision)) + } } diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageContainerView_Tests/test_imageAttachments_failedWhenMessageTextIsEmpty_snapshot.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageContainerView_Tests/test_imageAttachments_failedWhenMessageTextIsEmpty_snapshot.1.png new file mode 100644 index 000000000..79a916ce7 Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageContainerView_Tests/test_imageAttachments_failedWhenMessageTextIsEmpty_snapshot.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageContainerView_Tests/test_imageAttachments_failed_snapshot.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageContainerView_Tests/test_imageAttachments_failed_snapshot.1.png new file mode 100644 index 000000000..7ea4d26a6 Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageContainerView_Tests/test_imageAttachments_failed_snapshot.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageReadIndicatorView_Tests/test_messageReadIndicatorView_snapshotMessageFailed.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageReadIndicatorView_Tests/test_messageReadIndicatorView_snapshotMessageFailed.1.png new file mode 100644 index 000000000..f210a1ecd Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageReadIndicatorView_Tests/test_messageReadIndicatorView_snapshotMessageFailed.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageReadIndicatorView_Tests/test_messageReadIndicatorView_snapshotSending.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageReadIndicatorView_Tests/test_messageReadIndicatorView_snapshotSending.1.png new file mode 100644 index 000000000..567c11648 Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageReadIndicatorView_Tests/test_messageReadIndicatorView_snapshotSending.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannelList/ChatChannelListViewModel_Tests.swift b/StreamChatSwiftUITests/Tests/ChatChannelList/ChatChannelListViewModel_Tests.swift index 074dd4934..2259d73d7 100644 --- a/StreamChatSwiftUITests/Tests/ChatChannelList/ChatChannelListViewModel_Tests.swift +++ b/StreamChatSwiftUITests/Tests/ChatChannelList/ChatChannelListViewModel_Tests.swift @@ -110,7 +110,19 @@ class ChatChannelListViewModel_Tests: StreamChatTestCase { XCTAssert(viewModel.channelAlertType == .error) XCTAssert(viewModel.alertShown == true) } - + + func test_channelListVM_setChannelAlertType() { + // Given + let viewModel = makeDefaultChannelListVM() + + // When + viewModel.setChannelAlertType(.error) + + // Then + XCTAssert(viewModel.channelAlertType == .error) + XCTAssert(viewModel.alertShown == true) + } + func test_channelListVM_nameForChannel() { // Given let expectedName = "test"