diff --git a/.github/workflows/sdk-size-metrics.yml b/.github/workflows/sdk-size-metrics.yml
index a05407b1c..e71245a9a 100644
--- a/.github/workflows/sdk-size-metrics.yml
+++ b/.github/workflows/sdk-size-metrics.yml
@@ -18,6 +18,7 @@ jobs:
runs-on: macos-15
env:
GITHUB_TOKEN: '${{ secrets.CI_BOT_GITHUB_TOKEN }}'
+ GITHUB_PR_NUM: ${{ github.event.pull_request.number }}
steps:
- name: Connect Bot
uses: webfactory/ssh-agent@v0.7.0
@@ -28,10 +29,13 @@ jobs:
- uses: ./.github/actions/bootstrap
- - name: Run SDK Size Metrics
+ - name: Run General SDK Size Metrics
run: bundle exec fastlane show_frameworks_sizes
timeout-minutes: 30
env:
- GITHUB_PR_NUM: ${{ github.event.pull_request.number }}
MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }}
APPSTORE_API_KEY: ${{ secrets.APPSTORE_API_KEY }}
+
+ - name: Run Detailed SDK Size Metrics
+ run: bundle exec fastlane size_analyze
+ timeout-minutes: 30
diff --git a/.gitignore b/.gitignore
index 45ae8d6e0..06ee34d3b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -100,6 +100,7 @@ App Thinning Size Report.txt
app-thinning.plist
*.dmg
yeetd-normal.pkg
+*LinkMap.txt
# VSCode
.vscode
diff --git a/.spi.yml b/.spi.yml
index c5dc1a7ca..201ffcb2f 100644
--- a/.spi.yml
+++ b/.spi.yml
@@ -4,4 +4,4 @@ builder:
- platform: ios
documentation_targets: [StreamChatSwiftUI]
scheme: StreamChatSwiftUI
- swift_version: 5.9
+ swift_version: '6.1'
diff --git a/.swiftformat b/.swiftformat
index 09b4ef180..d07296f9a 100644
--- a/.swiftformat
+++ b/.swiftformat
@@ -35,7 +35,7 @@
--rules redundantRawValues
--rules redundantVoidReturnType
--rules semicolons
---rules sortedImports
+--rules sortImports
--rules spaceAroundBraces
--rules spaceAroundBrackets
--rules spaceAroundComments
@@ -81,4 +81,4 @@
--wrapcollections before-first
# Exclude paths
---exclude Sources/StreamChatSwiftUI/Generated,Sources/StreamChatSwiftUI/StreamSwiftyGif,Sources/StreamChatSwiftUI/StreamNuke
+--exclude Sources/StreamChatSwiftUI/Generated,Sources/StreamChatSwiftUI/StreamSwiftyGif,Sources/StreamChatSwiftUI/StreamNuke,vendor/bundle,Pods,spm_cache,derived_data,.build
diff --git a/.swiftlint.yml b/.swiftlint.yml
index 6a5da8f1b..4020346bd 100644
--- a/.swiftlint.yml
+++ b/.swiftlint.yml
@@ -5,6 +5,7 @@ excluded:
- Sources/StreamChatSwiftUI/Generated
- Sources/StreamChatSwiftUI/StreamSwiftyGif
- Sources/StreamChatSwiftUI/StreamNuke
+ - vendor/bundle
only_rules:
- attribute_name_spacing
@@ -43,7 +44,6 @@ only_rules:
- trailing_comma
- trailing_newline
- trailing_semicolon
- - trailing_whitespace
- unneeded_break_in_switch
- unneeded_override
- unused_closure_parameter
@@ -55,8 +55,5 @@ only_rules:
multiline_arguments:
only_enforce_after_first_closure_on_first_line: true
-trailing_whitespace:
- ignores_empty_lines: true
-
file_name_no_space:
severity: error
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 139f0c9d2..5512f5bad 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,18 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
### 🔄 Changed
+# [4.91.0](https://github.com/GetStream/stream-chat-swiftui/releases/tag/4.91.0)
+_October 22, 2025_
+
+### ✅ Added
+- Add the `makeAttachmentTextView` method to ViewFactory [#1013](https://github.com/GetStream/stream-chat-swiftui/pull/1013)
+- Allow dismissing commands overlay when tapping the message list [#1024](https://github.com/GetStream/stream-chat-swiftui/pull/1024)
+- Allows dismissing the keyboard attachments picker when tapping the message list [#1024](https://github.com/GetStream/stream-chat-swiftui/pull/1024)
+### 🐞 Fixed
+- Fix composer not being locked after the channel was frozen [#1015](https://github.com/GetStream/stream-chat-swiftui/pull/1015)
+- Fix `PollOptionAllVotesView` not updated on poll cast events [#1025](https://github.com/GetStream/stream-chat-swiftui/pull/1025)
+- Fix action sheet not showing when discarding Poll creation on iOS 26 [#1027](https://github.com/GetStream/stream-chat-swiftui/pull/1027)
+
# [4.90.0](https://github.com/GetStream/stream-chat-swiftui/releases/tag/4.90.0)
_October 08, 2025_
diff --git a/Gemfile.lock b/Gemfile.lock
index 622ff78c3..300196b57 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -208,9 +208,11 @@ GEM
fastlane
pry
fastlane-plugin-sonarcloud_metric_kit (0.2.1)
- fastlane-plugin-stream_actions (0.3.90)
+ fastlane-plugin-stream_actions (0.3.101)
xctest_list (= 1.2.1)
fastlane-plugin-versioning (0.7.1)
+ fastlane-plugin-xcsize (1.1.0)
+ xcsize (= 1.1.0)
fastlane-sirp (1.0.0)
sysrandom (~> 1.0)
ffi (1.17.2)
@@ -283,7 +285,7 @@ GEM
molinillo (0.8.0)
multi_json (1.17.0)
multipart-post (2.4.1)
- mustermann (3.0.3)
+ mustermann (3.0.4)
ruby2_keywords (~> 0.0.1)
mutex_m (0.3.0)
nanaimo (0.4.0)
@@ -316,8 +318,8 @@ GEM
puma (6.6.1)
nio4r (~> 2.0)
racc (1.8.1)
- rack (3.2.0)
- rack-protection (4.1.1)
+ rack (3.2.3)
+ rack-protection (4.2.0)
base64 (>= 0.1.0)
logger (>= 1.6.0)
rack (>= 3.0.0, < 4)
@@ -372,11 +374,11 @@ GEM
simctl (1.6.10)
CFPropertyList
naturally
- sinatra (4.1.1)
+ sinatra (4.2.0)
logger (>= 1.6.0)
mustermann (~> 3.0)
rack (>= 3.0.0, < 4)
- rack-protection (= 4.1.1)
+ rack-protection (= 4.2.0)
rack-session (>= 2.0.0, < 3)
tilt (~> 2.0)
slather (2.8.5)
@@ -413,6 +415,8 @@ GEM
rouge (~> 3.28.0)
xcpretty-travis-formatter (1.0.1)
xcpretty (~> 0.2, >= 0.0.7)
+ xcsize (1.1.0)
+ commander (>= 4.6, < 6.0)
xctest_list (1.2.1)
PLATFORMS
@@ -426,8 +430,9 @@ DEPENDENCIES
fastlane-plugin-create_xcframework
fastlane-plugin-lizard
fastlane-plugin-sonarcloud_metric_kit
- fastlane-plugin-stream_actions (= 0.3.90)
+ fastlane-plugin-stream_actions (= 0.3.101)
fastlane-plugin-versioning
+ fastlane-plugin-xcsize (= 1.1.0)
json
lefthook
plist
diff --git a/Package.swift b/Package.swift
index 0e96f688f..aa0f4fefb 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.90.0")
+ .package(url: "https://github.com/GetStream/stream-chat-swift.git", from: "4.91.0")
],
targets: [
.target(
@@ -28,8 +28,6 @@ let package = Package(
]
)
-#if swift(>=5.6)
package.dependencies.append(
.package(url: "https://github.com/apple/swift-docc-plugin", from: "1.0.0")
)
-#endif
diff --git a/README.md b/README.md
index de473ce8d..8f3264061 100644
--- a/README.md
+++ b/README.md
@@ -5,7 +5,7 @@
-
+
## SwiftUI StreamChat SDK
diff --git a/Scripts/GenerateSPMFileLists.swift b/Scripts/GenerateSPMFileLists.swift
index e49785bc1..2debc37b2 100755
--- a/Scripts/GenerateSPMFileLists.swift
+++ b/Scripts/GenerateSPMFileLists.swift
@@ -34,7 +34,7 @@ func sourceFileList(at url: URL) -> [String] {
let basePathRange = path.range(of: url.path + "/")!
return String(path[basePathRange.upperBound...])
}
- .filter { $0.hasSuffix("_Tests.swift") || $0.hasSuffix("_Mock.swift") || $0.contains("__Snapshots__")}
+ .filter { $0.hasSuffix("_Tests.swift") || $0.hasSuffix("_Mock.swift") || $0.contains("__Snapshots__") }
return sourceFiles
}
@@ -59,8 +59,6 @@ newGeneratedContent += "] }\n"
newGeneratedContent += "\n"
-
-
// StreamChatUI excluded source files
let streamChatUIExcludedFiles = sourceFileList(at: URL(string: "Sources/StreamChatUI")!)
newGeneratedContent += "var streamChatUIFilesExcluded: [String] { [\n"
diff --git a/Sources/StreamChatSwiftUI/ChatChannel/ChatChannelView.swift b/Sources/StreamChatSwiftUI/ChatChannel/ChatChannelView.swift
index e01c6bb0d..47ff42773 100644
--- a/Sources/StreamChatSwiftUI/ChatChannel/ChatChannelView.swift
+++ b/Sources/StreamChatSwiftUI/ChatChannel/ChatChannelView.swift
@@ -73,6 +73,9 @@ public struct ChatChannelView: View, KeyboardReadable {
},
onJumpToMessage: viewModel.jumpToMessage(messageId:)
)
+ .dismissKeyboardOnTap(enabled: true) {
+ hideComposerCommandsAndAttachmentsPicker()
+ }
.overlay(
viewModel.currentDateString != nil ?
factory.makeDateIndicatorView(dateString: viewModel.currentDateString!)
@@ -81,7 +84,9 @@ public struct ChatChannelView: View, KeyboardReadable {
} else {
ZStack {
factory.makeEmptyMessagesView(for: channel, colors: colors)
- .dismissKeyboardOnTap(enabled: keyboardShown)
+ .dismissKeyboardOnTap(enabled: keyboardShown) {
+ hideComposerCommandsAndAttachmentsPicker()
+ }
if viewModel.shouldShowTypingIndicator {
factory.makeTypingIndicatorBottomView(
channel: channel,
@@ -183,13 +188,6 @@ public struct ChatChannelView: View, KeyboardReadable {
viewModel.reactionsShown = false
messageDisplayInfo = nil
}
- .onChange(of: presentationMode.wrappedValue, perform: { newValue in
- if newValue.isPresented == false {
- viewModel.onViewDissappear()
- } else {
- viewModel.setActive()
- }
- })
.background(
Color(colors.background).background(
TabBarAccessor { _ in
@@ -220,10 +218,13 @@ public struct ChatChannelView: View, KeyboardReadable {
let bottomPadding = topVC()?.view.safeAreaInsets.bottom ?? 0
return bottomPadding
}
-}
-extension PresentationMode: Equatable {
- public static func == (lhs: PresentationMode, rhs: PresentationMode) -> Bool {
- lhs.isPresented == rhs.isPresented
+ private func hideComposerCommandsAndAttachmentsPicker() {
+ NotificationCenter.default.post(
+ name: .attachmentPickerHiddenNotification, object: nil
+ )
+ NotificationCenter.default.post(
+ name: .commandsOverlayHiddenNotification, object: nil
+ )
}
}
diff --git a/Sources/StreamChatSwiftUI/ChatChannel/Composer/AttachmentPickerTypeView.swift b/Sources/StreamChatSwiftUI/ChatChannel/Composer/AttachmentPickerTypeView.swift
index 9e0c09947..a021e153e 100644
--- a/Sources/StreamChatSwiftUI/ChatChannel/Composer/AttachmentPickerTypeView.swift
+++ b/Sources/StreamChatSwiftUI/ChatChannel/Composer/AttachmentPickerTypeView.swift
@@ -50,7 +50,7 @@ public struct AttachmentPickerTypeView: View {
HStack(spacing: 16) {
switch pickerTypeState {
case let .expanded(attachmentPickerType):
- if composerViewModel.channelController.channel?.canUploadFile == true {
+ if composerViewModel.channelController.channel?.canUploadFile == true && composerViewModel.isSendMessageEnabled {
PickerTypeButton(
pickerTypeState: $pickerTypeState,
pickerType: .media,
@@ -60,7 +60,7 @@ public struct AttachmentPickerTypeView: View {
.accessibilityIdentifier("PickerTypeButtonMedia")
}
- if commandsAvailable {
+ if commandsAvailable && composerViewModel.isSendMessageEnabled {
PickerTypeButton(
pickerTypeState: $pickerTypeState,
pickerType: .instantCommands,
@@ -70,16 +70,18 @@ public struct AttachmentPickerTypeView: View {
.accessibilityIdentifier("PickerTypeButtonCommands")
}
case .collapsed:
- Button {
- withAnimation {
- pickerTypeState = .expanded(.none)
+ if composerViewModel.isSendMessageEnabled {
+ Button {
+ withAnimation {
+ pickerTypeState = .expanded(.none)
+ }
+ } label: {
+ Image(uiImage: images.shrinkInputArrow)
+ .renderingMode(.template)
+ .foregroundColor(Color(colors.highlightedAccentBackground))
}
- } label: {
- Image(uiImage: images.shrinkInputArrow)
- .renderingMode(.template)
- .foregroundColor(Color(colors.highlightedAccentBackground))
+ .accessibilityIdentifier("PickerTypeButtonCollapsed")
}
- .accessibilityIdentifier("PickerTypeButtonCollapsed")
}
}
.accessibilityElement(children: .contain)
diff --git a/Sources/StreamChatSwiftUI/ChatChannel/Composer/MessageComposerView.swift b/Sources/StreamChatSwiftUI/ChatChannel/Composer/MessageComposerView.swift
index eb598176f..c4712a21d 100644
--- a/Sources/StreamChatSwiftUI/ChatChannel/Composer/MessageComposerView.swift
+++ b/Sources/StreamChatSwiftUI/ChatChannel/Composer/MessageComposerView.swift
@@ -9,6 +9,7 @@ import SwiftUI
public struct MessageComposerView: View, KeyboardReadable {
@Injected(\.colors) private var colors
@Injected(\.fonts) private var fonts
+ @Injected(\.utils) private var utils
// Initial popup size, before the keyboard is shown.
@State private var popupSize: CGFloat = 350
@@ -228,6 +229,18 @@ public struct MessageComposerView: View, KeyboardReadable
viewModel.updateDraftMessage(quotedMessage: quotedMessage)
}
})
+ .onReceive(NotificationCenter.default.publisher(for: .commandsOverlayHiddenNotification)) { _ in
+ guard utils.messageListConfig.hidesCommandsOverlayOnMessageListTap else {
+ return
+ }
+ viewModel.composerCommand = nil
+ }
+ .onReceive(NotificationCenter.default.publisher(for: .attachmentPickerHiddenNotification)) { _ in
+ guard utils.messageListConfig.hidesAttachmentsPickersOnMessageListTap else {
+ return
+ }
+ viewModel.pickerTypeState = .expanded(.none)
+ }
.accessibilityElement(children: .contain)
}
}
@@ -375,8 +388,8 @@ public struct ComposerInputView: View, KeyboardReadable {
text: $text,
height: $textHeight,
selectedRangeLocation: $selectedRangeLocation,
- placeholder: isInCooldown ? L10n.Composer.Placeholder.slowMode : L10n.Composer.Placeholder.message,
- editable: !isInCooldown,
+ placeholder: isInCooldown ? L10n.Composer.Placeholder.slowMode : (isChannelFrozen ? L10n.Composer.Placeholder.messageDisabled : L10n.Composer.Placeholder.message),
+ editable: !isInputDisabled,
maxMessageLength: maxMessageLength,
currentHeight: textFieldHeight
)
@@ -435,4 +448,22 @@ public struct ComposerInputView: View, KeyboardReadable {
private var isInCooldown: Bool {
cooldownDuration > 0
}
+
+ private var isChannelFrozen: Bool {
+ !viewModel.isSendMessageEnabled
+ }
+
+ private var isInputDisabled: Bool {
+ isInCooldown || isChannelFrozen
+ }
+}
+
+// MARK: - Notification Names
+
+extension Notification.Name {
+ /// Notification sent when the attachments picker should be hidden.
+ static let attachmentPickerHiddenNotification = Notification.Name("attachmentPickerHiddenNotification")
+
+ /// Notification sent when the commands overlay should be hidden.
+ static let commandsOverlayHiddenNotification = Notification.Name("commandsOverlayHiddenNotification")
}
diff --git a/Sources/StreamChatSwiftUI/ChatChannel/Composer/MessageComposerViewModel.swift b/Sources/StreamChatSwiftUI/ChatChannel/Composer/MessageComposerViewModel.swift
index 8c2afd6c2..48e1b1058 100644
--- a/Sources/StreamChatSwiftUI/ChatChannel/Composer/MessageComposerViewModel.swift
+++ b/Sources/StreamChatSwiftUI/ChatChannel/Composer/MessageComposerViewModel.swift
@@ -444,6 +444,11 @@ open class MessageComposerViewModel: ObservableObject {
}
}
+ /// A Boolean value indicating whether sending message is enabled.
+ public var isSendMessageEnabled: Bool {
+ channelController.channel?.canSendMessage ?? true
+ }
+
public var sendButtonEnabled: Bool {
if let composerCommand = composerCommand,
let handler = commandsHandler.commandHandler(for: composerCommand) {
diff --git a/Sources/StreamChatSwiftUI/ChatChannel/Composer/TrailingComposerView.swift b/Sources/StreamChatSwiftUI/ChatChannel/Composer/TrailingComposerView.swift
index 817f31710..7bd1621fc 100644
--- a/Sources/StreamChatSwiftUI/ChatChannel/Composer/TrailingComposerView.swift
+++ b/Sources/StreamChatSwiftUI/ChatChannel/Composer/TrailingComposerView.swift
@@ -17,7 +17,7 @@ public struct TrailingComposerView: View {
public var body: some View {
Group {
- if viewModel.cooldownDuration == 0 {
+ if viewModel.cooldownDuration == 0 && viewModel.isSendMessageEnabled {
HStack(spacing: 16) {
SendMessageButton(
enabled: viewModel.sendButtonEnabled,
@@ -28,7 +28,7 @@ public struct TrailingComposerView: View {
}
}
.padding(.bottom, 8)
- } else {
+ } else if viewModel.cooldownDuration > 0 {
SlowModeView(
cooldownDuration: viewModel.cooldownDuration
)
diff --git a/Sources/StreamChatSwiftUI/ChatChannel/MessageList/AsyncVoiceMessages/VoiceRecordingContainerView.swift b/Sources/StreamChatSwiftUI/ChatChannel/MessageList/AsyncVoiceMessages/VoiceRecordingContainerView.swift
index 5c4854acf..032941ed8 100644
--- a/Sources/StreamChatSwiftUI/ChatChannel/MessageList/AsyncVoiceMessages/VoiceRecordingContainerView.swift
+++ b/Sources/StreamChatSwiftUI/ChatChannel/MessageList/AsyncVoiceMessages/VoiceRecordingContainerView.swift
@@ -67,7 +67,7 @@ public struct VoiceRecordingContainerView: View {
}
}
if !message.text.isEmpty {
- AttachmentTextView(message: message)
+ AttachmentTextView(factory: factory, message: message)
.frame(maxWidth: .infinity)
}
}
diff --git a/Sources/StreamChatSwiftUI/ChatChannel/MessageList/ImageAttachmentView.swift b/Sources/StreamChatSwiftUI/ChatChannel/MessageList/ImageAttachmentView.swift
index 7a0aa7812..3ebeb57e5 100644
--- a/Sources/StreamChatSwiftUI/ChatChannel/MessageList/ImageAttachmentView.swift
+++ b/Sources/StreamChatSwiftUI/ChatChannel/MessageList/ImageAttachmentView.swift
@@ -47,7 +47,7 @@ public struct ImageAttachmentContainer: View {
}
if !message.text.isEmpty {
- AttachmentTextView(message: message)
+ AttachmentTextView(factory: factory, message: message)
.frame(width: width)
}
}
@@ -93,21 +93,23 @@ public struct ImageAttachmentContainer: View {
}
}
-public struct AttachmentTextView: View {
+public struct AttachmentTextView: View {
@Injected(\.colors) private var colors
@Injected(\.fonts) private var fonts
+ var factory: Factory
var message: ChatMessage
let injectedBackgroundColor: UIColor?
- public init(message: ChatMessage, injectedBackgroundColor: UIColor? = nil) {
+ public init(factory: Factory = DefaultViewFactory.shared, message: ChatMessage, injectedBackgroundColor: UIColor? = nil) {
+ self.factory = factory
self.message = message
self.injectedBackgroundColor = injectedBackgroundColor
}
public var body: some View {
HStack {
- StreamTextView(message: message)
+ factory.makeAttachmentTextView(options: .init(mesage: message))
.standardPadding()
.fixedSize(horizontal: false, vertical: true)
Spacer()
diff --git a/Sources/StreamChatSwiftUI/ChatChannel/MessageList/LinkAttachmentView.swift b/Sources/StreamChatSwiftUI/ChatChannel/MessageList/LinkAttachmentView.swift
index 47208901e..2e1dab237 100644
--- a/Sources/StreamChatSwiftUI/ChatChannel/MessageList/LinkAttachmentView.swift
+++ b/Sources/StreamChatSwiftUI/ChatChannel/MessageList/LinkAttachmentView.swift
@@ -51,7 +51,7 @@ public struct LinkAttachmentContainer: View {
if #available(iOS 15, *) {
HStack {
- StreamTextView(message: message)
+ factory.makeAttachmentTextView(options: .init(mesage: message))
.standardPadding()
Spacer()
}
diff --git a/Sources/StreamChatSwiftUI/ChatChannel/MessageList/MessageListConfig.swift b/Sources/StreamChatSwiftUI/ChatChannel/MessageList/MessageListConfig.swift
index e0dba4bcf..b03d85500 100644
--- a/Sources/StreamChatSwiftUI/ChatChannel/MessageList/MessageListConfig.swift
+++ b/Sources/StreamChatSwiftUI/ChatChannel/MessageList/MessageListConfig.swift
@@ -36,7 +36,9 @@ public struct MessageListConfig {
bouncedMessagesAlertActionsEnabled: Bool = true,
skipEditedMessageLabel: @escaping (ChatMessage) -> Bool = { _ in false },
draftMessagesEnabled: Bool = false,
- downloadFileAttachmentsEnabled: Bool = false
+ downloadFileAttachmentsEnabled: Bool = false,
+ hidesCommandsOverlayOnMessageListTap: Bool = true,
+ hidesAttachmentsPickersOnMessageListTap: Bool = true
) {
self.messageListType = messageListType
self.typingIndicatorPlacement = typingIndicatorPlacement
@@ -66,6 +68,8 @@ public struct MessageListConfig {
self.skipEditedMessageLabel = skipEditedMessageLabel
self.draftMessagesEnabled = draftMessagesEnabled
self.downloadFileAttachmentsEnabled = downloadFileAttachmentsEnabled
+ self.hidesCommandsOverlayOnMessageListTap = hidesCommandsOverlayOnMessageListTap
+ self.hidesAttachmentsPickersOnMessageListTap = hidesAttachmentsPickersOnMessageListTap
}
public let messageListType: MessageListType
@@ -93,6 +97,16 @@ public struct MessageListConfig {
public let markdownSupportEnabled: Bool
public let userBlockingEnabled: Bool
+ /// A boolean to enable hiding the commands overlay when tapping the message list.
+ ///
+ /// It is enabled by default.
+ public let hidesCommandsOverlayOnMessageListTap: Bool
+
+ /// A boolean to enable hiding the attachments keyboard picker when tapping the message list.
+ ///
+ /// It is enabled by default.
+ public let hidesAttachmentsPickersOnMessageListTap: Bool
+
/// A boolean to enable the alert actions for bounced messages.
///
/// By default it is true and the bounced actions are displayed as an alert instead of a context menu.
diff --git a/Sources/StreamChatSwiftUI/ChatChannel/MessageList/MessageListView.swift b/Sources/StreamChatSwiftUI/ChatChannel/MessageList/MessageListView.swift
index 0696eeb7e..2bfe8a96b 100644
--- a/Sources/StreamChatSwiftUI/ChatChannel/MessageList/MessageListView.swift
+++ b/Sources/StreamChatSwiftUI/ChatChannel/MessageList/MessageListView.swift
@@ -313,7 +313,6 @@ public struct MessageListView: View, KeyboardReadable {
) : nil
)
.modifier(factory.makeMessageListContainerModifier())
- .dismissKeyboardOnTap(enabled: keyboardShown)
.onDisappear {
messageRenderingUtil.update(previousTopMessage: nil)
}
diff --git a/Sources/StreamChatSwiftUI/ChatChannel/MessageList/MessageView.swift b/Sources/StreamChatSwiftUI/ChatChannel/MessageList/MessageView.swift
index b1c32f094..433b48735 100644
--- a/Sources/StreamChatSwiftUI/ChatChannel/MessageList/MessageView.swift
+++ b/Sources/StreamChatSwiftUI/ChatChannel/MessageList/MessageView.swift
@@ -167,7 +167,7 @@ public struct MessageTextView: View {
)
}
- StreamTextView(message: message)
+ factory.makeAttachmentTextView(options: .init(mesage: message))
.padding(.leading, leadingPadding)
.padding(.trailing, trailingPadding)
.padding(.top, topPadding)
@@ -247,6 +247,16 @@ struct StreamTextView: View {
}
}
+// Options for the attachment text view.
+public class AttachmentTextViewOptions {
+ // The message to display the text for.
+ public let message: ChatMessage
+
+ public init(mesage: ChatMessage) {
+ self.message = mesage
+ }
+}
+
@available(iOS 15, *)
public struct LinkDetectionTextView: View {
@Environment(\.layoutDirection) var layoutDirection
diff --git a/Sources/StreamChatSwiftUI/ChatChannel/MessageList/Polls/PollOptionAllVotesViewModel.swift b/Sources/StreamChatSwiftUI/ChatChannel/MessageList/Polls/PollOptionAllVotesViewModel.swift
index aeba9bf45..fb85a6a53 100644
--- a/Sources/StreamChatSwiftUI/ChatChannel/MessageList/Polls/PollOptionAllVotesViewModel.swift
+++ b/Sources/StreamChatSwiftUI/ChatChannel/MessageList/Polls/PollOptionAllVotesViewModel.swift
@@ -7,10 +7,10 @@ import StreamChat
import SwiftUI
class PollOptionAllVotesViewModel: ObservableObject, PollVoteListControllerDelegate {
- let poll: Poll
let option: PollOption
let controller: PollVoteListController
-
+
+ @Published var poll: Poll
@Published var pollVotes = [PollVote]()
@Published var errorShown = false
@@ -70,7 +70,11 @@ class PollOptionAllVotesViewModel: ObservableObject, PollVoteListControllerDeleg
pollVotes = Array(controller.votes)
}
}
-
+
+ func controller(_ controller: PollVoteListController, didUpdatePoll poll: Poll) {
+ self.poll = poll
+ }
+
private func loadVotes() {
loadingVotes = true
diff --git a/Sources/StreamChatSwiftUI/ChatChannel/MessageList/VideoAttachmentView.swift b/Sources/StreamChatSwiftUI/ChatChannel/MessageList/VideoAttachmentView.swift
index 7cc4e217b..ba458830a 100644
--- a/Sources/StreamChatSwiftUI/ChatChannel/MessageList/VideoAttachmentView.swift
+++ b/Sources/StreamChatSwiftUI/ChatChannel/MessageList/VideoAttachmentView.swift
@@ -46,7 +46,7 @@ public struct VideoAttachmentsContainer: View {
}
if !message.text.isEmpty {
- AttachmentTextView(message: message)
+ AttachmentTextView(factory: factory, message: message)
.frame(width: width)
}
}
diff --git a/Sources/StreamChatSwiftUI/ChatChannel/Polls/CreatePollView.swift b/Sources/StreamChatSwiftUI/ChatChannel/Polls/CreatePollView.swift
index be7a180eb..8064166d6 100644
--- a/Sources/StreamChatSwiftUI/ChatChannel/Polls/CreatePollView.swift
+++ b/Sources/StreamChatSwiftUI/ChatChannel/Polls/CreatePollView.swift
@@ -175,6 +175,17 @@ public struct CreatePollView: View {
} label: {
Text(L10n.Alert.Actions.cancel)
}
+ .actionSheet(isPresented: $viewModel.discardConfirmationShown) {
+ ActionSheet(
+ title: Text(L10n.Composer.Polls.actionSheetDiscardTitle),
+ buttons: [
+ .destructive(Text(L10n.Alert.Actions.discardChanges)) {
+ presentationMode.wrappedValue.dismiss()
+ },
+ .default(Text(L10n.Alert.Actions.keepEditing))
+ ]
+ )
+ }
}
ToolbarItem(placement: .principal) {
@@ -195,17 +206,6 @@ public struct CreatePollView: View {
}
}
.navigationBarTitleDisplayMode(.inline)
- .actionSheet(isPresented: $viewModel.discardConfirmationShown) {
- ActionSheet(
- title: Text(L10n.Composer.Polls.actionSheetDiscardTitle),
- buttons: [
- .destructive(Text(L10n.Alert.Actions.discardChanges)) {
- presentationMode.wrappedValue.dismiss()
- },
- .cancel(Text(L10n.Alert.Actions.keepEditing))
- ]
- )
- }
.alert(isPresented: $viewModel.errorShown) {
Alert.defaultErrorAlert
}
diff --git a/Sources/StreamChatSwiftUI/DefaultViewFactory.swift b/Sources/StreamChatSwiftUI/DefaultViewFactory.swift
index b238a265d..3d881999f 100644
--- a/Sources/StreamChatSwiftUI/DefaultViewFactory.swift
+++ b/Sources/StreamChatSwiftUI/DefaultViewFactory.swift
@@ -1151,6 +1151,12 @@ extension ViewFactory {
) -> some View {
AddUsersView(loadedUserIds: options.loadedUsers.map(\.id), onUserTap: onUserTap)
}
+
+ public func makeAttachmentTextView(
+ options: AttachmentTextViewOptions
+ ) -> some View {
+ StreamTextView(message: options.message)
+ }
}
/// Default class conforming to `ViewFactory`, used throughout the SDK.
diff --git a/Sources/StreamChatSwiftUI/Generated/L10n.swift b/Sources/StreamChatSwiftUI/Generated/L10n.swift
index 79a7dddf7..9c4dcf11c 100644
--- a/Sources/StreamChatSwiftUI/Generated/L10n.swift
+++ b/Sources/StreamChatSwiftUI/Generated/L10n.swift
@@ -257,6 +257,8 @@ internal enum L10n {
internal static var giphy: String { L10n.tr("Localizable", "composer.placeholder.giphy") }
/// Send a message
internal static var message: String { L10n.tr("Localizable", "composer.placeholder.message") }
+ /// You can't send messages in this channel
+ internal static var messageDisabled: String { L10n.tr("Localizable", "composer.placeholder.messageDisabled") }
/// Slow mode ON
internal static var slowMode: String { L10n.tr("Localizable", "composer.placeholder.slow-mode") }
}
diff --git a/Sources/StreamChatSwiftUI/Generated/SystemEnvironment+Version.swift b/Sources/StreamChatSwiftUI/Generated/SystemEnvironment+Version.swift
index b97f1f3b2..a5c3c79c9 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.90.0"
+ public static let version: String = "4.91.0"
}
diff --git a/Sources/StreamChatSwiftUI/Info.plist b/Sources/StreamChatSwiftUI/Info.plist
index eca9a0a57..268afdcca 100644
--- a/Sources/StreamChatSwiftUI/Info.plist
+++ b/Sources/StreamChatSwiftUI/Info.plist
@@ -15,7 +15,7 @@
CFBundlePackageType
$(PRODUCT_BUNDLE_PACKAGE_TYPE)
CFBundleShortVersionString
- 4.90.0
+ 4.91.0
CFBundleVersion
$(CURRENT_PROJECT_VERSION)
NSPhotoLibraryUsageDescription
diff --git a/Sources/StreamChatSwiftUI/Resources/en.lproj/Localizable.strings b/Sources/StreamChatSwiftUI/Resources/en.lproj/Localizable.strings
index 7ac2913f6..619e24b32 100644
--- a/Sources/StreamChatSwiftUI/Resources/en.lproj/Localizable.strings
+++ b/Sources/StreamChatSwiftUI/Resources/en.lproj/Localizable.strings
@@ -121,6 +121,7 @@
"composer.title.edit" = "Edit Message";
"composer.title.reply" = "Reply to Message";
"composer.placeholder.message" = "Send a message";
+"composer.placeholder.messageDisabled" = "You can't send messages in this channel";
"composer.placeholder.slow-mode" = "Slow mode ON";
"composer.placeholder.giphy" = "Search GIFs";
"composer.checkmark.direct-message-reply" = "Also send as direct message";
diff --git a/Sources/StreamChatSwiftUI/Utils/KeyboardHandling.swift b/Sources/StreamChatSwiftUI/Utils/KeyboardHandling.swift
index ec483dbff..5a21e9dc8 100644
--- a/Sources/StreamChatSwiftUI/Utils/KeyboardHandling.swift
+++ b/Sources/StreamChatSwiftUI/Utils/KeyboardHandling.swift
@@ -63,7 +63,7 @@ extension View {
/// - enabled: If true, tapping on the view dismisses the view, otherwise keyboard stays visible.
/// - onTapped: A closure which is triggered when keyboard is dismissed after tapping the view.
func dismissKeyboardOnTap(enabled: Bool, onKeyboardDismissed: (() -> Void)? = nil) -> some View {
- modifier(HideKeyboardOnTapGesture(shouldAdd: enabled))
+ modifier(HideKeyboardOnTapGesture(shouldAdd: enabled, onTapped: onKeyboardDismissed))
}
}
diff --git a/Sources/StreamChatSwiftUI/ViewFactory.swift b/Sources/StreamChatSwiftUI/ViewFactory.swift
index 9c7465737..0439b8d19 100644
--- a/Sources/StreamChatSwiftUI/ViewFactory.swift
+++ b/Sources/StreamChatSwiftUI/ViewFactory.swift
@@ -1182,4 +1182,12 @@ public protocol ViewFactory: AnyObject {
options: AddUsersOptions,
onUserTap: @escaping (ChatUser) -> Void
) -> AddUsersViewType
+
+ associatedtype AttachmentTextViewType: View
+ /// Creates a view for displaying the text of an attachment.
+ /// - Parameter options: Configuration options for the attachment text view, such as message.
+ /// - Returns: The view shown in the attachment text slot.
+ func makeAttachmentTextView(
+ options: AttachmentTextViewOptions
+ ) -> AttachmentTextViewType
}
diff --git a/StreamChatSwiftUI-XCFramework.podspec b/StreamChatSwiftUI-XCFramework.podspec
index 75dfae9b1..6d88ce8d5 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.90.0'
+ spec.version = '4.91.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.90.0'
+ spec.dependency 'StreamChat-XCFramework', '~> 4.91.0'
spec.cocoapods_version = '>= 1.11.0'
end
diff --git a/StreamChatSwiftUI.podspec b/StreamChatSwiftUI.podspec
index 0d1ce08e2..e8cd2f445 100644
--- a/StreamChatSwiftUI.podspec
+++ b/StreamChatSwiftUI.podspec
@@ -1,6 +1,6 @@
Pod::Spec.new do |spec|
spec.name = 'StreamChatSwiftUI'
- spec.version = '4.90.0'
+ spec.version = '4.91.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.90.0'
+ spec.dependency 'StreamChat', '~> 4.91.0'
end
diff --git a/StreamChatSwiftUI.xcodeproj/project.pbxproj b/StreamChatSwiftUI.xcodeproj/project.pbxproj
index a87a019fb..904fe0c47 100644
--- a/StreamChatSwiftUI.xcodeproj/project.pbxproj
+++ b/StreamChatSwiftUI.xcodeproj/project.pbxproj
@@ -3296,6 +3296,8 @@
INFOPLIST_KEY_NSHumanReadableCopyright = "";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
+ LD_GENERATE_MAP_FILE = YES;
+ LD_MAP_FILE_PATH = "linkmaps/$(PRODUCT_NAME)-$(CURRENT_ARCH)-LinkMap.txt";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
@@ -3674,6 +3676,8 @@
INFOPLIST_KEY_NSHumanReadableCopyright = "";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
+ LD_GENERATE_MAP_FILE = YES;
+ LD_MAP_FILE_PATH = "linkmaps/$(PRODUCT_NAME)-$(CURRENT_ARCH)-LinkMap.txt";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
@@ -3709,6 +3713,8 @@
INFOPLIST_KEY_NSHumanReadableCopyright = "";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
+ LD_GENERATE_MAP_FILE = YES;
+ LD_MAP_FILE_PATH = "linkmaps/$(PRODUCT_NAME)-$(CURRENT_ARCH)-LinkMap.txt";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
@@ -3940,7 +3946,7 @@
repositoryURL = "https://github.com/GetStream/stream-chat-swift.git";
requirement = {
kind = upToNextMajorVersion;
- minimumVersion = 4.90.0;
+ minimumVersion = 4.91.0;
};
};
E3A1C01A282BAC66002D1E26 /* XCRemoteSwiftPackageReference "sentry-cocoa" */ = {
diff --git a/StreamChatSwiftUIArtifacts.json b/StreamChatSwiftUIArtifacts.json
index 212e8b2ec..84875efd1 100644
--- a/StreamChatSwiftUIArtifacts.json
+++ b/StreamChatSwiftUIArtifacts.json
@@ -1 +1 @@
-{"4.40.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.40.0/StreamChatSwiftUI.zip","4.41.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.41.0/StreamChatSwiftUI.zip","4.42.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.42.0/StreamChatSwiftUI.zip","4.43.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.43.0/StreamChatSwiftUI.zip","4.44.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.44.0/StreamChatSwiftUI.zip","4.45.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.45.0/StreamChatSwiftUI.zip","4.46.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.46.0/StreamChatSwiftUI.zip","4.47.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.47.0/StreamChatSwiftUI.zip","4.47.1":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.47.1/StreamChatSwiftUI.zip","4.48.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.48.0/StreamChatSwiftUI.zip","4.49.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.49.0/StreamChatSwiftUI.zip","4.50.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.50.0/StreamChatSwiftUI.zip","4.50.1":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.50.1/StreamChatSwiftUI.zip","4.51.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.51.0/StreamChatSwiftUI.zip","4.52.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.52.0/StreamChatSwiftUI.zip","4.53.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.53.0/StreamChatSwiftUI.zip","4.54.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.54.0/StreamChatSwiftUI.zip","4.55.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.55.0/StreamChatSwiftUI.zip","4.56.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.56.0/StreamChatSwiftUI.zip","4.57.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.57.0/StreamChatSwiftUI.zip","4.58.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.58.0/StreamChatSwiftUI.zip","4.59.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.59.0/StreamChatSwiftUI.zip","4.60.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.60.0/StreamChatSwiftUI.zip","4.61.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.61.0/StreamChatSwiftUI.zip","4.62.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.62.0/StreamChatSwiftUI.zip","4.63.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.63.0/StreamChatSwiftUI.zip","4.64.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.64.0/StreamChatSwiftUI.zip","4.65.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.65.0/StreamChatSwiftUI.zip","4.66.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.66.0/StreamChatSwiftUI.zip","4.67.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.67.0/StreamChatSwiftUI.zip","4.68.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.68.0/StreamChatSwiftUI.zip","4.69.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.69.0/StreamChatSwiftUI.zip","4.70.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.70.0/StreamChatSwiftUI.zip","4.71.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.71.0/StreamChatSwiftUI.zip","4.72.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.72.0/StreamChatSwiftUI.zip","4.73.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.73.0/StreamChatSwiftUI.zip","4.74.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.74.0/StreamChatSwiftUI.zip","4.75.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.75.0/StreamChatSwiftUI.zip","4.76.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.76.0/StreamChatSwiftUI.zip","4.77.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.77.0/StreamChatSwiftUI.zip","4.78.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.78.0/StreamChatSwiftUI.zip","4.79.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.79.0/StreamChatSwiftUI.zip","4.79.1":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.79.1/StreamChatSwiftUI.zip","4.80.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.80.0/StreamChatSwiftUI.zip","4.81.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.81.0/StreamChatSwiftUI.zip","4.82.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.82.0/StreamChatSwiftUI.zip","4.83.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.83.0/StreamChatSwiftUI.zip","4.84.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.84.0/StreamChatSwiftUI.zip","4.85.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.85.0/StreamChatSwiftUI.zip","4.86.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.86.0/StreamChatSwiftUI.zip","4.87.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.87.0/StreamChatSwiftUI.zip","4.88.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.88.0/StreamChatSwiftUI.zip","4.89.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.89.0/StreamChatSwiftUI.zip","4.89.1":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.89.1/StreamChatSwiftUI.zip","4.90.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.90.0/StreamChatSwiftUI.zip"}
\ No newline at end of file
+{"4.40.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.40.0/StreamChatSwiftUI.zip","4.41.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.41.0/StreamChatSwiftUI.zip","4.42.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.42.0/StreamChatSwiftUI.zip","4.43.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.43.0/StreamChatSwiftUI.zip","4.44.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.44.0/StreamChatSwiftUI.zip","4.45.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.45.0/StreamChatSwiftUI.zip","4.46.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.46.0/StreamChatSwiftUI.zip","4.47.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.47.0/StreamChatSwiftUI.zip","4.47.1":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.47.1/StreamChatSwiftUI.zip","4.48.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.48.0/StreamChatSwiftUI.zip","4.49.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.49.0/StreamChatSwiftUI.zip","4.50.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.50.0/StreamChatSwiftUI.zip","4.50.1":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.50.1/StreamChatSwiftUI.zip","4.51.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.51.0/StreamChatSwiftUI.zip","4.52.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.52.0/StreamChatSwiftUI.zip","4.53.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.53.0/StreamChatSwiftUI.zip","4.54.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.54.0/StreamChatSwiftUI.zip","4.55.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.55.0/StreamChatSwiftUI.zip","4.56.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.56.0/StreamChatSwiftUI.zip","4.57.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.57.0/StreamChatSwiftUI.zip","4.58.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.58.0/StreamChatSwiftUI.zip","4.59.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.59.0/StreamChatSwiftUI.zip","4.60.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.60.0/StreamChatSwiftUI.zip","4.61.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.61.0/StreamChatSwiftUI.zip","4.62.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.62.0/StreamChatSwiftUI.zip","4.63.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.63.0/StreamChatSwiftUI.zip","4.64.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.64.0/StreamChatSwiftUI.zip","4.65.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.65.0/StreamChatSwiftUI.zip","4.66.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.66.0/StreamChatSwiftUI.zip","4.67.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.67.0/StreamChatSwiftUI.zip","4.68.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.68.0/StreamChatSwiftUI.zip","4.69.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.69.0/StreamChatSwiftUI.zip","4.70.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.70.0/StreamChatSwiftUI.zip","4.71.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.71.0/StreamChatSwiftUI.zip","4.72.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.72.0/StreamChatSwiftUI.zip","4.73.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.73.0/StreamChatSwiftUI.zip","4.74.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.74.0/StreamChatSwiftUI.zip","4.75.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.75.0/StreamChatSwiftUI.zip","4.76.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.76.0/StreamChatSwiftUI.zip","4.77.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.77.0/StreamChatSwiftUI.zip","4.78.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.78.0/StreamChatSwiftUI.zip","4.79.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.79.0/StreamChatSwiftUI.zip","4.79.1":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.79.1/StreamChatSwiftUI.zip","4.80.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.80.0/StreamChatSwiftUI.zip","4.81.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.81.0/StreamChatSwiftUI.zip","4.82.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.82.0/StreamChatSwiftUI.zip","4.83.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.83.0/StreamChatSwiftUI.zip","4.84.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.84.0/StreamChatSwiftUI.zip","4.85.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.85.0/StreamChatSwiftUI.zip","4.86.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.86.0/StreamChatSwiftUI.zip","4.87.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.87.0/StreamChatSwiftUI.zip","4.88.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.88.0/StreamChatSwiftUI.zip","4.89.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.89.0/StreamChatSwiftUI.zip","4.89.1":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.89.1/StreamChatSwiftUI.zip","4.90.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.90.0/StreamChatSwiftUI.zip","4.91.0":"https://github.com/GetStream/stream-chat-swiftui/releases/download/4.91.0/StreamChatSwiftUI.zip"}
\ No newline at end of file
diff --git a/StreamChatSwiftUITests/Infrastructure/TestTools/ViewFrameUtils.swift b/StreamChatSwiftUITests/Infrastructure/TestTools/ViewFrameUtils.swift
index c9186bbe6..77a7130d6 100644
--- a/StreamChatSwiftUITests/Infrastructure/TestTools/ViewFrameUtils.swift
+++ b/StreamChatSwiftUITests/Infrastructure/TestTools/ViewFrameUtils.swift
@@ -15,4 +15,15 @@ extension View {
func applySize(_ size: CGSize) -> some View {
frame(width: size.width, height: size.height)
}
+
+ @discardableResult
+ /// Add SwiftUI View to a fake hierarchy so that it can receive UI events.
+ func addToViewHierarchy() -> some View {
+ let window = UIWindow(frame: CGRect(x: 0, y: 0, width: 400, height: 400))
+ let hostingController = UIHostingController(rootView: self)
+ window.rootViewController = hostingController
+ window.makeKeyAndVisible()
+ hostingController.view.layoutIfNeeded()
+ return self
+ }
}
diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChatChannelTestHelpers.swift b/StreamChatSwiftUITests/Tests/ChatChannel/ChatChannelTestHelpers.swift
index 8b8183048..05926d9a6 100644
--- a/StreamChatSwiftUITests/Tests/ChatChannel/ChatChannelTestHelpers.swift
+++ b/StreamChatSwiftUITests/Tests/ChatChannel/ChatChannelTestHelpers.swift
@@ -17,7 +17,7 @@ class ChatChannelTestHelpers {
let config = ChannelConfig(commands: [Command(name: "giphy", description: "", set: "", args: "")])
let channel = chatChannel ?? ChatChannel.mockDMChannel(
config: config,
- ownCapabilities: [.uploadFile],
+ ownCapabilities: [.sendMessage, .uploadFile],
lastActiveWatchers: lastActiveWatchers
)
let channelQuery = ChannelQuery(cid: channel.cid)
diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/MessageComposerView_Tests.swift b/StreamChatSwiftUITests/Tests/ChatChannel/MessageComposerView_Tests.swift
index 905da904c..34663602e 100644
--- a/StreamChatSwiftUITests/Tests/ChatChannel/MessageComposerView_Tests.swift
+++ b/StreamChatSwiftUITests/Tests/ChatChannel/MessageComposerView_Tests.swift
@@ -204,7 +204,7 @@ class MessageComposerView_Tests: StreamChatTestCase {
// Given
let factory = DefaultViewFactory.shared
let mockChannelController = ChatChannelTestHelpers.makeChannelController(chatClient: chatClient)
- mockChannelController.channel_mock = .mockDMChannel(ownCapabilities: [.uploadFile])
+ mockChannelController.channel_mock = .mockDMChannel(ownCapabilities: [.sendMessage, .uploadFile])
let viewModel = MessageComposerViewModel(channelController: mockChannelController, messageController: nil)
// When
@@ -234,6 +234,97 @@ class MessageComposerView_Tests: StreamChatTestCase {
assertSnapshot(matching: view, as: .image(perceptualPrecision: precision))
}
+ // MARK: - Frozen Channel Tests
+
+ func test_messageComposerView_frozenChannel() {
+ // Given
+ let factory = DefaultViewFactory.shared
+ let mockChannelController = ChatChannelTestHelpers.makeChannelController(chatClient: chatClient)
+ // Create a channel without sendMessage capability (simulating frozen channel)
+ mockChannelController.channel_mock = .mockDMChannel(ownCapabilities: [.uploadFile, .readEvents])
+ let viewModel = MessageComposerViewModel(channelController: mockChannelController, messageController: nil)
+
+ // When
+ let view = MessageComposerView(
+ viewFactory: factory,
+ viewModel: viewModel,
+ channelController: mockChannelController,
+ messageController: nil,
+ quotedMessage: .constant(nil),
+ editedMessage: .constant(nil),
+ onMessageSent: {}
+ )
+ .frame(width: defaultScreenSize.width, height: 100)
+
+ // Then
+ assertSnapshot(matching: view, as: .image(perceptualPrecision: precision))
+ }
+
+ func test_composerInputView_frozenChannel() {
+ // Given
+ let factory = DefaultViewFactory.shared
+ let mockChannelController = ChatChannelTestHelpers.makeChannelController(chatClient: chatClient)
+ mockChannelController.channel_mock = .mockDMChannel(ownCapabilities: [.uploadFile, .readEvents])
+ let viewModel = MessageComposerViewModel(channelController: mockChannelController, messageController: nil)
+
+ // When
+ let view = ComposerInputView(
+ factory: factory,
+ text: .constant(""),
+ selectedRangeLocation: .constant(0),
+ command: .constant(nil),
+ addedAssets: [],
+ addedFileURLs: [],
+ addedCustomAttachments: [],
+ quotedMessage: .constant(nil),
+ cooldownDuration: 0,
+ onCustomAttachmentTap: { _ in },
+ removeAttachmentWithId: { _ in }
+ )
+ .environmentObject(viewModel)
+ .frame(width: defaultScreenSize.width, height: 100)
+
+ // Then
+ assertSnapshot(matching: view, as: .image(perceptualPrecision: precision))
+ }
+
+ func test_leadingComposerView_frozenChannel() {
+ // Given
+ let factory = DefaultViewFactory.shared
+ let mockChannelController = ChatChannelTestHelpers.makeChannelController(chatClient: chatClient)
+ mockChannelController.channel_mock = .mockDMChannel(ownCapabilities: [.uploadFile, .readEvents])
+ let viewModel = MessageComposerViewModel(channelController: mockChannelController, messageController: nil)
+
+ // When
+ let pickerTypeState: Binding = .constant(.expanded(.none))
+ let view = factory.makeLeadingComposerView(state: pickerTypeState, channelConfig: nil)
+ .environmentObject(viewModel)
+ .frame(width: 36, height: 36)
+
+ // Then
+ assertSnapshot(matching: view, as: .image(perceptualPrecision: precision))
+ }
+
+ func test_trailingComposerView_frozenChannel() {
+ // Given
+ let factory = DefaultViewFactory.shared
+ let mockChannelController = ChatChannelTestHelpers.makeChannelController(chatClient: chatClient)
+ mockChannelController.channel_mock = .mockDMChannel(ownCapabilities: [.uploadFile, .readEvents])
+ let viewModel = MessageComposerViewModel(channelController: mockChannelController, messageController: nil)
+
+ // When
+ let view = factory.makeTrailingComposerView(
+ enabled: true,
+ cooldownDuration: 0,
+ onTap: {}
+ )
+ .environmentObject(viewModel)
+ .frame(width: 100, height: 40)
+
+ // Then
+ assertSnapshot(matching: view, as: .image(perceptualPrecision: precision))
+ }
+
func test_composerInputView_inputTextView() {
// Given
let view = InputTextView(
@@ -803,6 +894,166 @@ class MessageComposerView_Tests: StreamChatTestCase {
onMessageSent: {}
)
}
+
+ // MARK: - Notification Tests
+
+ func test_commandsOverlayHiddenNotification_hidesCommandsOverlay() {
+ // Given
+ let utils = Utils(
+ messageListConfig: MessageListConfig(
+ hidesCommandsOverlayOnMessageListTap: true
+ )
+ )
+ streamChat = StreamChat(chatClient: chatClient, utils: utils)
+
+ let factory = DefaultViewFactory.shared
+ let channelController = ChatChannelTestHelpers.makeChannelController(chatClient: chatClient)
+ let viewModel = MessageComposerViewModel(channelController: channelController, messageController: nil)
+
+ // Set up a command to be shown
+ viewModel.composerCommand = ComposerCommand(
+ id: "testCommand",
+ typingSuggestion: TypingSuggestion.empty,
+ displayInfo: nil
+ )
+
+ let view = MessageComposerView(
+ viewFactory: factory,
+ viewModel: viewModel,
+ channelController: channelController,
+ messageController: nil,
+ quotedMessage: .constant(nil),
+ editedMessage: .constant(nil),
+ onMessageSent: {}
+ )
+ view.addToViewHierarchy()
+
+ // When
+ NotificationCenter.default.post(
+ name: .commandsOverlayHiddenNotification,
+ object: nil
+ )
+
+ // Then
+ XCTAssertNil(viewModel.composerCommand)
+ }
+
+ func test_commandsOverlayHiddenNotification_respectsConfigSetting() {
+ // Given
+ let utils = Utils(
+ messageListConfig: MessageListConfig(
+ hidesCommandsOverlayOnMessageListTap: false
+ )
+ )
+ streamChat = StreamChat(chatClient: chatClient, utils: utils)
+
+ let factory = DefaultViewFactory.shared
+ let channelController = ChatChannelTestHelpers.makeChannelController(chatClient: chatClient)
+ let viewModel = MessageComposerViewModel(channelController: channelController, messageController: nil)
+
+ // Set up a command to be shown
+ let testCommand = ComposerCommand(
+ id: "testCommand",
+ typingSuggestion: TypingSuggestion.empty,
+ displayInfo: nil
+ )
+ viewModel.composerCommand = testCommand
+
+ let view = MessageComposerView(
+ viewFactory: factory,
+ viewModel: viewModel,
+ channelController: channelController,
+ messageController: nil,
+ quotedMessage: .constant(nil),
+ editedMessage: .constant(nil),
+ onMessageSent: {}
+ )
+ view.addToViewHierarchy()
+
+ // When
+ NotificationCenter.default.post(
+ name: .commandsOverlayHiddenNotification,
+ object: nil
+ )
+
+ // Then
+ XCTAssertNotNil(viewModel.composerCommand)
+ XCTAssertEqual(viewModel.composerCommand?.id, testCommand.id)
+ }
+
+ func test_attachmentPickerHiddenNotification_hidesAttachmentPicker() {
+ // Given
+ let utils = Utils(
+ messageListConfig: MessageListConfig(
+ hidesAttachmentsPickersOnMessageListTap: true
+ )
+ )
+ streamChat = StreamChat(chatClient: chatClient, utils: utils)
+
+ let factory = DefaultViewFactory.shared
+ let channelController = ChatChannelTestHelpers.makeChannelController(chatClient: chatClient)
+ let viewModel = MessageComposerViewModel(channelController: channelController, messageController: nil)
+
+ // Set up attachment picker to be shown
+ viewModel.pickerTypeState = .expanded(.media)
+
+ let view = MessageComposerView(
+ viewFactory: factory,
+ viewModel: viewModel,
+ channelController: channelController,
+ messageController: nil,
+ quotedMessage: .constant(nil),
+ editedMessage: .constant(nil),
+ onMessageSent: {}
+ )
+ view.addToViewHierarchy()
+
+ // When
+ NotificationCenter.default.post(
+ name: .attachmentPickerHiddenNotification,
+ object: nil
+ )
+
+ // Then
+ XCTAssertEqual(viewModel.pickerTypeState, .expanded(.none))
+ }
+
+ func test_attachmentPickerHiddenNotification_respectsConfigSetting() {
+ // Given
+ let utils = Utils(
+ messageListConfig: MessageListConfig(
+ hidesAttachmentsPickersOnMessageListTap: false
+ )
+ )
+ streamChat = StreamChat(chatClient: chatClient, utils: utils)
+
+ let factory = DefaultViewFactory.shared
+ let channelController = ChatChannelTestHelpers.makeChannelController(chatClient: chatClient)
+ let viewModel = MessageComposerViewModel(channelController: channelController, messageController: nil)
+
+ // Set up attachment picker to be shown
+ viewModel.pickerTypeState = .expanded(.media)
+
+ let view = MessageComposerView(
+ viewFactory: factory,
+ viewModel: viewModel,
+ channelController: channelController,
+ messageController: nil,
+ quotedMessage: .constant(nil),
+ editedMessage: .constant(nil),
+ onMessageSent: {}
+ )
+ view.addToViewHierarchy()
+
+ // When
+ NotificationCenter.default.post(
+ name: .attachmentPickerHiddenNotification,
+ object: nil
+ )
+
+ // Then
+ XCTAssertEqual(viewModel.pickerTypeState, .expanded(.media))
+ }
}
class SynchronousAttachmentsConverter: MessageAttachmentsConverter {
diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_composerInputView_frozenChannel.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_composerInputView_frozenChannel.1.png
new file mode 100644
index 000000000..c0474044c
Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_composerInputView_frozenChannel.1.png differ
diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_leadingComposerView_frozenChannel.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_leadingComposerView_frozenChannel.1.png
new file mode 100644
index 000000000..86c39cbb3
Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_leadingComposerView_frozenChannel.1.png differ
diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_frozenChannel.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_frozenChannel.1.png
new file mode 100644
index 000000000..9f366ec2d
Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_frozenChannel.1.png differ
diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_trailingComposerView_frozenChannel.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_trailingComposerView_frozenChannel.1.png
new file mode 100644
index 000000000..18daa12e6
Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_trailingComposerView_frozenChannel.1.png differ
diff --git a/StreamChatSwiftUITests/Tests/Utils/ViewFactory_Tests.swift b/StreamChatSwiftUITests/Tests/Utils/ViewFactory_Tests.swift
index a2974a46d..0b4e693f0 100644
--- a/StreamChatSwiftUITests/Tests/Utils/ViewFactory_Tests.swift
+++ b/StreamChatSwiftUITests/Tests/Utils/ViewFactory_Tests.swift
@@ -1043,6 +1043,17 @@ class ViewFactory_Tests: StreamChatTestCase {
// Then
XCTAssert(view is AddUsersView)
}
+
+ func test_viewFactory_makeAttachmentTextView() {
+ // Given
+ let viewFactory = DefaultViewFactory.shared
+
+ // When
+ let view = viewFactory.makeAttachmentTextView(options: .init(mesage: message))
+
+ // Then
+ XCTAssert(view is StreamTextView)
+ }
}
extension ChannelAction: Equatable {
diff --git a/StreamChatSwiftUITestsApp/AppDelegate.swift b/StreamChatSwiftUITestsApp/AppDelegate.swift
index d3d6a5606..7a9bfa7c4 100644
--- a/StreamChatSwiftUITestsApp/AppDelegate.swift
+++ b/StreamChatSwiftUITestsApp/AppDelegate.swift
@@ -5,18 +5,21 @@
import SwiftUI
class AppDelegate: NSObject, UIApplicationDelegate {
-
- func application(_ application: UIApplication,
- didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
+ func application(
+ _ application: UIApplication,
+ didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil
+ ) -> Bool {
disableAnimations()
registerForPushNotifications()
UNUserNotificationCenter.current().delegate = NotificationsHandler.shared
return true
}
- func application(_ application: UIApplication,
- configurationForConnecting connectingSceneSession: UISceneSession,
- options: UIScene.ConnectionOptions) -> UISceneConfiguration {
+ func application(
+ _ application: UIApplication,
+ configurationForConnecting connectingSceneSession: UISceneSession,
+ options: UIScene.ConnectionOptions
+ ) -> UISceneConfiguration {
let sceneConfig = UISceneConfiguration(name: nil, sessionRole: connectingSceneSession.role)
sceneConfig.delegateClass = SceneDelegate.self
return sceneConfig
@@ -44,13 +47,14 @@ class AppDelegate: NSObject, UIApplicationDelegate {
}
func application(
- _ application: UIApplication,
- didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data
+ _ application: UIApplication,
+ didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data
) {
let tokenParts = deviceToken.map { data in String(format: "%02.2hhx", data) }
let token = tokenParts.joined()
print("Device Token: \(token)")
}
+
func application(
_ application: UIApplication,
didFailToRegisterForRemoteNotificationsWithError error: Error
diff --git a/StreamChatSwiftUITestsApp/CustomChannelHeader.swift b/StreamChatSwiftUITestsApp/CustomChannelHeader.swift
index a3d98f602..c3269c9da 100644
--- a/StreamChatSwiftUITestsApp/CustomChannelHeader.swift
+++ b/StreamChatSwiftUITestsApp/CustomChannelHeader.swift
@@ -7,7 +7,6 @@ import StreamChatSwiftUI
import SwiftUI
public struct CustomChannelHeader: ToolbarContent {
-
@Injected(\.fonts) var fonts
@Injected(\.images) var images
@Injected(\.colors) var colors
@@ -36,7 +35,6 @@ public struct CustomChannelHeader: ToolbarContent {
}
struct CustomChannelModifier: ChannelListHeaderViewModifier {
-
@Injected(\.chatClient) var chatClient
var title: String
diff --git a/StreamChatSwiftUITestsApp/InternetConnectionMonitor_Mock.swift b/StreamChatSwiftUITestsApp/InternetConnectionMonitor_Mock.swift
index ec1e8026e..cb5a87b6d 100644
--- a/StreamChatSwiftUITestsApp/InternetConnectionMonitor_Mock.swift
+++ b/StreamChatSwiftUITestsApp/InternetConnectionMonitor_Mock.swift
@@ -4,7 +4,7 @@
import Foundation
-//#if TESTS
+// #if TESTS
@testable import StreamChat
final class InternetConnectionMonitor_Mock: InternetConnectionMonitor {
@@ -19,6 +19,6 @@ final class InternetConnectionMonitor_Mock: InternetConnectionMonitor {
self.status = status
delegate?.internetConnectionStatusDidChange(status: status)
}
-
}
-//#endif
+
+// #endif
diff --git a/StreamChatSwiftUITestsApp/StartPage.swift b/StreamChatSwiftUITestsApp/StartPage.swift
index 280b967c3..69e61f7d7 100644
--- a/StreamChatSwiftUITestsApp/StartPage.swift
+++ b/StreamChatSwiftUITestsApp/StartPage.swift
@@ -2,12 +2,11 @@
// Copyright © 2025 Stream.io Inc. All rights reserved.
//
-import SwiftUI
import StreamChat
import StreamChatSwiftUI
+import SwiftUI
struct StartPage: View {
-
@State var streamChat: StreamChat?
@State var chatShown = false
@ObservedObject var appState = AppState.shared
@@ -67,8 +66,8 @@ struct StartPage: View {
streamChat = StreamChat(chatClient: chatClient)
chatClient.connectUser(
- userInfo: .init(id: credentials.id, name: credentials.name, imageURL: credentials.avatarURL),
- token: token
+ userInfo: .init(id: credentials.id, name: credentials.name, imageURL: credentials.avatarURL),
+ token: token
) { error in
if let error = error {
log.error("connecting the user failed \(error)")
@@ -79,7 +78,6 @@ struct StartPage: View {
}
class DemoAppFactory: ViewFactory {
-
@Injected(\.chatClient) public var chatClient
private init() {}
diff --git a/StreamChatSwiftUITestsApp/StreamChatSwiftUITestsAppApp.swift b/StreamChatSwiftUITestsApp/StreamChatSwiftUITestsAppApp.swift
index 0b6fc9e6d..0fccfefff 100644
--- a/StreamChatSwiftUITestsApp/StreamChatSwiftUITestsAppApp.swift
+++ b/StreamChatSwiftUITestsApp/StreamChatSwiftUITestsAppApp.swift
@@ -7,7 +7,6 @@ import SwiftUI
@main
struct StreamChatSwiftUITestsAppApp: App {
-
@UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
var body: some Scene {
@@ -18,7 +17,6 @@ struct StreamChatSwiftUITestsAppApp: App {
}
class AppState: ObservableObject, Equatable {
-
static func == (lhs: AppState, rhs: AppState) -> Bool {
lhs.userState == rhs.userState
}
diff --git a/StreamChatSwiftUITestsApp/StreamChatWrapper.swift b/StreamChatSwiftUITestsApp/StreamChatWrapper.swift
index a18853d6b..78c4e217c 100644
--- a/StreamChatSwiftUITestsApp/StreamChatWrapper.swift
+++ b/StreamChatSwiftUITestsApp/StreamChatWrapper.swift
@@ -4,8 +4,8 @@
import Foundation
#if TESTS
-@testable import StreamChat
import OHHTTPStubs
+@testable import StreamChat
#else
import StreamChat
#endif
@@ -13,7 +13,6 @@ import StreamChatSwiftUI
import UIKit
final class StreamChatWrapper {
-
@Injected(\.chatClient) var client
static let shared = StreamChatWrapper()
@@ -26,9 +25,11 @@ final class StreamChatWrapper {
let baseURL = self.client.config.baseURL.restAPIBaseURL.absoluteString
return request.url?.absoluteString.contains(baseURL) ?? false
}, withStubResponse: { _ -> HTTPStubsResponse in
- let error = NSError(domain: "NSURLErrorDomain",
- code: -1009,
- userInfo: nil)
+ let error = NSError(
+ domain: "NSURLErrorDomain",
+ code: -1009,
+ userInfo: nil
+ )
return HTTPStubsResponse(error: error)
})
@@ -51,5 +52,4 @@ final class StreamChatWrapper {
}
#endif
}
-
}
diff --git a/StreamChatSwiftUITestsApp/UserCredentials.swift b/StreamChatSwiftUITestsApp/UserCredentials.swift
index df293db54..64c216211 100644
--- a/StreamChatSwiftUITestsApp/UserCredentials.swift
+++ b/StreamChatSwiftUITestsApp/UserCredentials.swift
@@ -18,15 +18,15 @@ public struct UserCredentials {
}
extension UserCredentials {
-
static func builtInUsersByID(id: String) -> UserCredentials? {
mock
}
- static let mock: UserCredentials = UserCredentials(id: "luke_skywalker",
- name: "Luke Skywalker",
- avatarURL: URL(string: "https://vignette.wikia.nocookie.net/starwars/images/2/20/LukeTLJ.jpg")!,
- token: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoibHVrZV9za3l3YWxrZXIifQ.b6EiC8dq2AHk0JPfI-6PN-AM9TVzt8JV-qB1N9kchlI",
- birthLand: "Tatooine")
-
+ static let mock: UserCredentials = UserCredentials(
+ id: "luke_skywalker",
+ name: "Luke Skywalker",
+ avatarURL: URL(string: "https://vignette.wikia.nocookie.net/starwars/images/2/20/LukeTLJ.jpg")!,
+ token: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoibHVrZV9za3l3YWxrZXIifQ.b6EiC8dq2AHk0JPfI-6PN-AM9TVzt8JV-qB1N9kchlI",
+ birthLand: "Tatooine"
+ )
}
diff --git a/StreamChatSwiftUITestsAppTests/Pages/ChannelListPage.swift b/StreamChatSwiftUITestsAppTests/Pages/ChannelListPage.swift
index f926db289..4cf37f9b8 100644
--- a/StreamChatSwiftUITestsAppTests/Pages/ChannelListPage.swift
+++ b/StreamChatSwiftUITestsAppTests/Pages/ChannelListPage.swift
@@ -3,11 +3,10 @@
//
import Foundation
-import XCTest
import StreamChat
+import XCTest
enum ChannelListPage {
-
static var userAvatar: XCUIElement {
return app.buttons["LogoutButton"]
}
@@ -55,5 +54,4 @@ enum ChannelListPage {
return cell.images["readIndicatorCheckmark"]
}
}
-
}
diff --git a/StreamChatSwiftUITestsAppTests/Pages/MessageListPage.swift b/StreamChatSwiftUITestsAppTests/Pages/MessageListPage.swift
index 314d04d46..1eac12e41 100644
--- a/StreamChatSwiftUITestsAppTests/Pages/MessageListPage.swift
+++ b/StreamChatSwiftUITestsAppTests/Pages/MessageListPage.swift
@@ -3,14 +3,13 @@
//
import Foundation
-import XCTest
import StreamChat
@testable import StreamChatSwiftUI
+import XCTest
// swiftlint:disable convenience_type
class MessageListPage {
-
static var cells: XCUIElementQuery {
app.otherElements.matching(identifier: "MessageContainerView")
}
@@ -44,7 +43,6 @@ class MessageListPage {
}
enum NavigationBar {
-
static var chatAvatar: XCUIElement {
app.images["ChannelAvatarView"]
}
@@ -57,13 +55,13 @@ class MessageListPage {
app.staticTexts.matching(identifier: "ChannelTitleView").lastMatch!
}
- // FIXME
+ // FIXME:
static var debugMenu: XCUIElement {
app.buttons[""].firstMatch
}
}
- // FIXME
+ // FIXME:
enum Alert {
enum Debug {
// Add member
@@ -168,7 +166,7 @@ class MessageListPage {
messageCell.staticTexts["readIndicatorCount"]
}
- // FIXME
+ // FIXME:
static func statusCheckmark(for status: MessageDeliveryStatus? = nil, in messageCell: XCUIElement) -> XCUIElement {
messageCell.images["readIndicatorCheckmark"]
}
@@ -314,7 +312,7 @@ class MessageListPage {
}
}
- struct Element {
+ enum Element {
static var actionsView: XCUIElement { app.otherElements["MessageActionsView"] }
static var reply: XCUIElement { app.otherElements["messageAction-reply_message_action"].images.firstMatch }
static var threadReply: XCUIElement { app.otherElements["messageAction-thread_message_action"].images.firstMatch }
@@ -324,7 +322,7 @@ class MessageListPage {
static var unmute: XCUIElement { app.otherElements["messageAction-unmute_message_action"].images.firstMatch }
static var edit: XCUIElement { app.otherElements["messageAction-edit_message_action"].images.firstMatch }
static var delete: XCUIElement { app.otherElements["messageAction-delete_message_action"].images.firstMatch }
- static var hardDelete: XCUIElement { app.otherElements["messageAction-delete_message_action"].images.firstMatch } // FIXME
+ static var hardDelete: XCUIElement { app.otherElements["messageAction-delete_message_action"].images.firstMatch } // FIXME:
static var resend: XCUIElement { app.otherElements["messageAction-resend_message_action"].images.firstMatch }
static var pin: XCUIElement { app.otherElements["messageAction-pin_message_action"].images.firstMatch }
static var unpin: XCUIElement { app.otherElements["messageAction-unpin_message_action"].images.firstMatch }
@@ -348,6 +346,7 @@ class MessageListPage {
static var cancelButton: XCUIElement {
app.scrollViews.buttons.matching(NSPredicate(format: "label LIKE 'Cancel'")).firstMatch
}
+
static var images: XCUIElementQuery { app.scrollViews["AttachmentTypeContainer"].images }
}
@@ -374,5 +373,4 @@ class MessageListPage {
app.scrollViews["CommandsContainerView"].otherElements.matching(NSPredicate(format: "identifier LIKE 'MessageAvatarView'"))
}
}
-
}
diff --git a/StreamChatSwiftUITestsAppTests/Pages/SpringBoard.swift b/StreamChatSwiftUITestsAppTests/Pages/SpringBoard.swift
index ea7568949..e94aecf42 100644
--- a/StreamChatSwiftUITestsAppTests/Pages/SpringBoard.swift
+++ b/StreamChatSwiftUITestsAppTests/Pages/SpringBoard.swift
@@ -14,9 +14,9 @@ enum SpringBoard {
static var notificationBanner: XCUIElement {
app.otherElements["Notification"]
- .descendants(matching: .any)
- .matching(NSPredicate(format: "label CONTAINS[c] ', now,'"))
- .firstMatch
+ .descendants(matching: .any)
+ .matching(NSPredicate(format: "label CONTAINS[c] ', now,'"))
+ .firstMatch
}
static var testAppIcon: XCUIElement {
diff --git a/StreamChatSwiftUITestsAppTests/Pages/ThreadPage.swift b/StreamChatSwiftUITestsAppTests/Pages/ThreadPage.swift
index 9a6daecb1..eca7e35b9 100644
--- a/StreamChatSwiftUITestsAppTests/Pages/ThreadPage.swift
+++ b/StreamChatSwiftUITestsAppTests/Pages/ThreadPage.swift
@@ -6,7 +6,5 @@ import Foundation
import XCTest
class ThreadPage: MessageListPage {
-
static var alsoSendInChannelCheckbox: XCUIElement { app.buttons["SendInChannelView"] }
-
}
diff --git a/StreamChatSwiftUITestsAppTests/Robots/UserRobot+Asserts.swift b/StreamChatSwiftUITestsAppTests/Robots/UserRobot+Asserts.swift
index 637cdb19a..3ab1f0b8b 100644
--- a/StreamChatSwiftUITestsAppTests/Robots/UserRobot+Asserts.swift
+++ b/StreamChatSwiftUITestsAppTests/Robots/UserRobot+Asserts.swift
@@ -3,9 +3,9 @@
//
import Foundation
-import XCTest
import StreamChat
@testable import StreamChatSwiftUI
+import XCTest
let channelAttributes = ChannelListPage.Attributes.self
let channelCells = ChannelListPage.cells
@@ -13,26 +13,28 @@ let attributes = MessageListPage.Attributes.self
let cells = MessageListPage.cells
// MARK: Channel List
-extension UserRobot {
+extension UserRobot {
@discardableResult
- func channelCell(withIndex index: Int? = nil,
- file: StaticString = #filePath,
- line: UInt = #line) -> XCUIElement {
- guard let index = index else {
- return channelCells.firstMatch
- }
+ func channelCell(
+ withIndex index: Int? = nil,
+ file: StaticString = #filePath,
+ line: UInt = #line
+ ) -> XCUIElement {
+ guard let index = index else {
+ return channelCells.firstMatch
+ }
- let minExpectedCount = index + 1
- let cells = cells.waitCount(index)
- XCTAssertGreaterThanOrEqual(
- cells.count,
- minExpectedCount,
- "Message cell is not found at index #\(index)",
- file: file,
- line: line
- )
- return channelCells.element(boundBy: index)
+ let minExpectedCount = index + 1
+ let cells = cells.waitCount(index)
+ XCTAssertGreaterThanOrEqual(
+ cells.count,
+ minExpectedCount,
+ "Message cell is not found at index #\(index)",
+ file: file,
+ line: line
+ )
+ return channelCells.element(boundBy: index)
}
@discardableResult
@@ -45,10 +47,12 @@ extension UserRobot {
let cell = channelCell(withIndex: cellIndex, file: file, line: line)
let message = channelAttributes.lastMessage(in: cell)
let actualText = message.waitForText(text, mustBeEqual: false).text
- XCTAssertTrue(actualText.contains(text),
- "'\(actualText)' does not contain '\(text)'",
- file: file,
- line: line)
+ XCTAssertTrue(
+ actualText.contains(text),
+ "'\(actualText)' does not contain '\(text)'",
+ file: file,
+ line: line
+ )
return self
}
@@ -116,10 +120,12 @@ extension UserRobot {
let expectedChannel = ChannelListPage.channel(withName: "\(expectedCount)")
var expectedChannelExist = expectedChannel.exists
- XCTAssertFalse(expectedChannelExist,
- "Expected channel should not be visible",
- file: file,
- line: line)
+ XCTAssertFalse(
+ expectedChannelExist,
+ "Expected channel should not be visible",
+ file: file,
+ line: line
+ )
let endTime = Date().timeIntervalSince1970 * 1000 + XCUIElement.waitTimeout * 1000
while !expectedChannelExist && endTime > Date().timeIntervalSince1970 * 1000 {
@@ -127,10 +133,12 @@ extension UserRobot {
expectedChannelExist = expectedChannel.exists
}
- XCTAssertTrue(expectedChannelExist,
- "Expected channel should be visible",
- file: file,
- line: line)
+ XCTAssertTrue(
+ expectedChannelExist,
+ "Expected channel should be visible",
+ file: file,
+ line: line
+ )
return self
}
@@ -147,12 +155,14 @@ extension UserRobot {
}
// MARK: Message List
-extension UserRobot {
+extension UserRobot {
@discardableResult
- func messageCell(withIndex index: Int? = nil,
- file: StaticString = #filePath,
- line: UInt = #line) -> XCUIElement {
+ func messageCell(
+ withIndex index: Int? = nil,
+ file: StaticString = #filePath,
+ line: UInt = #line
+ ) -> XCUIElement {
let messageCell: XCUIElement
if let index = index {
let minExpectedCount = index + 1
@@ -193,29 +203,37 @@ extension UserRobot {
line: UInt = #line
) -> Self {
let pushNotification = SpringBoard.notificationBanner.wait()
- XCTAssertTrue(pushNotification.exists,
- "Push notification should appear",
- file: file,
- line: line)
+ XCTAssertTrue(
+ pushNotification.exists,
+ "Push notification should appear",
+ file: file,
+ line: line
+ )
let pushNotificationContent = pushNotification.text
- XCTAssertTrue(pushNotificationContent.contains(text),
- "\(pushNotificationContent) does not contain \(text)",
- file: file,
- line: line)
- XCTAssertTrue(pushNotificationContent.contains(sender),
- "\(pushNotificationContent) does not contain \(sender)",
- file: file,
- line: line)
+ XCTAssertTrue(
+ pushNotificationContent.contains(text),
+ "\(pushNotificationContent) does not contain \(text)",
+ file: file,
+ line: line
+ )
+ XCTAssertTrue(
+ pushNotificationContent.contains(sender),
+ "\(pushNotificationContent) does not contain \(sender)",
+ file: file,
+ line: line
+ )
return self
}
@discardableResult
func assertPushNotificationDoesNotAppear(file: StaticString = #filePath, line: UInt = #line) -> Self {
- XCTAssertFalse(SpringBoard.notificationBanner.exists,
- "Push notification should not appear",
- file: file,
- line: line)
+ XCTAssertFalse(
+ SpringBoard.notificationBanner.exists,
+ "Push notification should not appear",
+ file: file,
+ line: line
+ )
return self
}
@@ -227,11 +245,13 @@ extension UserRobot {
) -> Self {
SpringBoard.notificationBanner.wait()
let appIconValue = SpringBoard.testAppIcon.value as? String
- XCTAssertEqual(appIconValue?.contains("1"),
- shouldBeVisible,
- "Badge should be visible: \(shouldBeVisible)",
- file: file,
- line: line)
+ XCTAssertEqual(
+ appIconValue?.contains("1"),
+ shouldBeVisible,
+ "Badge should be visible: \(shouldBeVisible)",
+ file: file,
+ line: line
+ )
return self
}
@@ -334,6 +354,7 @@ extension UserRobot {
file: StaticString = #filePath,
line: UInt = #line
) -> Self {
+ // swiftformat:disable:next isEmpty
if MessageListPage.cells.count > 0 {
let messageCell = messageCell(withIndex: messageCellIndex, file: file, line: line)
let actualText = attributes.text(in: messageCell).waitForTextDisappearance(deletedText).text
@@ -356,7 +377,7 @@ extension UserRobot {
XCTAssertEqual(author, actualAuthor, file: file, line: line)
return self
}
-
+
@discardableResult
func assertScrollToBottomButton(
isVisible: Bool,
@@ -365,14 +386,16 @@ extension UserRobot {
) -> Self {
var btn = MessageListPage.scrollToBottomButton
btn = isVisible ? btn.wait() : btn.waitForDisappearance()
- XCTAssertEqual(isVisible,
- btn.exists,
- "Scroll to bottom button should be \(isVisible ? "visible" : "hidden")",
- file: file,
- line: line)
+ XCTAssertEqual(
+ isVisible,
+ btn.exists,
+ "Scroll to bottom button should be \(isVisible ? "visible" : "hidden")",
+ file: file,
+ line: line
+ )
return self
}
-
+
@discardableResult
func assertScrollToBottomButtonUnreadCount(
_ expectedCount: Int,
@@ -399,14 +422,18 @@ extension UserRobot {
line: UInt = #line
) -> Self {
let typingIndicatorView = MessageListPage.typingIndicator.wait(timeout: waitTimeout)
- XCTAssertTrue(typingIndicatorView.exists,
- "Element hidden",
- file: file,
- line: line)
- XCTAssertTrue(typingIndicatorView.text.contains(typingUserName),
- "User name is wrong",
- file: file,
- line: line)
+ XCTAssertTrue(
+ typingIndicatorView.exists,
+ "Element hidden",
+ file: file,
+ line: line
+ )
+ XCTAssertTrue(
+ typingIndicatorView.text.contains(typingUserName),
+ "User name is wrong",
+ file: file,
+ line: line
+ )
return self
}
@@ -422,10 +449,12 @@ extension UserRobot {
}
@discardableResult
- func assertContextMenuOptionNotAvailable(option: MessageListPage.ContextMenu,
- forMessageAtIndex index: Int = 0,
- file: StaticString = #filePath,
- line: UInt = #line) -> Self {
+ func assertContextMenuOptionNotAvailable(
+ option: MessageListPage.ContextMenu,
+ forMessageAtIndex index: Int = 0,
+ file: StaticString = #filePath,
+ line: UInt = #line
+ ) -> Self {
openContextMenu(messageCellIndex: index)
XCTAssertFalse(option.element.exists, "Context menu option is visible", file: file, line: line)
return self
@@ -442,7 +471,7 @@ extension UserRobot {
XCTAssertTrue(errorButton.exists, "There is no error icon", file: file, line: line)
return self
}
-
+
@discardableResult
func waitForMessageDeliveryStatus(
_ deliveryStatus: MessageDeliveryStatus?,
@@ -489,9 +518,11 @@ extension UserRobot {
return self
}
- func assertComposerLimits(toNumberOfLines limit: Int,
- file: StaticString = #filePath,
- line: UInt = #line) {
+ func assertComposerLimits(
+ toNumberOfLines limit: Int,
+ file: StaticString = #filePath,
+ line: UInt = #line
+ ) {
let composer = MessageListPage.Composer.inputField
var composerHeight = composer.height
for i in 1.. Self {
_ = messageCell(withIndex: messageCellIndex).waitForHitPoint()
@@ -680,8 +715,8 @@ extension UserRobot {
}
// MARK: Quoted Messages
-extension UserRobot {
+extension UserRobot {
@discardableResult
func assertQuotedMessage(
replyText: String = "", // empty text by default for attachment messages
@@ -695,7 +730,7 @@ extension UserRobot {
let actualText = message.waitForText(quotedText).text
XCTAssertEqual(quotedText, actualText)
XCTAssertTrue(message.exists, "Quoted message was not showed")
-
+
if !replyText.isEmpty {
let message = attributes.text(in: messageCell).wait()
let actualText = message.waitForText(replyText).text
@@ -703,7 +738,7 @@ extension UserRobot {
}
return self
}
-
+
@discardableResult
func assertQuotedMessageWithAttachment(
quotedText: String,
@@ -720,15 +755,17 @@ extension UserRobot {
}
// MARK: Thread Replies
-extension UserRobot {
+extension UserRobot {
@discardableResult
func assertThreadIsOpen(file: StaticString = #filePath, line: UInt = #line) -> Self {
let alsoSendInChannelCheckbox = ThreadPage.alsoSendInChannelCheckbox.wait()
- XCTAssertTrue(alsoSendInChannelCheckbox.exists,
- "alsoSendInChannel checkbox is not visible",
- file: file,
- line: line)
+ XCTAssertTrue(
+ alsoSendInChannelCheckbox.exists,
+ "alsoSendInChannel checkbox is not visible",
+ file: file,
+ line: line
+ )
return self
}
@@ -777,27 +814,35 @@ extension UserRobot {
@discardableResult
func assertCooldownIsShown(file: StaticString = #filePath, line: UInt = #line) -> Self {
- XCTAssertEqual(MessageListPage.Composer.placeholder.text,
- L10n.Composer.Placeholder.slowMode,
- file: file,
- line: line)
- XCTAssertTrue(MessageListPage.Composer.cooldown.wait().exists,
- "Cooldown should be visible",
- file: file,
- line: line)
+ XCTAssertEqual(
+ MessageListPage.Composer.placeholder.text,
+ L10n.Composer.Placeholder.slowMode,
+ file: file,
+ line: line
+ )
+ XCTAssertTrue(
+ MessageListPage.Composer.cooldown.wait().exists,
+ "Cooldown should be visible",
+ file: file,
+ line: line
+ )
return self
}
@discardableResult
func assertCooldownIsNotShown(file: StaticString = #filePath, line: UInt = #line) -> Self {
- XCTAssertNotEqual(MessageListPage.Composer.placeholder.text,
- L10n.Composer.Placeholder.slowMode,
- file: file,
- line: line)
- XCTAssertFalse(MessageListPage.Composer.cooldown.exists,
- "Cooldown should not be visible",
- file: file,
- line: line)
+ XCTAssertNotEqual(
+ MessageListPage.Composer.placeholder.text,
+ L10n.Composer.Placeholder.slowMode,
+ file: file,
+ line: line
+ )
+ XCTAssertFalse(
+ MessageListPage.Composer.cooldown.exists,
+ "Cooldown should not be visible",
+ file: file,
+ line: line
+ )
return self
}
@@ -816,15 +861,18 @@ extension UserRobot {
) -> Self {
let messageCell = messageCell(withIndex: messageCellIndex, file: file, line: line)
let threadReplyCountButton = attributes.threadReplyCountButton(in: messageCell).wait()
- XCTAssertTrue(threadReplyCountButton.exists,
- "There is no thread reply count button",
- file: file,
- line: line)
+ XCTAssertTrue(
+ threadReplyCountButton.exists,
+ "There is no thread reply count button",
+ file: file,
+ line: line
+ )
return self
}
}
// MARK: Reactions
+
extension UserRobot {
@discardableResult
func assertReaction(
@@ -845,9 +893,11 @@ extension UserRobot {
///
/// - Returns: Self
@discardableResult
- func waitForNewReaction(at messageCellIndex: Int? = nil,
- file: StaticString = #filePath,
- line: UInt = #line) -> Self {
+ func waitForNewReaction(
+ at messageCellIndex: Int? = nil,
+ file: StaticString = #filePath,
+ line: UInt = #line
+ ) -> Self {
let cell = messageCell(withIndex: messageCellIndex, file: file, line: line).wait()
attributes.reactionButton(in: cell).wait()
return self
@@ -857,7 +907,6 @@ extension UserRobot {
// MARK: Ephemeral messages
extension UserRobot {
-
@discardableResult
func assertGiphyImage(
at messageCellIndex: Int? = nil,
@@ -898,8 +947,8 @@ extension UserRobot {
}
// MARK: Keyboard
-extension UserRobot {
+extension UserRobot {
@discardableResult
func assertKeyboard(
isVisible: Bool,
@@ -908,18 +957,20 @@ extension UserRobot {
) -> Self {
let keyboard = app.keyboards.firstMatch
keyboard.wait(timeout: 1.5)
- XCTAssertEqual(isVisible,
- keyboard.exists,
- "Keyboard should be \(isVisible ? "visible" : "hidden")",
- file: file,
- line: line)
+ XCTAssertEqual(
+ isVisible,
+ keyboard.exists,
+ "Keyboard should be \(isVisible ? "visible" : "hidden")",
+ file: file,
+ line: line
+ )
return self
}
}
// MARK: Attachments
-extension UserRobot {
+extension UserRobot {
@discardableResult
func assertImage(
isPresent: Bool,
diff --git a/StreamChatSwiftUITestsAppTests/Robots/UserRobot.swift b/StreamChatSwiftUITestsAppTests/Robots/UserRobot.swift
index 9f2d112f3..f03af913b 100644
--- a/StreamChatSwiftUITestsAppTests/Robots/UserRobot.swift
+++ b/StreamChatSwiftUITestsAppTests/Robots/UserRobot.swift
@@ -3,12 +3,11 @@
//
import Foundation
-import XCTest
import StreamChat
+import XCTest
/// Simulates user behavior
final class UserRobot: Robot {
-
let composer = MessageListPage.Composer.self
let contextMenu = MessageListPage.ContextMenu.self
let debugAlert = MessageListPage.Alert.Debug.self
@@ -64,7 +63,6 @@ final class UserRobot: Robot {
// MARK: Message List
extension UserRobot {
-
@discardableResult
func openContextMenu(messageCellIndex: Int = 0) -> Self {
messageCell(withIndex: messageCellIndex).press(forDuration: 1)
@@ -82,11 +80,13 @@ extension UserRobot {
}
@discardableResult
- func sendMessage(_ text: String,
- at messageCellIndex: Int? = nil,
- waitForAppearance: Bool = true,
- file: StaticString = #filePath,
- line: UInt = #line) -> Self {
+ func sendMessage(
+ _ text: String,
+ at messageCellIndex: Int? = nil,
+ waitForAppearance: Bool = true,
+ file: StaticString = #filePath,
+ line: UInt = #line
+ ) -> Self {
server.channelsEndpointWasCalled = false
typeText(text)
@@ -194,17 +194,21 @@ extension UserRobot {
}
@discardableResult
- func quoteMessage(_ text: String,
- messageCellIndex: Int = 0,
- waitForAppearance: Bool = true,
- file: StaticString = #filePath,
- line: UInt = #line) -> Self {
+ func quoteMessage(
+ _ text: String,
+ messageCellIndex: Int = 0,
+ waitForAppearance: Bool = true,
+ file: StaticString = #filePath,
+ line: UInt = #line
+ ) -> Self {
selectOptionFromContextMenu(option: .reply, forMessageAtIndex: messageCellIndex)
- sendMessage(text,
- at: messageCellIndex,
- waitForAppearance: waitForAppearance,
- file: file,
- line: line)
+ sendMessage(
+ text,
+ at: messageCellIndex,
+ waitForAppearance: waitForAppearance,
+ file: file,
+ line: line
+ )
return self
}
@@ -293,11 +297,13 @@ extension UserRobot {
if alsoSendInChannel {
threadCheckbox.wait().safeTap()
}
- sendMessage(text,
- at: messageCellIndex,
- waitForAppearance: waitForAppearance,
- file: file,
- line: line)
+ sendMessage(
+ text,
+ at: messageCellIndex,
+ waitForAppearance: waitForAppearance,
+ file: file,
+ line: line
+ )
return self
}
@@ -346,6 +352,7 @@ extension UserRobot {
@discardableResult
func openComposerCommands() -> Self {
+ // swiftformat:disable:next isEmpty
if MessageListPage.ComposerCommands.cells.count == 0 {
MessageListPage.Composer.commandButton.wait().safeTap()
}
@@ -430,7 +437,6 @@ extension UserRobot {
// MARK: Debug menu
extension UserRobot {
-
@discardableResult
private func tapOnDebugMenu() -> Self {
MessageListPage.NavigationBar.debugMenu.safeTap()
@@ -471,7 +477,6 @@ extension UserRobot {
// MARK: Connectivity
extension UserRobot {
-
/// Toggles the visibility of the connectivity switch control. When set to `.on`, the switch control will be displayed in the navigation bar.
@discardableResult
func setConnectivitySwitchVisibility(to state: SwitchState) -> Self {
@@ -490,7 +495,6 @@ extension UserRobot {
// MARK: Config
extension UserRobot {
-
@discardableResult
func setIsLocalStorageEnabled(to state: SwitchState) -> Self {
setSwitchState(Settings.isLocalStorageEnabled.element, state: state)
diff --git a/StreamChatSwiftUITestsAppTests/StreamChatSwiftUITests.swift b/StreamChatSwiftUITestsAppTests/StreamChatSwiftUITests.swift
index 33dbeb3fb..ed36a6938 100644
--- a/StreamChatSwiftUITestsAppTests/StreamChatSwiftUITests.swift
+++ b/StreamChatSwiftUITestsAppTests/StreamChatSwiftUITests.swift
@@ -2,8 +2,8 @@
// Copyright © 2025 Stream.io Inc. All rights reserved.
//
+import Foundation
@_exported import StreamChatTestMockServer
@_exported import StreamSwiftTestHelpers
-import Foundation
final class StreamChatSwiftUITests {}
diff --git a/StreamChatSwiftUITestsAppTests/Tests/Attachments_Tests.swift b/StreamChatSwiftUITestsAppTests/Tests/Attachments_Tests.swift
index b125e52d7..05fd667a9 100644
--- a/StreamChatSwiftUITestsAppTests/Tests/Attachments_Tests.swift
+++ b/StreamChatSwiftUITestsAppTests/Tests/Attachments_Tests.swift
@@ -5,10 +5,11 @@
import XCTest
final class Attachments_Tests: StreamTestCase {
-
override func setUpWithError() throws {
- try XCTSkipIf(ProcessInfo().operatingSystemVersion.majorVersion >= 18,
- "Attachments tests freeze the test app on iOS > 18")
+ try XCTSkipIf(
+ ProcessInfo().operatingSystemVersion.majorVersion >= 18,
+ "Attachments tests freeze the test app on iOS > 18"
+ )
try super.setUpWithError()
addTags([.coreFeatures])
@@ -78,5 +79,4 @@ final class Attachments_Tests: StreamTestCase {
userRobot.assertFile(isPresent: true)
}
}
-
}
diff --git a/StreamChatSwiftUITestsAppTests/Tests/Base TestCase/StreamTestCase.swift b/StreamChatSwiftUITestsAppTests/Tests/Base TestCase/StreamTestCase.swift
index c6bcd4494..17a77ff5a 100644
--- a/StreamChatSwiftUITestsAppTests/Tests/Base TestCase/StreamTestCase.swift
+++ b/StreamChatSwiftUITestsAppTests/Tests/Base TestCase/StreamTestCase.swift
@@ -8,7 +8,6 @@ import XCTest
let app = XCUIApplication()
class StreamTestCase: XCTestCase {
-
let deviceRobot = DeviceRobot(app)
var userRobot: UserRobot!
var backendRobot: BackendRobot!
@@ -45,7 +44,6 @@ class StreamTestCase: XCTestCase {
}
extension StreamTestCase {
-
func assertMockServer() {
XCTAssertFalse(mockServerCrashed, "Mock server failed on start")
}
diff --git a/StreamChatSwiftUITestsAppTests/Tests/ChannelList_Tests.swift b/StreamChatSwiftUITestsAppTests/Tests/ChannelList_Tests.swift
index b4cd7f105..0f2bae593 100644
--- a/StreamChatSwiftUITestsAppTests/Tests/ChannelList_Tests.swift
+++ b/StreamChatSwiftUITestsAppTests/Tests/ChannelList_Tests.swift
@@ -5,7 +5,6 @@
import XCTest
final class ChannelList_Tests: StreamTestCase {
-
let message = "message"
override func setUpWithError() throws {
@@ -246,7 +245,6 @@ extension ChannelList_Tests {
// MARK: - Truncate channel
extension ChannelList_Tests {
-
func test_messageList_and_channelPreview_AreUpdatedWhenChannelTruncatedWithMessage() throws {
linkToScenario(withId: 357)
diff --git a/StreamChatSwiftUITestsAppTests/Tests/Ephemeral_Messages_Tests.swift b/StreamChatSwiftUITestsAppTests/Tests/Ephemeral_Messages_Tests.swift
index 453a8cc92..aa74183b7 100644
--- a/StreamChatSwiftUITestsAppTests/Tests/Ephemeral_Messages_Tests.swift
+++ b/StreamChatSwiftUITestsAppTests/Tests/Ephemeral_Messages_Tests.swift
@@ -5,7 +5,6 @@
import XCTest
final class Ephemeral_Messages_Tests: StreamTestCase {
-
override func setUpWithError() throws {
try super.setUpWithError()
assertMockServer()
diff --git a/StreamChatSwiftUITestsAppTests/Tests/Message Delivery Status/MessageDeliveryStatus+ChannelList_Tests.swift b/StreamChatSwiftUITestsAppTests/Tests/Message Delivery Status/MessageDeliveryStatus+ChannelList_Tests.swift
index af04a93f0..121936b18 100644
--- a/StreamChatSwiftUITestsAppTests/Tests/Message Delivery Status/MessageDeliveryStatus+ChannelList_Tests.swift
+++ b/StreamChatSwiftUITestsAppTests/Tests/Message Delivery Status/MessageDeliveryStatus+ChannelList_Tests.swift
@@ -5,7 +5,6 @@
import XCTest
final class MessageDeliveryStatus_ChannelList_Tests: StreamTestCase {
-
let message = "message"
var failedMessage: String { "failed \(message)" }
@@ -63,7 +62,6 @@ final class MessageDeliveryStatus_ChannelList_Tests: StreamTestCase {
userRobot
.assertMessageReadCountInChannelPreview(readBy: 0)
.assertMessageDeliveryStatusInChannelPreview(.sent)
-
}
}
@@ -172,7 +170,6 @@ final class MessageDeliveryStatus_ChannelList_Tests: StreamTestCase {
// MARK: Thread Reply
extension MessageDeliveryStatus_ChannelList_Tests {
-
func test_noCheckmarkShownForMessageInPreview_whenThreadReplyIsSent() throws {
linkToScenario(withId: 430)
diff --git a/StreamChatSwiftUITestsAppTests/Tests/Message Delivery Status/MessageDeliveryStatus_Tests.swift b/StreamChatSwiftUITestsAppTests/Tests/Message Delivery Status/MessageDeliveryStatus_Tests.swift
index acf04b42d..e33ae7254 100644
--- a/StreamChatSwiftUITestsAppTests/Tests/Message Delivery Status/MessageDeliveryStatus_Tests.swift
+++ b/StreamChatSwiftUITestsAppTests/Tests/Message Delivery Status/MessageDeliveryStatus_Tests.swift
@@ -5,7 +5,6 @@
import XCTest
final class MessageDeliveryStatus_Tests: StreamTestCase {
-
let message = "message"
var pendingMessage: String { "pending \(message)" }
var failedMessage: String { "failed \(message)" }
@@ -21,6 +20,7 @@ final class MessageDeliveryStatus_Tests: StreamTestCase {
}
// MARK: Message List
+
func test_singleCheckmarkShown_whenMessageIsSent() throws {
linkToScenario(withId: 397)
@@ -71,7 +71,6 @@ final class MessageDeliveryStatus_Tests: StreamTestCase {
.login()
.setConnectivity(to: .off)
.openChannel()
-
}
WHEN("user sends a new message") {
userRobot.sendMessage(failedMessage, waitForAppearance: false)
@@ -227,8 +226,8 @@ final class MessageDeliveryStatus_Tests: StreamTestCase {
// MARK: Thread Reply
extension MessageDeliveryStatus_Tests {
-
// MARK: Thread Previews
+
func test_singleCheckmarkShown_whenMessageIsSent_andPreviewedInThread() throws {
linkToScenario(withId: 405)
@@ -534,7 +533,6 @@ extension MessageDeliveryStatus_Tests {
// MARK: Disabled Read Events feature
extension MessageDeliveryStatus_Tests {
-
// MARK: Messages
func test_deliveryStatusHidden_whenMessageIsSentAndReadEventsIsDisabled() throws {
diff --git a/StreamChatSwiftUITestsAppTests/Tests/MessageList_Tests.swift b/StreamChatSwiftUITestsAppTests/Tests/MessageList_Tests.swift
index 821986de5..8ee85d954 100644
--- a/StreamChatSwiftUITestsAppTests/Tests/MessageList_Tests.swift
+++ b/StreamChatSwiftUITestsAppTests/Tests/MessageList_Tests.swift
@@ -5,7 +5,6 @@
import XCTest
final class MessageList_Tests: StreamTestCase {
-
override func setUpWithError() throws {
try super.setUpWithError()
addTags([.coreFeatures])
@@ -359,7 +358,6 @@ final class MessageList_Tests: StreamTestCase {
// MARK: Scroll to bottom
extension MessageList_Tests {
-
func test_messageListScrollsDown_whenMessageListIsScrolledUp_andUserSendsNewMessage() throws {
linkToScenario(withId: 359)
@@ -511,7 +509,6 @@ extension MessageList_Tests {
// MARK: Pagination
extension MessageList_Tests {
-
func test_paginationOnMessageList() throws {
linkToScenario(withId: 370)
@@ -549,7 +546,6 @@ extension MessageList_Tests {
// MARK: Mentions
extension MessageList_Tests {
-
func test_addingCommandHidesLeftButtons() throws {
linkToScenario(withId: 372)
@@ -610,7 +606,6 @@ extension MessageList_Tests {
// MARK: Links preview
extension MessageList_Tests {
-
func test_addMessageWithLinkToUnsplash() {
linkToScenario(withId: 375)
@@ -683,6 +678,7 @@ extension MessageList_Tests {
}
// MARK: - Thread replies
+
extension MessageList_Tests {
func test_threadReplyAppearsInThread_whenParticipantAddsThreadReply() throws {
linkToScenario(withId: 379)
diff --git a/StreamChatSwiftUITestsAppTests/Tests/PushNotification_Tests.swift b/StreamChatSwiftUITestsAppTests/Tests/PushNotification_Tests.swift
index ae8239069..65ca6f65c 100644
--- a/StreamChatSwiftUITestsAppTests/Tests/PushNotification_Tests.swift
+++ b/StreamChatSwiftUITestsAppTests/Tests/PushNotification_Tests.swift
@@ -6,7 +6,6 @@ import XCTest
// Requires running a standalone Sinatra server
final class PushNotification_Tests: StreamTestCase {
-
let sender = "Han Solo"
let message = "How are you? 🙂"
@@ -30,7 +29,7 @@ final class PushNotification_Tests: StreamTestCase {
GIVEN("user goes to channel list") {
userRobot
.login()
- .openChannel() // this is required to let the mock server know
+ .openChannel() // this is required to let the mock server know
.tapOnBackButton() // which channel to use for push notifications
}
checkHappyPath(message: message, sender: sender)
@@ -61,7 +60,7 @@ final class PushNotification_Tests: StreamTestCase {
version: "",
messageId: "",
cid: ""
- )
+ )
GIVEN("user goes to message list") {
userRobot.login().openChannel()
@@ -125,9 +124,11 @@ final class PushNotification_Tests: StreamTestCase {
mockPushNotification(body: nil)
WHEN("participant sends a message (push body param is nil)") {
- participantRobot.wait(2).sendMessage("\(message)_0",
- withPushNotification: true,
- bundleIdForPushNotification: app.bundleId())
+ participantRobot.wait(2).sendMessage(
+ "\(message)_0",
+ withPushNotification: true,
+ bundleIdForPushNotification: app.bundleId()
+ )
}
THEN("user does not receive a push notification") {
userRobot.assertPushNotificationDoesNotAppear()
@@ -135,9 +136,11 @@ final class PushNotification_Tests: StreamTestCase {
mockPushNotification(body: "")
WHEN("participant sends a message (push body param is empty)") {
- participantRobot.sendMessage("\(message)_1",
- withPushNotification: true,
- bundleIdForPushNotification: app.bundleId())
+ participantRobot.sendMessage(
+ "\(message)_1",
+ withPushNotification: true,
+ bundleIdForPushNotification: app.bundleId()
+ )
}
THEN("user does not receive a push notification") {
userRobot.assertPushNotificationDoesNotAppear()
@@ -145,9 +148,11 @@ final class PushNotification_Tests: StreamTestCase {
mockPushNotification(body: 42)
WHEN("participant sends a message (push body param contains incorrect type)") {
- participantRobot.sendMessage("\(message)_2",
- withPushNotification: true,
- bundleIdForPushNotification: app.bundleId())
+ participantRobot.sendMessage(
+ "\(message)_2",
+ withPushNotification: true,
+ bundleIdForPushNotification: app.bundleId()
+ )
}
THEN("user does not receive a push notification") {
userRobot.assertPushNotificationDoesNotAppear()
diff --git a/StreamChatSwiftUITestsAppTests/Tests/QuotedReply_Tests.swift b/StreamChatSwiftUITestsAppTests/Tests/QuotedReply_Tests.swift
index fb935677b..44833c433 100644
--- a/StreamChatSwiftUITestsAppTests/Tests/QuotedReply_Tests.swift
+++ b/StreamChatSwiftUITestsAppTests/Tests/QuotedReply_Tests.swift
@@ -5,7 +5,6 @@
import XCTest
final class QuotedReply_Tests: StreamTestCase {
-
let messageCount = 30
let parentMessage = "1"
let quotedMessage = "quoted reply"
@@ -107,7 +106,7 @@ final class QuotedReply_Tests: StreamTestCase {
}
func test_quotedReplyNotInList_whenParticipantAddsQuotedReply_Message() {
- linkToScenario(withId: 1702)
+ linkToScenario(withId: 1702)
GIVEN("user opens the channel") {
backendRobot.generateChannels(count: 1, messagesCount: messageCount)
@@ -133,7 +132,7 @@ final class QuotedReply_Tests: StreamTestCase {
}
func test_quotedReplyNotInList_whenParticipantAddsQuotedReply_File() {
- linkToScenario(withId: 1703)
+ linkToScenario(withId: 1703)
GIVEN("user opens the channel") {
backendRobot.generateChannels(count: 1, messagesCount: messageCount)
@@ -160,7 +159,7 @@ final class QuotedReply_Tests: StreamTestCase {
}
func test_quotedReplyNotInList_whenParticipantAddsQuotedReply_Giphy() {
- linkToScenario(withId: 1704)
+ linkToScenario(withId: 1704)
GIVEN("user opens the channel") {
backendRobot.generateChannels(count: 1, messagesCount: messageCount)
@@ -187,7 +186,7 @@ final class QuotedReply_Tests: StreamTestCase {
}
func test_quotedReplyIsDeletedByParticipant_deletedMessageIsShown() {
- linkToScenario(withId: 388)
+ linkToScenario(withId: 388)
GIVEN("user opens the channel") {
backendRobot.generateChannels(count: 1, messagesCount: 1)
@@ -205,7 +204,7 @@ final class QuotedReply_Tests: StreamTestCase {
}
func test_quotedReplyIsDeletedByUser_deletedMessageIsShown() {
- linkToScenario(withId: 389)
+ linkToScenario(withId: 389)
GIVEN("user opens the channel") {
backendRobot.generateChannels(count: 1, messagesCount: 1)
@@ -223,7 +222,7 @@ final class QuotedReply_Tests: StreamTestCase {
}
func test_unreadCount_whenUserSendsInvalidCommand_and_jumpingOnQuotedMessage() throws {
- linkToScenario(withId: 1705)
+ linkToScenario(withId: 1705)
let invalidCommand = "invalid command"
diff --git a/StreamChatSwiftUITestsAppTests/Tests/Reactions_Tests.swift b/StreamChatSwiftUITestsAppTests/Tests/Reactions_Tests.swift
index b97de225a..df9422970 100644
--- a/StreamChatSwiftUITestsAppTests/Tests/Reactions_Tests.swift
+++ b/StreamChatSwiftUITestsAppTests/Tests/Reactions_Tests.swift
@@ -5,7 +5,6 @@
import XCTest
final class Reactions_Tests: StreamTestCase {
-
override func setUpWithError() throws {
try super.setUpWithError()
addTags([.coreFeatures])
diff --git a/StreamChatSwiftUITestsAppTests/Tests/SlowMode_Tests.swift b/StreamChatSwiftUITestsAppTests/Tests/SlowMode_Tests.swift
index 132efdf76..8884d9b5d 100644
--- a/StreamChatSwiftUITestsAppTests/Tests/SlowMode_Tests.swift
+++ b/StreamChatSwiftUITestsAppTests/Tests/SlowMode_Tests.swift
@@ -5,7 +5,6 @@
import XCTest
final class SlowMode_Tests: StreamTestCase {
-
let cooldownDuration = 15
let message = "message"
let anotherNewMessage = "Another new message"
diff --git a/StreamChatSwiftUITestsAppTests/Tests/StreamTestCase+Tags.swift b/StreamChatSwiftUITestsAppTests/Tests/StreamTestCase+Tags.swift
index 55d641b85..2a289319e 100644
--- a/StreamChatSwiftUITestsAppTests/Tests/StreamTestCase+Tags.swift
+++ b/StreamChatSwiftUITestsAppTests/Tests/StreamTestCase+Tags.swift
@@ -13,6 +13,6 @@ extension StreamTestCase {
}
func addTags(_ tags: [Tags]) {
- addTagsToScenario(tags.map{ $0.rawValue })
+ addTagsToScenario(tags.map { $0.rawValue })
}
}
diff --git a/fastlane/Fastfile b/fastlane/Fastfile
index da6f0de56..5866b6bd5 100644
--- a/fastlane/Fastfile
+++ b/fastlane/Fastfile
@@ -511,13 +511,9 @@ lane :run_swift_format do |options|
Dir.chdir('..') do
check_foundation_import
strict = options[:strict] ? '--lint' : nil
- sources_matrix[:swiftformat].each do |path|
- sh("swiftformat #{strict} --config .swiftformat #{path}")
- next if path.include?('Tests')
-
- sh("swiftlint lint --config .swiftlint.yml --fix --progress --reporter json #{path}") unless strict
- sh("swiftlint lint --config .swiftlint.yml --strict --progress --reporter json #{path}")
- end
+ sh("swiftformat #{strict} --config .swiftformat .")
+ sh("swiftlint lint --config .swiftlint.yml --fix --progress --reporter json") unless strict
+ sh("swiftlint lint --config .swiftlint.yml --strict --progress --reporter json")
end
end
@@ -545,8 +541,7 @@ lane :sources_matrix do
ruby: ['fastlane', 'Gemfile', 'Gemfile.lock'],
size: ['Sources', xcode_project],
sonar: ['Sources'],
- public_interface: ['Sources'],
- swiftformat: ['Sources', 'DemoAppSwiftUI', 'StreamChatSwiftUITests']
+ public_interface: ['Sources']
}
end
@@ -618,7 +613,7 @@ lane :update_img_shields_sdk_sizes do |options|
)
end
-def frameworks_sizes
+private_lane :frameworks_sizes do
root_dir = 'Build/SDKSize'
archive_dir = "#{root_dir}/DemoApp.xcarchive"
@@ -630,7 +625,9 @@ def frameworks_sizes
scheme: 'DemoAppSwiftUI',
archive_path: archive_dir,
export_method: 'ad-hoc',
- export_options: 'fastlane/sdk_size_export_options.plist'
+ export_options: 'fastlane/sdk_size_export_options.plist',
+ derived_data_path: derived_data_path,
+ cloned_source_packages_path: source_packages_path
)
# Parse the thinned size of Assets.car from Packaging.log
@@ -645,3 +642,20 @@ def frameworks_sizes
{ StreamChatSwiftUI: stream_chat_swiftui_size_kb.round(0) }
end
+
+lane :size_analyze do
+ next unless is_check_required(sources: sources_matrix[:size], force_check: @force_check)
+
+ gym(
+ scheme: 'DemoAppSwiftUI',
+ configuration: 'Release',
+ skip_archive: true,
+ skip_package_ipa: true,
+ skip_package_pkg: true,
+ skip_codesigning: true,
+ derived_data_path: derived_data_path,
+ cloned_source_packages_path: source_packages_path
+ )
+
+ show_detailed_sdk_size(sdk_names: sdk_names, threshold: 42)
+end
diff --git a/fastlane/Pluginfile b/fastlane/Pluginfile
index 37b60ac84..772a05733 100644
--- a/fastlane/Pluginfile
+++ b/fastlane/Pluginfile
@@ -5,4 +5,5 @@
gem 'fastlane-plugin-versioning'
gem 'fastlane-plugin-sonarcloud_metric_kit'
gem 'fastlane-plugin-create_xcframework'
-gem 'fastlane-plugin-stream_actions', '0.3.90'
+gem 'fastlane-plugin-stream_actions', '0.3.101'
+gem 'fastlane-plugin-xcsize', '1.1.0'
diff --git a/lefthook.yml b/lefthook.yml
index 1320df25c..61221d999 100644
--- a/lefthook.yml
+++ b/lefthook.yml
@@ -4,10 +4,6 @@ pre-commit:
- run: swiftlint lint --config .swiftlint.yml --fix --progress --reporter json {staged_files}
glob: "*.{swift}"
stage_fixed: true
- exclude:
- - Sources/StreamChatSwiftUI/Generated/**
- - Sources/StreamChatSwiftUI/StreamNuke/**
- - Sources/StreamChatSwiftUI/StreamSwiftyGif/**
skip:
- merge
- rebase
@@ -15,10 +11,6 @@ pre-commit:
- run: swiftformat --config .swiftformat {staged_files}
glob: "*.{swift}"
stage_fixed: true
- exclude:
- - Sources/StreamChatSwiftUI/Generated/**
- - Sources/StreamChatSwiftUI/StreamNuke/**
- - Sources/StreamChatSwiftUI/StreamSwiftyGif/**
skip:
- merge
- rebase
@@ -27,9 +19,5 @@ pre-push:
jobs:
- run: swiftlint lint --config .swiftlint.yml --strict --progress --reporter json {push_files}
glob: "*.{swift}"
- exclude:
- - Sources/StreamChatSwiftUI/Generated/**
- - Sources/StreamChatSwiftUI/StreamNuke/**
- - Sources/StreamChatSwiftUI/StreamSwiftyGif/**
skip:
- merge-commit