diff --git a/.github/workflows/release-publish.yml b/.github/workflows/release-publish.yml
index 2d2a2deea..0d42daa8a 100644
--- a/.github/workflows/release-publish.yml
+++ b/.github/workflows/release-publish.yml
@@ -1,10 +1,6 @@
name: "Publish new release"
on:
- push:
- branches:
- - main
-
workflow_dispatch:
jobs:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 85dbdc475..837d4dd65 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.64.0](https://github.com/GetStream/stream-chat-swiftui/releases/tag/4.64.0)
+_October 03, 2024_
+
+### 🔄 Changed
+- Improves Poll voting UX by making it possible to tap on the whole option as well [#612](https://github.com/GetStream/stream-chat-swiftui/pull/612)
+### 🐞 Fixed
+- Rare crash when accessing frame of the view [#607](https://github.com/GetStream/stream-chat-swiftui/pull/607)
+- `ChatChannelListView` navigation did not trigger when using a custom container and its body reloaded [#609](https://github.com/GetStream/stream-chat-swiftui/pull/609)
+- Channel was sometimes not marked as read when tapping the x on the unread message pill in the message list [#610](https://github.com/GetStream/stream-chat-swiftui/pull/610)
+- Channel was sometimes not selected if `ChatChannelViewModel.selectedChannelId` was set to a channel created a moments ago [#611](https://github.com/GetStream/stream-chat-swiftui/pull/611)
+- Fix the poll vote progress view not having full width when the Poll is closed [#612](https://github.com/GetStream/stream-chat-swiftui/pull/612)
+- Fix the last vote author not accurate in the channel preview [#612](https://github.com/GetStream/stream-chat-swiftui/pull/612)
+
# [4.63.0](https://github.com/GetStream/stream-chat-swiftui/releases/tag/4.63.0)
_September 12, 2024_
diff --git a/Gemfile.lock b/Gemfile.lock
index 9bec85b73..9a4ebde82 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -199,7 +199,7 @@ GEM
fastlane
pry
fastlane-plugin-sonarcloud_metric_kit (0.2.1)
- fastlane-plugin-stream_actions (0.3.63)
+ fastlane-plugin-stream_actions (0.3.70)
xctest_list (= 1.2.1)
fastlane-plugin-versioning (0.5.2)
ffi (1.17.0)
@@ -306,7 +306,7 @@ GEM
coderay (~> 1.1)
method_source (~> 1.0)
public_suffix (4.0.7)
- puma (6.4.2)
+ puma (6.4.3)
nio4r (~> 2.0)
racc (1.8.1)
rack (3.1.7)
@@ -396,7 +396,7 @@ GEM
concurrent-ruby (~> 1.0)
uber (0.1.0)
unicode-display_width (2.5.0)
- webrick (1.8.1)
+ webrick (1.8.2)
word_wrap (1.0.0)
xcinvoke (0.3.0)
liferaft (~> 0.0.6)
@@ -427,7 +427,7 @@ DEPENDENCIES
fastlane-plugin-create_xcframework
fastlane-plugin-lizard
fastlane-plugin-sonarcloud_metric_kit
- fastlane-plugin-stream_actions (= 0.3.63)
+ fastlane-plugin-stream_actions (= 0.3.70)
fastlane-plugin-versioning
jazzy
json
diff --git a/Package.swift b/Package.swift
index 44ef9bf45..74df90fef 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.63.0"),
+ .package(url: "https://github.com/GetStream/stream-chat-swift.git", from: "4.64.0"),
],
targets: [
.target(
diff --git a/README.md b/README.md
index 2e09c4a01..0ee588e56 100644
--- a/README.md
+++ b/README.md
@@ -5,7 +5,7 @@
-
+
## SwiftUI StreamChat SDK
diff --git a/Sources/StreamChatSwiftUI/ChatChannel/Composer/Suggestions/InstantCommands/TwoStepMentionCommand.swift b/Sources/StreamChatSwiftUI/ChatChannel/Composer/Suggestions/InstantCommands/TwoStepMentionCommand.swift
index dd544a9a8..cfdb9719d 100644
--- a/Sources/StreamChatSwiftUI/ChatChannel/Composer/Suggestions/InstantCommands/TwoStepMentionCommand.swift
+++ b/Sources/StreamChatSwiftUI/ChatChannel/Composer/Suggestions/InstantCommands/TwoStepMentionCommand.swift
@@ -40,7 +40,7 @@ open class TwoStepMentionCommand: CommandHandler {
self.displayInfo = displayInfo
}
- public func canHandleCommand(in text: String, caretLocation: Int) -> ComposerCommand? {
+ open func canHandleCommand(in text: String, caretLocation: Int) -> ComposerCommand? {
if text == id {
return ComposerCommand(
id: id,
@@ -59,7 +59,7 @@ open class TwoStepMentionCommand: CommandHandler {
}
}
- public func handleCommand(
+ open func handleCommand(
for text: Binding,
selectedRangeLocation: Binding,
command: Binding,
@@ -84,11 +84,11 @@ open class TwoStepMentionCommand: CommandHandler {
selectedRangeLocation.wrappedValue = newCaretLocation
}
- public func canBeExecuted(composerCommand: ComposerCommand) -> Bool {
+ open func canBeExecuted(composerCommand: ComposerCommand) -> Bool {
selectedUser != nil
}
- public func commandHandler(for command: ComposerCommand) -> CommandHandler? {
+ open func commandHandler(for command: ComposerCommand) -> CommandHandler? {
if let selectedUser = selectedUser,
command.typingSuggestion.text != "\(mentionSymbol)\(selectedUser.mentionText)" {
self.selectedUser = nil
@@ -96,7 +96,7 @@ open class TwoStepMentionCommand: CommandHandler {
return command.id == id ? self : nil
}
- public func showSuggestions(
+ open func showSuggestions(
for command: ComposerCommand
) -> Future {
if selectedUser != nil {
@@ -126,7 +126,7 @@ open class TwoStepMentionCommand: CommandHandler {
return mentionsCommandHandler.showSuggestions(for: updated)
}
- public var replacesMessageSent: Bool {
+ open var replacesMessageSent: Bool {
true
}
diff --git a/Sources/StreamChatSwiftUI/ChatChannel/MessageList/MessageContainerView.swift b/Sources/StreamChatSwiftUI/ChatChannel/MessageList/MessageContainerView.swift
index 12c2c84c6..ea39a48d9 100644
--- a/Sources/StreamChatSwiftUI/ChatChannel/MessageList/MessageContainerView.swift
+++ b/Sources/StreamChatSwiftUI/ChatChannel/MessageList/MessageContainerView.swift
@@ -112,9 +112,7 @@ public struct MessageContainerView: View {
GeometryReader { proxy in
Rectangle().fill(Color.clear)
.onChange(of: computeFrame, perform: { _ in
- DispatchQueue.main.async {
- frame = proxy.frame(in: .global)
- }
+ frame = proxy.frame(in: .global)
})
}
)
@@ -347,9 +345,8 @@ public struct MessageContainerView: View {
showsMessageActions: Bool,
showsBottomContainer: Bool = true
) {
- computeFrame = true
+ computeFrame.toggle()
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
- computeFrame = false
triggerHapticFeedback(style: .medium)
onLongPress(
MessageDisplayInfo(
diff --git a/Sources/StreamChatSwiftUI/ChatChannel/MessageList/MessageListView.swift b/Sources/StreamChatSwiftUI/ChatChannel/MessageList/MessageListView.swift
index e508f9308..aebc4132e 100644
--- a/Sources/StreamChatSwiftUI/ChatChannel/MessageList/MessageListView.swift
+++ b/Sources/StreamChatSwiftUI/ChatChannel/MessageList/MessageListView.swift
@@ -301,7 +301,7 @@ public struct MessageListView: View, KeyboardReadable {
_ = onJumpToMessage?(firstUnreadMessageId ?? .unknownMessageId)
},
onClose: {
- firstUnreadMessageId = nil
+ chatClient.channelController(for: channel.cid).markRead()
unreadButtonDismissed = true
}
) : nil
diff --git a/Sources/StreamChatSwiftUI/ChatChannel/MessageList/Polls/PollAllOptionsView.swift b/Sources/StreamChatSwiftUI/ChatChannel/MessageList/Polls/PollAllOptionsView.swift
index c5106e3dc..e8a2de2fb 100644
--- a/Sources/StreamChatSwiftUI/ChatChannel/MessageList/Polls/PollAllOptionsView.swift
+++ b/Sources/StreamChatSwiftUI/ChatChannel/MessageList/Polls/PollAllOptionsView.swift
@@ -31,7 +31,8 @@ struct PollAllOptionsView: View {
viewModel: viewModel,
option: option,
optionFont: fonts.headline,
- alternativeStyle: true
+ alternativeStyle: true,
+ checkboxButtonSpacing: 8
)
}
}
diff --git a/Sources/StreamChatSwiftUI/ChatChannel/MessageList/Polls/PollAttachmentView.swift b/Sources/StreamChatSwiftUI/ChatChannel/MessageList/Polls/PollAttachmentView.swift
index 8e1512983..ad17f8401 100644
--- a/Sources/StreamChatSwiftUI/ChatChannel/MessageList/Polls/PollAttachmentView.swift
+++ b/Sources/StreamChatSwiftUI/ChatChannel/MessageList/Polls/PollAttachmentView.swift
@@ -55,8 +55,8 @@ public struct PollAttachmentView: View {
PollOptionView(
viewModel: viewModel,
option: option,
- optionVotes: poll.voteCountsByOption?[option.id],
- maxVotes: poll.voteCountsByOption?.values.max()
+ optionVotes: poll.voteCount(for: option),
+ maxVotes: poll.currentMaximumVoteCount
)
.layoutPriority(1) // do not compress long text
}
@@ -190,53 +190,63 @@ struct PollOptionView: View {
var maxVotes: Int?
/// If true, only option name and vote count is shown, otherwise votes indicator and avatars appear as well.
var alternativeStyle: Bool = false
-
+ /// The spacing between the checkbox and the option name.
+ /// By default it is 4. For All Options View is 8.
+ var checkboxButtonSpacing: CGFloat = 4
+
var body: some View {
- VStack(spacing: 4) {
- HStack(alignment: .top) {
- if !viewModel.poll.isClosed {
- Button {
- if viewModel.optionVotedByCurrentUser(option) {
- viewModel.removePollVote(for: option)
- } else {
- viewModel.castPollVote(for: option)
- }
- } label: {
- if viewModel.optionVotedByCurrentUser(option) {
- Image(systemName: "checkmark.circle.fill")
- } else {
- Image(systemName: "circle")
- }
+ HStack(alignment: .top, spacing: checkboxButtonSpacing) {
+ if !viewModel.poll.isClosed {
+ Button {
+ togglePollVote()
+ } label: {
+ if viewModel.optionVotedByCurrentUser(option) {
+ Image(systemName: "checkmark.circle.fill")
+ } else {
+ Image(systemName: "circle")
}
}
-
- Text(option.text)
- .font(optionFont)
- Spacer()
- if !alternativeStyle, viewModel.showVoterAvatars {
- HStack(spacing: -4) {
- ForEach(
- option.latestVotes.sorted(by: { $0.createdAt > $1.createdAt }).suffix(2)
- ) { vote in
- MessageAvatarView(
- avatarURL: vote.user?.imageURL,
- size: .init(width: 20, height: 20)
- )
+ }
+ VStack(spacing: 4) {
+ HStack(alignment: .top) {
+ Text(option.text)
+ .font(optionFont)
+ Spacer()
+ if !alternativeStyle, viewModel.showVoterAvatars {
+ HStack(spacing: -4) {
+ ForEach(
+ option.latestVotes.prefix(2)
+ ) { vote in
+ MessageAvatarView(
+ avatarURL: vote.user?.imageURL,
+ size: .init(width: 20, height: 20)
+ )
+ }
}
}
+ Text("\(viewModel.poll.voteCountsByOption?[option.id] ?? 0)")
+ }
+ if !alternativeStyle {
+ PollVotesIndicatorView(
+ alternativeStyle: viewModel.poll.isClosed && viewModel.hasMostVotes(for: option),
+ optionVotes: optionVotes ?? 0,
+ maxVotes: maxVotes ?? 0
+ )
}
- Text("\(viewModel.poll.voteCountsByOption?[option.id] ?? 0)")
- }
-
- if !alternativeStyle {
- PollVotesIndicatorView(
- alternativeStyle: viewModel.poll.isClosed && viewModel.hasMostVotes(for: option),
- optionVotes: optionVotes ?? 0,
- maxVotes: maxVotes ?? 0
- )
- .padding(.leading, 24)
}
}
+ .contentShape(Rectangle())
+ .onTapGesture {
+ togglePollVote()
+ }
+ }
+
+ func togglePollVote() {
+ if viewModel.optionVotedByCurrentUser(option) {
+ viewModel.removePollVote(for: option)
+ } else {
+ viewModel.castPollVote(for: option)
+ }
}
}
diff --git a/Sources/StreamChatSwiftUI/ChatChannel/MessageList/Polls/PollAttachmentViewModel.swift b/Sources/StreamChatSwiftUI/ChatChannel/MessageList/Polls/PollAttachmentViewModel.swift
index 6165a366b..bf3e3ace9 100644
--- a/Sources/StreamChatSwiftUI/ChatChannel/MessageList/Polls/PollAttachmentViewModel.swift
+++ b/Sources/StreamChatSwiftUI/ChatChannel/MessageList/Polls/PollAttachmentViewModel.swift
@@ -198,7 +198,7 @@ public class PollAttachmentViewModel: ObservableObject, PollControllerDelegate {
/// True, if the current user has voted for the specified option, otherwise false.
public func optionVotedByCurrentUser(_ option: PollOption) -> Bool {
- currentUserVote(for: option) != nil
+ poll.hasCurrentUserVoted(for: option)
}
/// Adds a new option to the poll.
@@ -219,13 +219,7 @@ public class PollAttachmentViewModel: ObservableObject, PollControllerDelegate {
///
/// - Note: When multiple options have the highest vote count, this function returns false.
public func hasMostVotes(for option: PollOption) -> Bool {
- guard let allCounts = poll.voteCountsByOption else { return false }
- guard let optionVoteCount = allCounts[option.id], optionVoteCount > 0 else { return false }
- guard let highestVotePerOption = allCounts.values.max() else { return false }
- guard optionVoteCount == highestVotePerOption else { return false }
- // Check if only one option has highest number for votes
- let optionsByVoteCounts = Dictionary(grouping: allCounts, by: { $0.value })
- return optionsByVoteCounts[optionVoteCount]?.count == 1
+ poll.isOptionWithMostVotes(option)
}
// MARK: - PollControllerDelegate
@@ -244,7 +238,7 @@ public class PollAttachmentViewModel: ObservableObject, PollControllerDelegate {
// MARK: - private
private func currentUserVote(for option: PollOption) -> PollVote? {
- currentUserVotes.first(where: { $0.optionId == option.id })
+ poll.currentUserVote(for: option)
}
private func notifySheetPresentation(shown: Bool) {
diff --git a/Sources/StreamChatSwiftUI/ChatChannel/MessageList/Polls/PollCommentsViewModel.swift b/Sources/StreamChatSwiftUI/ChatChannel/MessageList/Polls/PollCommentsViewModel.swift
index 826e4a5ae..34569209a 100644
--- a/Sources/StreamChatSwiftUI/ChatChannel/MessageList/Polls/PollCommentsViewModel.swift
+++ b/Sources/StreamChatSwiftUI/ChatChannel/MessageList/Polls/PollCommentsViewModel.swift
@@ -25,10 +25,7 @@ class PollCommentsViewModel: ObservableObject, PollVoteListControllerDelegate {
convenience init(poll: Poll, pollController: PollController) {
let query = PollVoteListQuery(
pollId: poll.id,
- optionId: nil,
- filter: .and(
- [.equal(.pollId, to: poll.id), .equal(.isAnswer, to: true)]
- )
+ filter: .equal(.isAnswer, to: true)
)
self.init(
pollController: pollController,
diff --git a/Sources/StreamChatSwiftUI/ChatChannel/MessageList/Polls/PollOptionAllVotesViewModel.swift b/Sources/StreamChatSwiftUI/ChatChannel/MessageList/Polls/PollOptionAllVotesViewModel.swift
index 7f6a414d0..5fbf7de5b 100644
--- a/Sources/StreamChatSwiftUI/ChatChannel/MessageList/Polls/PollOptionAllVotesViewModel.swift
+++ b/Sources/StreamChatSwiftUI/ChatChannel/MessageList/Polls/PollOptionAllVotesViewModel.swift
@@ -24,7 +24,7 @@ class PollOptionAllVotesViewModel: ObservableObject, PollVoteListControllerDeleg
self.option = option
let query = PollVoteListQuery(
pollId: poll.id,
- optionId: option.id, filter: .equal(.optionId, to: option.id)
+ optionId: option.id
)
controller = InjectedValues[\.chatClient].pollVoteListController(query: query)
controller.delegate = self
diff --git a/Sources/StreamChatSwiftUI/ChatChannel/MessageList/Polls/PollResultsView.swift b/Sources/StreamChatSwiftUI/ChatChannel/MessageList/Polls/PollResultsView.swift
index 06870fbc9..46b1b3e29 100644
--- a/Sources/StreamChatSwiftUI/ChatChannel/MessageList/Polls/PollResultsView.swift
+++ b/Sources/StreamChatSwiftUI/ChatChannel/MessageList/Polls/PollResultsView.swift
@@ -45,7 +45,7 @@ struct PollResultsView: View {
poll: viewModel.poll,
option: option,
votes: Array(
- option.latestVotes.sorted(by: { $0.createdAt > $1.createdAt })
+ option.latestVotes
.prefix(numberOfItemsShown)
),
hasMostVotes: viewModel.hasMostVotes(for: option),
diff --git a/Sources/StreamChatSwiftUI/ChatChannelList/ChatChannelListItem.swift b/Sources/StreamChatSwiftUI/ChatChannelList/ChatChannelListItem.swift
index 0e9c1c85f..831a07f4c 100644
--- a/Sources/StreamChatSwiftUI/ChatChannelList/ChatChannelListItem.swift
+++ b/Sources/StreamChatSwiftUI/ChatChannelList/ChatChannelListItem.swift
@@ -360,8 +360,8 @@ extension ChatChannel {
private func pollMessageText(for previewMessage: ChatMessage) -> String? {
guard let poll = previewMessage.poll, !previewMessage.isDeleted else { return nil }
var components = ["📊"]
- if let latestVoter = poll.latestVotesByOption.first?.latestVotes.first?.user {
- if previewMessage.isSentByCurrentUser {
+ if let latestVoter = poll.latestVotes.first?.user {
+ if latestVoter.id == membership?.id {
components.append(L10n.Channel.Item.pollYouVoted)
} else {
components.append(L10n.Channel.Item.pollSomeoneVoted(latestVoter.name ?? latestVoter.id))
diff --git a/Sources/StreamChatSwiftUI/ChatChannelList/ChatChannelListView.swift b/Sources/StreamChatSwiftUI/ChatChannelList/ChatChannelListView.swift
index 6b688b06f..5f9dd7ca5 100644
--- a/Sources/StreamChatSwiftUI/ChatChannelList/ChatChannelListView.swift
+++ b/Sources/StreamChatSwiftUI/ChatChannelList/ChatChannelListView.swift
@@ -16,10 +16,29 @@ public struct ChatChannelListView: View {
private let viewFactory: Factory
private let title: String
- private var onItemTap: (ChatChannel) -> Void
+ private let customOnItemTap: ((ChatChannel) -> Void)?
private var embedInNavigationView: Bool
private var handleTabBarVisibility: Bool
-
+
+ /// Creates a channel list view.
+ ///
+ /// - Parameters:
+ /// - viewFactory: The view factory used for creating views used by the channel list.
+ /// - viewModel: The view model instance providing the data. Default view model is created if nil.
+ /// - channelListController: The channel list controller managing the list of channels used as a data souce for the view model. Default controller is created if nil.
+ /// - title: A title used as the navigation bar title.
+ /// - onItemTap: A closure for handling a tap on the channel item. Default closure updates the ``ChatChannelListViewModel/selectedChannel`` property in the view model.
+ /// - selectedChannelId: The id of a channel to be opened after the initial channel list load.
+ /// - handleTabBarVisibility: True, if TabBar visibility should be automatically updated.
+ /// - embedInNavigationView: True, if the channel list view should be embedded in a navigation stack.
+ ///
+ /// Changing the instance of the passed in `viewModel` or `channelListController` does not have an effect without reloading the channel list view by assigning a custom identity. The custom identity should be refreshed when either of the passed in instances have been recreated.
+ /// ```swift
+ /// ChatChannelListView(
+ /// viewModel: viewModel
+ /// )
+ /// .id(myCustomViewIdentity)
+ /// ```
public init(
viewFactory: Factory = DefaultViewFactory.shared,
viewModel: ChatChannelListViewModel? = nil,
@@ -30,23 +49,25 @@ public struct ChatChannelListView: View {
handleTabBarVisibility: Bool = true,
embedInNavigationView: Bool = true
) {
- let channelListVM = viewModel ?? ViewModelsFactory.makeChannelListViewModel(
- channelListController: channelListController,
- selectedChannelId: selectedChannelId
- )
_viewModel = StateObject(
- wrappedValue: channelListVM
+ wrappedValue: viewModel ?? ViewModelsFactory.makeChannelListViewModel(
+ channelListController: channelListController,
+ selectedChannelId: selectedChannelId
+ )
)
self.viewFactory = viewFactory
self.title = title
self.handleTabBarVisibility = handleTabBarVisibility
self.embedInNavigationView = embedInNavigationView
- if let onItemTap = onItemTap {
- self.onItemTap = onItemTap
- } else {
- self.onItemTap = { channel in
- channelListVM.selectedChannel = channel.channelSelectionInfo
- }
+ customOnItemTap = onItemTap
+ }
+
+ var onItemTap: (ChatChannel) -> Void {
+ if let customOnItemTap {
+ return customOnItemTap
+ }
+ return { [weak viewModel] channel in
+ viewModel?.selectedChannel = channel.channelSelectionInfo
}
}
diff --git a/Sources/StreamChatSwiftUI/ChatChannelList/ChatChannelListViewModel.swift b/Sources/StreamChatSwiftUI/ChatChannelList/ChatChannelListViewModel.swift
index 2265d8a41..1fe060e30 100644
--- a/Sources/StreamChatSwiftUI/ChatChannelList/ChatChannelListViewModel.swift
+++ b/Sources/StreamChatSwiftUI/ChatChannelList/ChatChannelListViewModel.swift
@@ -2,6 +2,7 @@
// Copyright © 2024 Stream.io Inc. All rights reserved.
//
+import Combine
import Foundation
import StreamChat
import SwiftUI
@@ -117,7 +118,13 @@ open class ChatChannelListViewModel: ObservableObject, ChatChannelListController
public var isSearching: Bool {
!searchText.isEmpty
}
-
+
+ /// Creates a view model for the `ChatChannelListView`.
+ ///
+ /// - Parameters:
+ /// - channelListController: A controller providing the list of channels. If nil, a controller with default `ChannelListQuery` is created.
+ /// - selectedChannelId: The id of a channel to select. If the channel is not part of the channel list query, no channel is selected.
+ /// Consider using ``ChatChannelScreen`` for presenting channels what might not be part of the initial page of channels.
public init(
channelListController: ChatChannelListController? = nil,
selectedChannelId: String? = nil
@@ -265,15 +272,30 @@ open class ChatChannelListViewModel: ObservableObject, ChatChannelListController
}
}
+ private var deeplinkCancellable: AnyCancellable?
+
+ /// Checks for currently loaded channels for opening a channel with id.
private func checkForDeeplinks() {
- if let selectedChannelId = selectedChannelId,
- let channelId = try? ChannelId(cid: selectedChannelId) {
- let chatController = chatClient.channelController(
- for: channelId,
- messageOrdering: .topToBottom
- )
- selectedChannel = chatController.channel?.channelSelectionInfo
- self.selectedChannelId = nil
+ guard let selectedChannelId else { return }
+ do {
+ let channelId = try ChannelId(cid: selectedChannelId)
+ if let channel = channels.first(where: { $0.cid == channelId }) {
+ selectedChannel = channel.channelSelectionInfo
+ } else {
+ // Start waiting for a channel list change because the channel is not part of the loaded list
+ deeplinkCancellable = $channels
+ .map { Array($0) }
+ .compactMap { channels in
+ channels.first(where: { $0.cid == channelId })
+ }
+ .map(\.channelSelectionInfo)
+ .sink { [weak self] selection in
+ self?.deeplinkCancellable = nil
+ self?.selectedChannel = selection
+ }
+ }
+ } catch {
+ log.error("Failed to select a channel with id \(selectedChannelId) (\(error))")
}
}
diff --git a/Sources/StreamChatSwiftUI/Generated/SystemEnvironment+Version.swift b/Sources/StreamChatSwiftUI/Generated/SystemEnvironment+Version.swift
index 922434ca3..a154345d2 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.63.0"
+ public static let version: String = "4.64.0"
}
diff --git a/Sources/StreamChatSwiftUI/Info.plist b/Sources/StreamChatSwiftUI/Info.plist
index 4572be90d..9a56fe8f6 100644
--- a/Sources/StreamChatSwiftUI/Info.plist
+++ b/Sources/StreamChatSwiftUI/Info.plist
@@ -15,7 +15,7 @@
CFBundlePackageType
$(PRODUCT_BUNDLE_PACKAGE_TYPE)
CFBundleShortVersionString
- 4.63.0
+ 4.64.0
CFBundleVersion
$(CURRENT_PROJECT_VERSION)
NSPhotoLibraryUsageDescription
diff --git a/StreamChatSwiftUI-XCFramework.podspec b/StreamChatSwiftUI-XCFramework.podspec
index 9e2e00999..6bf762853 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.63.0'
+ spec.version = '4.64.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.63.0'
+ spec.dependency 'StreamChat-XCFramework', '~> 4.64.0'
spec.cocoapods_version = '>= 1.11.0'
end
diff --git a/StreamChatSwiftUI.podspec b/StreamChatSwiftUI.podspec
index 52980009a..92d1fdd4a 100644
--- a/StreamChatSwiftUI.podspec
+++ b/StreamChatSwiftUI.podspec
@@ -1,6 +1,6 @@
Pod::Spec.new do |spec|
spec.name = 'StreamChatSwiftUI'
- spec.version = '4.63.0'
+ spec.version = '4.64.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.63.0'
+ spec.dependency 'StreamChat', '~> 4.64.0'
end
diff --git a/StreamChatSwiftUI.xcodeproj/project.pbxproj b/StreamChatSwiftUI.xcodeproj/project.pbxproj
index 2145d9830..e6a6ac9e2 100644
--- a/StreamChatSwiftUI.xcodeproj/project.pbxproj
+++ b/StreamChatSwiftUI.xcodeproj/project.pbxproj
@@ -3721,7 +3721,7 @@
repositoryURL = "https://github.com/GetStream/stream-chat-swift.git";
requirement = {
kind = upToNextMajorVersion;
- minimumVersion = 4.63.0;
+ minimumVersion = 4.64.0;
};
};
E3A1C01A282BAC66002D1E26 /* XCRemoteSwiftPackageReference "sentry-cocoa" */ = {
diff --git a/StreamChatSwiftUIArtifacts.json b/StreamChatSwiftUIArtifacts.json
index 69566c06c..a7eb8a623 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"}
\ 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"}
\ No newline at end of file
diff --git a/StreamChatSwiftUITests/Infrastructure/Mocks/Poll_Mock.swift b/StreamChatSwiftUITests/Infrastructure/Mocks/Poll_Mock.swift
index 6a7405c32..ead778f5b 100644
--- a/StreamChatSwiftUITests/Infrastructure/Mocks/Poll_Mock.swift
+++ b/StreamChatSwiftUITests/Infrastructure/Mocks/Poll_Mock.swift
@@ -51,7 +51,9 @@ extension Poll {
createdBy: .mock(id: "test", name: "test"),
latestAnswers: [],
options: [option],
- latestVotesByOption: [option]
+ latestVotesByOption: [option],
+ latestVotes: [],
+ ownVotes: []
)
return poll
}
@@ -89,7 +91,9 @@ extension Poll {
createdBy: .mock(id: "test", name: "test"),
latestAnswers: [],
options: options,
- latestVotesByOption: options
+ latestVotesByOption: options,
+ latestVotes: [],
+ ownVotes: []
)
}
}
diff --git a/StreamChatSwiftUITests/Infrastructure/Shared/StreamChatModel.xcdatamodeld/StreamChatModel.xcdatamodel/contents b/StreamChatSwiftUITests/Infrastructure/Shared/StreamChatModel.xcdatamodeld/StreamChatModel.xcdatamodel/contents
index 3d988576e..aca907f81 100644
--- a/StreamChatSwiftUITests/Infrastructure/Shared/StreamChatModel.xcdatamodeld/StreamChatModel.xcdatamodel/contents
+++ b/StreamChatSwiftUITests/Infrastructure/Shared/StreamChatModel.xcdatamodeld/StreamChatModel.xcdatamodel/contents
@@ -1,9 +1,11 @@
-
+
+
+
@@ -20,6 +22,7 @@
+
@@ -36,10 +39,12 @@
+
+
@@ -132,6 +137,7 @@
+
@@ -139,6 +145,7 @@
+
@@ -323,10 +330,10 @@
-
+
-
+
@@ -345,7 +352,7 @@
-
+
@@ -372,9 +379,16 @@
+
+
+
+
+
+
+
@@ -434,7 +448,7 @@
-
+
diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/PollAttachmentViewModel_Tests.swift b/StreamChatSwiftUITests/Tests/ChatChannel/PollAttachmentViewModel_Tests.swift
index e91e026e5..ddc5d0402 100644
--- a/StreamChatSwiftUITests/Tests/ChatChannel/PollAttachmentViewModel_Tests.swift
+++ b/StreamChatSwiftUITests/Tests/ChatChannel/PollAttachmentViewModel_Tests.swift
@@ -58,14 +58,13 @@ final class PollAttachmentViewModel_Tests: StreamChatTestCase {
func test_pollAttachmentViewModel_removeVoteCalled() {
// Given
+ let vote = makePollVote()
let pollController = makePollController()
let viewModel = PollAttachmentViewModel(
message: .mock(),
- poll: .unique,
+ poll: .mock(ownVotes: [vote]),
pollController: pollController
)
- let vote = makePollVote()
- viewModel.currentUserVotes = [vote]
// When
viewModel.removePollVote(for: .init(id: vote.optionId!, text: ""))
@@ -92,15 +91,14 @@ final class PollAttachmentViewModel_Tests: StreamChatTestCase {
func test_pollAttachmentViewModel_optionVotedByCurrentUser() {
// Given
+ let vote = makePollVote()
let pollController = makePollController()
let viewModel = PollAttachmentViewModel(
message: .mock(),
- poll: .unique,
+ poll: .mock(ownVotes: [vote]),
pollController: pollController
)
- let vote = makePollVote()
let option = PollOption(id: vote.optionId!, text: "")
- viewModel.currentUserVotes = [vote]
// When
let optionVoted = viewModel.optionVotedByCurrentUser(option)
diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/PollCommentsViewModel_Tests.swift b/StreamChatSwiftUITests/Tests/ChatChannel/PollCommentsViewModel_Tests.swift
index 2a9af80bd..c98b1513f 100644
--- a/StreamChatSwiftUITests/Tests/ChatChannel/PollCommentsViewModel_Tests.swift
+++ b/StreamChatSwiftUITests/Tests/ChatChannel/PollCommentsViewModel_Tests.swift
@@ -82,10 +82,7 @@ final class PollCommentsViewModel_Tests: StreamChatTestCase {
private func makeCommentsController() -> PollVoteListController_Mock {
let query = PollVoteListQuery(
pollId: .unique,
- optionId: nil,
- filter: .and(
- [.equal(.pollId, to: .unique), .equal(.isAnswer, to: true)]
- )
+ filter: .equal(.isAnswer, to: true)
)
return PollVoteListController_Mock(query: query, client: chatClient)
}
diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAttachmentView_Tests/test_pollAttachmentView_closedPoll.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAttachmentView_Tests/test_pollAttachmentView_closedPoll.1.png
index 4cad27e7c..973eec26d 100644
Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAttachmentView_Tests/test_pollAttachmentView_closedPoll.1.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAttachmentView_Tests/test_pollAttachmentView_closedPoll.1.png differ
diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAttachmentView_Tests/test_pollAttachmentView_snapshotCommentsAndSuggestions.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAttachmentView_Tests/test_pollAttachmentView_snapshotCommentsAndSuggestions.1.png
index 39ae151d5..d53ef697e 100644
Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAttachmentView_Tests/test_pollAttachmentView_snapshotCommentsAndSuggestions.1.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAttachmentView_Tests/test_pollAttachmentView_snapshotCommentsAndSuggestions.1.png differ
diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAttachmentView_Tests/test_pollAttachmentView_snapshotUniqueVotes.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAttachmentView_Tests/test_pollAttachmentView_snapshotUniqueVotes.1.png
index 042e8f541..66c029490 100644
Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAttachmentView_Tests/test_pollAttachmentView_snapshotUniqueVotes.1.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAttachmentView_Tests/test_pollAttachmentView_snapshotUniqueVotes.1.png differ
diff --git a/StreamChatSwiftUITests/Tests/ChatChannelList/ChatChannelListItemView_Tests.swift b/StreamChatSwiftUITests/Tests/ChatChannelList/ChatChannelListItemView_Tests.swift
index e98f45327..98988b360 100644
--- a/StreamChatSwiftUITests/Tests/ChatChannelList/ChatChannelListItemView_Tests.swift
+++ b/StreamChatSwiftUITests/Tests/ChatChannelList/ChatChannelListItemView_Tests.swift
@@ -153,6 +153,54 @@ final class ChatChannelListItemView_Tests: StreamChatTestCase {
assertSnapshot(matching: view, as: .image(perceptualPrecision: precision))
}
+ func test_channelListItem_pollMessage_youVoted() throws {
+ // Given
+ let currentUserId = UserId.unique
+ let message = try mockPollMessage(isSentByCurrentUser: false, latestVotes: [
+ .mock(pollId: .unique, optionId: .unique, user: .mock(id: currentUserId)),
+ .unique,
+ .unique
+ ])
+ let channel = ChatChannel.mock(cid: .unique, membership: .mock(id: currentUserId), latestMessages: [message])
+
+ // When
+ let view = ChatChannelListItem(
+ channel: channel,
+ channelName: "Test",
+ avatar: .circleImage,
+ onlineIndicatorShown: true,
+ onItemTap: { _ in }
+ )
+ .frame(width: defaultScreenSize.width)
+
+ // Then
+ assertSnapshot(matching: view, as: .image(perceptualPrecision: precision))
+ }
+
+ func test_channelListItem_pollMessage_someoneVoted() throws {
+ // Given
+ let currentUserId = UserId.unique
+ let message = try mockPollMessage(isSentByCurrentUser: false, latestVotes: [
+ .mock(pollId: .unique, optionId: .unique, user: .mock(id: .unique, name: "Steve Jobs")),
+ .unique,
+ .mock(pollId: .unique, optionId: .unique, user: .mock(id: currentUserId))
+ ])
+ let channel = ChatChannel.mock(cid: .unique, membership: .mock(id: currentUserId), latestMessages: [message])
+
+ // When
+ let view = ChatChannelListItem(
+ channel: channel,
+ channelName: "Test",
+ avatar: .circleImage,
+ onlineIndicatorShown: true,
+ onItemTap: { _ in }
+ )
+ .frame(width: defaultScreenSize.width)
+
+ // Then
+ assertSnapshot(matching: view, as: .image(perceptualPrecision: precision))
+ }
+
// MARK: - private
private func mockAudioMessage(text: String, isSentByCurrentUser: Bool) throws -> ChatMessage {
@@ -271,7 +319,7 @@ final class ChatChannelListItemView_Tests: StreamChatTestCase {
)
}
- private func mockPollMessage(isSentByCurrentUser: Bool) throws -> ChatMessage {
+ private func mockPollMessage(isSentByCurrentUser: Bool, latestVotes: [PollVote] = []) throws -> ChatMessage {
.mock(
id: .unique,
cid: .unique,
@@ -281,7 +329,11 @@ final class ChatChannelListItemView_Tests: StreamChatTestCase {
createdAt: Date(timeIntervalSince1970: 100),
localState: nil,
isSentByCurrentUser: isSentByCurrentUser,
- poll: .mock(optionCount: 1, voteCountForOption: { _ in 0 })
+ poll: .mock(
+ name: "Test poll",
+ createdBy: .mock(id: "test", name: "test"),
+ latestVotes: latestVotes
+ )
)
}
}
diff --git a/StreamChatSwiftUITests/Tests/ChatChannelList/ChatChannelListViewModel_Tests.swift b/StreamChatSwiftUITests/Tests/ChatChannelList/ChatChannelListViewModel_Tests.swift
index 3f6fde345..194d4fe89 100644
--- a/StreamChatSwiftUITests/Tests/ChatChannelList/ChatChannelListViewModel_Tests.swift
+++ b/StreamChatSwiftUITests/Tests/ChatChannelList/ChatChannelListViewModel_Tests.swift
@@ -4,6 +4,7 @@
@testable import StreamChat
@testable import StreamChatSwiftUI
+@testable import StreamChatTestTools
import XCTest
class ChatChannelListViewModel_Tests: StreamChatTestCase {
@@ -270,6 +271,59 @@ class ChatChannelListViewModel_Tests: StreamChatTestCase {
// Then
XCTAssert(viewModel.hideTabBar == true)
}
+
+ func test_channelListVM_deeplinkToExistingChannel() throws {
+ // Given
+ let channels = (0..<3).map { ChatChannel.mock(cid: ChannelId(type: .messaging, id: "\($0)")) }
+ let channelListController = makeChannelListController(channels: channels)
+ let selectedId = channels[1].cid
+ let viewModel = ChatChannelListViewModel(
+ channelListController: channelListController,
+ selectedChannelId: selectedId.rawValue
+ )
+
+ // Then
+ let expectation = XCTestExpectation(description: "SelectedChannel")
+ let cancellable = viewModel.$selectedChannel
+ .filter { $0?.channel.cid == selectedId }
+ .sink { _ in
+ expectation.fulfill()
+ }
+ // Resume synchronize()
+ chatClient.mockAPIClient.test_simulateResponse(.success(ChannelListPayload(channels: [])))
+ wait(for: [expectation], timeout: defaultTimeout)
+ cancellable.cancel()
+ }
+
+ func test_channelListVM_deeplinkToIncomingChannel() {
+ // Given
+ let channels = (0..<3).map { ChatChannel.mock(cid: ChannelId(type: .messaging, id: "\($0)")) }
+ let channelListController = makeChannelListController(channels: channels)
+ let selectedId = ChannelId(type: .messaging, id: "3")
+ let viewModel = ChatChannelListViewModel(
+ channelListController: channelListController,
+ selectedChannelId: selectedId.rawValue
+ )
+
+ // When
+ let expectation = XCTestExpectation(description: "SelectedChannel")
+ let cancellable = viewModel.$selectedChannel
+ .filter { $0?.channel.cid == selectedId }
+ .sink { _ in
+ expectation.fulfill()
+ }
+ let insertedChannel = ChatChannel.mock(cid: selectedId)
+ channelListController.simulate(
+ channels: channels + [insertedChannel],
+ changes: [.insert(insertedChannel, index: IndexPath(item: 0, section: 0))]
+ )
+ // Resume synchronize()
+ chatClient.mockAPIClient.test_simulateResponse(.success(ChannelListPayload(channels: [])))
+
+ // Then
+ wait(for: [expectation], timeout: defaultTimeout)
+ cancellable.cancel()
+ }
// MARK: - private
diff --git a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_pollMessage_someoneVoted.1.png b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_pollMessage_someoneVoted.1.png
new file mode 100644
index 000000000..20ffe5d51
Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_pollMessage_someoneVoted.1.png differ
diff --git a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_pollMessage_youVoted.1.png b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_pollMessage_youVoted.1.png
new file mode 100644
index 000000000..f05304e7f
Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_pollMessage_youVoted.1.png differ
diff --git a/fastlane/Fastfile b/fastlane/Fastfile
index c4d53a098..240212be1 100644
--- a/fastlane/Fastfile
+++ b/fastlane/Fastfile
@@ -96,6 +96,11 @@ end
lane :merge_release do |options|
merge_release_to_main(author: options[:author])
+ sh('gh workflow run release-publish.yml --ref main')
+end
+
+lane :merge_main do
+ merge_main_to_develop
end
desc "Publish a new release to GitHub and CocoaPods"
@@ -121,8 +126,6 @@ lane :publish_release do |options|
)
update_spm(version: release_version)
-
- merge_main_to_develop
end
private_lane :appstore_api_key do
@@ -190,8 +193,10 @@ lane :test_ui do |options|
next if png_files.empty?
# Discard all files apart from the snapshots
- png_files.each { |png| sh("git add #{png}") || true }
- sh('git restore .')
+ Dir.chdir('..') do
+ png_files.each { |png| sh("git add #{png}") || true }
+ sh('git restore .')
+ end
pr_create(
title: '[CI] Snapshots',
diff --git a/fastlane/Pluginfile b/fastlane/Pluginfile
index 882e92bd4..3d5398c7c 100644
--- a/fastlane/Pluginfile
+++ b/fastlane/Pluginfile
@@ -5,4 +5,4 @@
gem 'fastlane-plugin-versioning'
gem 'fastlane-plugin-sonarcloud_metric_kit'
gem 'fastlane-plugin-create_xcframework'
-gem 'fastlane-plugin-stream_actions', '0.3.63'
+gem 'fastlane-plugin-stream_actions', '0.3.70'