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 @@

- StreamChatSwiftUI + StreamChatSwiftUI

## 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'