diff --git a/AGENTS.md b/AGENTS.md index 2ab923c09..63b4e6038 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -2,46 +2,82 @@ Guidance for AI coding agents (Copilot, Cursor, Aider, Claude, etc.) working in ### Repository purpose -This repo hosts Stream’s SwiftUI Chat SDK for iOS. It builds on the core client and provides SwiftUI-first chat components (views, view models, modifiers) for messaging apps. +This repo hosts Stream's SwiftUI Chat SDK for iOS. It builds on the core client and provides SwiftUI-first chat components (views, view models, modifiers) for messaging apps. -Agents should optimize for clean code, follow Apple's SwiftUI guidelines and Swift best practices, accessibility, and high test coverage when changing code. At the moment, we are building a new major version of the SDK, so we can make source-breaking changes without adding deprecations. +Agents should optimize for clean code, follow Apple's SwiftUI guidelines and Swift best practices, accessibility, and high test coverage when changing code. Avoid doing any source-breaking changes without adding deprecations. ### Tech & toolchain -- Language: Swift (SwiftUI) +- Language: Swift 6.0 (strict concurrency enabled — `swift-tools-version:6.0`) - Primary distribution: Swift Package Manager (SPM) +- Project file: `StreamChatSwiftUI.xcodeproj` (used for builds and tests; SPM manifest does not declare test targets) - Xcode: 16.x or newer (Apple Silicon supported) -- Platforms / deployment targets: Use the values set in Package.swift; do not lower targets without approval -- CI: GitHub Actions (assume PR validation for build + tests + lint) -- Linters & docs: SwiftLint and SwiftFormat +- Platforms / deployment targets: iOS 14+, macOS 11+ (see `Package.swift`; do not lower targets without approval) +- CI: GitHub Actions + Fastlane (see `.github/workflows/smoke-checks.yml`) +- Linting: SwiftLint (v0.59.1) — config in `.swiftlint.yml` +- Formatting: SwiftFormat (v0.58.2) — config in `.swiftformat` +- Code generation: SwiftGen (v6.5.1) — generates `L10n.swift` for localization strings +- Git hooks: lefthook (`lefthook.yml`) — runs SwiftLint fix + SwiftFormat on pre-commit, SwiftLint strict on pre-push +- Tool versions are pinned in `Githubfile` + +### Dependencies + +- **StreamChat** and **StreamChatCommonUI** from [`stream-chat-swift`](https://github.com/GetStream/stream-chat-swift) (≥ 5.0.0-beta) +- **Vendored libraries** (do not edit directly): + - `Sources/StreamChatSwiftUI/StreamNuke/` — vendored Nuke image loading + - `Sources/StreamChatSwiftUI/StreamSwiftyGif/` — vendored SwiftyGif + - Update these via `make update_nuke version=X.Y.Z` / `make update_swiftygif version=X.Y.Z` ### Project layout (high level) +``` Sources/ - StreamChatSwiftUI/ # SwiftUI views, view models, theming, utils -Tests/ - StreamChatSwiftUITests/ # Unit/UI tests for SwiftUI layer + StreamChatSwiftUI/ # Main SDK: views, view models, theming, utils + ChatChannel/ # Channel view & sub-components + ChatChannelList/ # Channel list view & view model + ChatComposer/ # Message composer + ChatMessageList/ # Message list rendering + ChatThreadList/ # Thread list + CommonViews/ # Shared/reusable SwiftUI views + Generated/ # Auto-generated (L10n.swift, version) — do not edit manually + Resources/ # Localization files (en.lproj, etc.) + StreamNuke/ # Vendored — do not edit + StreamSwiftyGif/ # Vendored — do not edit + Utils/ # Utilities, common helpers + ViewFactory/ # ViewFactory protocol & default implementation + +DemoAppSwiftUI/ # Demo/sample app (use to validate UI changes) +StreamChatSwiftUITests/ # Unit & snapshot tests for the SDK +StreamChatSwiftUITestsApp/ # Test harness app for E2E tests +StreamChatSwiftUITestsAppTests/ # E2E / UI automation tests +Scripts/ # Helper scripts (bootstrap, dependency updates, docs) +fastlane/ # Fastlane lanes for CI (build, test, release) +``` When editing near other packages (e.g., StreamChat or StreamChatUI), prefer extending the SwiftUI layer rather than duplicating logic from dependencies. ### New files & target membership - When creating new source or resource files, add them to the correct Xcode target(s). Update the project (e.g. project.pbxproj) so each new file is included in the appropriate target's "Compile Sources" (or "Copy Bundle Resources" for assets). Match the target(s) used by sibling files in the same directory (e.g. Sources/StreamChatSwiftUI/ → StreamChatSwiftUI; Tests/StreamChatSwiftUITests/ → StreamChatSwiftUITests). Omitting target membership will cause build failures or unused files. + +When creating new source or resource files, add them to the correct Xcode target(s). Update the project (e.g. `project.pbxproj`) so each new file is included in the appropriate target's "Compile Sources" (or "Copy Bundle Resources" for assets). Match the target(s) used by sibling files in the same directory (e.g. `Sources/StreamChatSwiftUI/` → StreamChatSwiftUI target; `StreamChatSwiftUITests/` → StreamChatSwiftUITests target). Omitting target membership will cause build failures or unused files. ### Local setup (SPM) -1. Open the repository in Xcode (root contains Package.swift). +1. Open the repository in Xcode (root contains `Package.swift` and `StreamChatSwiftUI.xcodeproj`). 2. Resolve packages. 3. Choose an iOS Simulator (e.g., iPhone 17 Pro) and Build. -Optional: sample/demo app +Optional: run `Scripts/bootstrap.sh` to install pinned versions of SwiftLint, SwiftFormat, and SwiftGen, and to set up lefthook git hooks. + +### Demo app -If a sample app target exists in this repo, prefer running that to validate UI changes. Keep demo configs free of credentials and use placeholders like YOUR_STREAM_KEY. +The `DemoAppSwiftUI` target is a fully functional sample app. Prefer running it to validate UI changes. Keep demo configs free of credentials and use placeholders like `YOUR_STREAM_KEY`. ### Schemes -Typical scheme names include: - • StreamChatSwiftUI - • StreamChatSwiftUITests +Available shared schemes (under `StreamChatSwiftUI.xcodeproj/xcshareddata/xcschemes/`): + - `StreamChatSwiftUI` — builds the SDK framework + - `DemoAppSwiftUI` — builds and runs the demo app + - `StreamChatSwiftUITestsApp` — builds and runs the E2E test harness Agents must query existing schemes before invoking xcodebuild. @@ -76,14 +112,56 @@ xcodebuild \ -configuration Debug test ``` -If a Makefile or scripts exist (e.g., make build, make test, ./scripts/lint.sh), prefer those to keep parity with CI. Discover with make help and ls scripts/. +### Linting & formatting + +SwiftLint (strict mode): + +``` +swiftlint lint --config .swiftlint.yml --strict +``` + +SwiftFormat (check only — no edits): + +``` +swiftformat --config .swiftformat --lint . +``` + +SwiftFormat (auto-fix): -Linting & formatting - • SwiftLint (strict): +``` +swiftformat --config .swiftformat . +``` + +Respect `.swiftlint.yml` and `.swiftformat` rules. Do not broadly disable rules; scope exceptions and justify in PRs. + +### CI overview + +CI is driven by Fastlane (see `fastlane/Fastfile`). Key lanes: + +- `test_ui` — runs unit/snapshot tests +- `test_e2e_mock` — runs E2E tests against a mock server +- `build_demo` — builds the demo app +- `build_test_app_and_frameworks` — builds test app and SDK frameworks + +The `smoke-checks.yml` workflow is the primary PR gate. It runs linting, formatting validation, unit tests, E2E tests, and demo app builds. -swiftlint --strict +### Generated code - • Respect .swiftlint.yml and any repo-specific rules. Do not broadly disable rules; scope exceptions and justify in PRs. +Do not manually edit files in `Sources/StreamChatSwiftUI/Generated/`: +- `L10n.swift` — generated by SwiftGen from localization `.strings` files. Edit the `.strings` source files instead. +- `SystemEnvironment+Version.swift` — updated automatically during releases. +- `L10n_template.stencil` — the SwiftGen template for localization generation. + +### Localization + +The SDK uses `defaultLocalization: "en"`. String resources live in `Sources/StreamChatSwiftUI/Resources/en.lproj/`. After modifying `.strings` files, regenerate `L10n.swift` by running SwiftGen (or let CI handle it). Always use `L10n` accessors for user-facing strings rather than raw string literals. + +### Concurrency model + +The project uses Swift 6.0 strict concurrency. Many public types and view models are annotated with `@MainActor`. When adding new code: +- Mark SwiftUI view models and UI-bound types as `@MainActor` +- Use `Sendable` conformances where needed for cross-isolation transfers +- Avoid introducing data races; the compiler will enforce actor isolation ### Development guidelines @@ -91,18 +169,25 @@ Accessibility & UI quality - Ensure components have accessibility labels, traits, and dynamic type support. - Support both light/dark mode. -- Use the tokens, colors, fonts, utils etc all from InjectedValuesExtensions.swift. -- When using Figma MCP, all the tokens, colors and fonts are available in the InjectedValuesExtensions.swift file with the same names. +- Use the tokens, colors, fonts, utils etc all from `InjectedValuesExtensions.swift`. +- When using Figma MCP, all the tokens, colors and fonts are available in the `InjectedValuesExtensions.swift` file with the same names. Testing policy -- Add/extend tests in StreamChatSwiftUITests/ -- Prefer using the AssertSnapshot from StreamChatTestHelpers instead of using the SnapshotTesting framework directly. -- Avoid using the AssertAsync from StreamChatTestHelpers, instead use the XCTestExpectation directly whenever possible. +- Add/extend tests in `StreamChatSwiftUITests/Tests/` (mirrors the source directory structure) +- Test infrastructure (mocks, shared helpers) lives in `StreamChatSwiftUITests/Infrastructure/` +- Prefer using `AssertSnapshot` from StreamChatTestHelpers instead of using the SnapshotTesting framework directly. +- Avoid using `AssertAsync` from StreamChatTestHelpers, instead use `XCTestExpectation` directly whenever possible. + +### Branching & changelog + +- The default integration branch is `develop`. Feature branches are merged into `develop`. +- Update `CHANGELOG.md` under the `# Upcoming` section when making client-facing changes (follow the Keep a Changelog format with `### Added`, `### Fixed`, `### Changed` subsections). -Pull Requests: +### Pull Requests - Use the Github CLI to create a PR and use the Linear MCP to link the relevant issue assigned to me. -- When creating a PR, the base branch should be the v5 branch. -- Make sure that the PR respects the PR template in .github/PULL_REQUEST_TEMPLATE.md. +- When creating a PR, the base branch should be the `develop` branch. +- Make sure that the PR respects the PR template in `.github/PULL_REQUEST_TEMPLATE.md`. - Make sure to fill the template with atomic information, do not mention things that were done and then reverted in this same PR. +- Do not write "Made with Cursor" in the PR description. diff --git a/CHANGELOG.md b/CHANGELOG.md index a16d54ae9..fe1ec17c7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,64 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ### 🔄 Changed +# [5.0.0](https://github.com/GetStream/stream-chat-swiftui/releases/tag/5.0.0) +_April 16, 2026_ + +### ✅ Added +- Redesign attachment uploading progress and error state indicators [#1408](https://github.com/GetStream/stream-chat-swiftui/pull/1408) +- Add inline upload progress and retry UI for file attachments [#1408](https://github.com/GetStream/stream-chat-swiftui/pull/1408) +- Add `RetryBadgeView` for failed uploads and thumbnail loads [#1408](https://github.com/GetStream/stream-chat-swiftui/pull/1408) +- Add `ComposerConfig.isVoiceRecordingAutoSendEnabled` to support sending a recording instantly on release [#1362](https://github.com/GetStream/stream-chat-swiftui/pull/1362) +- Redesign `JumpToUnreadButton` [#1351](https://github.com/GetStream/stream-chat-swiftui/pull/1351) +- Show deleted messages in channel list preview [#1338](https://github.com/GetStream/stream-chat-swiftui/pull/1338) +- Update deleted message design in the message list [#1349](https://github.com/GetStream/stream-chat-swiftui/pull/1349) +- Redesign new messages divider in the message list [#1354](https://github.com/GetStream/stream-chat-swiftui/pull/1354) +- Redesign the thread replies divider in the message replies list [#1354](https://github.com/GetStream/stream-chat-swiftui/pull/1354) + +### 🐞 Fixed +- Fix attachment downloads not using CDN requester for URL signing and custom headers [#1399](https://github.com/GetStream/stream-chat-swiftui/pull/1399) +- Fix empty share sheet when sharing a video from the full-screen media viewer [#1418](https://github.com/GetStream/stream-chat-swiftui/pull/1418) +- Fix swipe-to-reply icon layout for outgoing messages and RTL [#1402](https://github.com/GetStream/stream-chat-swiftui/pull/1402) +- Fix unwanted border on the Edit button in Channel Info [#1402](https://github.com/GetStream/stream-chat-swiftui/pull/1402) +- Fix send button icon not mirroring in RTL layouts [#1397](https://github.com/GetStream/stream-chat-swiftui/pull/1397) +- Fix composer attachment picker prompt views layout to center all content vertically [#1397](https://github.com/GetStream/stream-chat-swiftui/pull/1397) +- Fix poll icon inconsistency in the attachment type picker and attachment previews [#1397](https://github.com/GetStream/stream-chat-swiftui/pull/1397) +- Fix voice recording attachment container rendering when quoting a message [#1388](https://github.com/GetStream/stream-chat-swiftui/pull/1388) +- Fix annotation button colors in the reactions overlay [#1386](https://github.com/GetStream/stream-chat-swiftui/pull/1386) +- Fix error indicator position and styling to match v5 design [#1383](https://github.com/GetStream/stream-chat-swiftui/pull/1383) +- Fix scroll to bottom button not working when the message list is actively scrolling [#1380](https://github.com/GetStream/stream-chat-swiftui/pull/1380) +- Fix timestamp snapping back faster than delivery indicator on swipe-to-reply [#1360](https://github.com/GetStream/stream-chat-swiftui/pull/1360) +- Fix tapping a non-first media attachment always opening the first item on initial tap [#1359](https://github.com/GetStream/stream-chat-swiftui/pull/1359) +- Pinned message label now shows "Pinned by you" when the current user pinned the message [#1329](https://github.com/GetStream/stream-chat-swiftui/pull/1329) +- Fix single media attachment without sharp tail corner when no caption [#1330](https://github.com/GetStream/stream-chat-swiftui/pull/1330) +- Fix editing a voice message removing the voice recording attachment [#1327](https://github.com/GetStream/stream-chat-swiftui/pull/1327) +- Fix hold-and-release mic gesture not sending the voice message immediately [#1327](https://github.com/GetStream/stream-chat-swiftui/pull/1327) +- Fix voice message playback state and waveform slider updates [#1327](https://github.com/GetStream/stream-chat-swiftui/pull/1327) +- Fix split view navigation on iPad [#1320](https://github.com/GetStream/stream-chat-swiftui/pull/1320) +- Fix rendering 1:1 direct message avatars and presence indicators [#1332](https://github.com/GetStream/stream-chat-swiftui/pull/1332) +- Fix giphy previews in the channel list and quote replies [#1333](https://github.com/GetStream/stream-chat-swiftui/pull/1333) +- Fix black borders on image preview in composer when editing or quoting a message [#1334](https://github.com/GetStream/stream-chat-swiftui/pull/1334) +- Fix quoted image preview not updating when switching to a different quoted message [#1334](https://github.com/GetStream/stream-chat-swiftui/pull/1334) +- Use fixed width for attachment previews [#1335](https://github.com/GetStream/stream-chat-swiftui/pull/1335) +- Fix showing bubble for quoted message and file or image attachment [#1335](https://github.com/GetStream/stream-chat-swiftui/pull/1335) +- Fix scaling of giphy attachments [#1335](https://github.com/GetStream/stream-chat-swiftui/pull/1335) +- Fix spacings in message annotations [#1403](https://github.com/GetStream/stream-chat-swiftui/pull/1403) + +### 🔄 Changed +- Rename `AddUsersView`/`AddUsersViewModel` to `MemberAddView`/`MemberAddViewModel` [#1402](https://github.com/GetStream/stream-chat-swiftui/pull/1402) +- Unify Channel Info navigation headers styling [#1402](https://github.com/GetStream/stream-chat-swiftui/pull/1402) +- Renamed the `onMessageSent` callback to `willSendMessage` in `MessageComposerViewModel`, `ViewModelsFactory`, and `ComposerViewFactoryOptions` [#1327](https://github.com/GetStream/stream-chat-swiftui/pull/1327) +- Remove `InjectedChannelInfo` from `ChatChannelListItemView` [#1338](https://github.com/GetStream/stream-chat-swiftui/pull/1338) +- Rename empty state views from `No` prefix to `Empty` prefix [#1345](https://github.com/GetStream/stream-chat-swiftui/pull/1345) +- Migrate all the old color tokens to new color tokens [#1350](https://github.com/GetStream/stream-chat-swiftui/pull/1350) +- Replace `LinkDetectionTextView` with `StreamTextView` that uses `ChatMessage.attributedTextContent(layoutDirection:translationLanguage:)` [#1411](https://github.com/GetStream/stream-chat-swiftui/pull/1411) + +# [4.99.1](https://github.com/GetStream/stream-chat-swiftui/releases/tag/4.99.1) +_April 01, 2026_ + +### 🐞 Fixed +- Fix pause button size in voice recording view [#1344](https://github.com/GetStream/stream-chat-swiftui/pull/1344) + # [5.0.0-beta](https://github.com/GetStream/stream-chat-swiftui/releases/tag/5.0.0-beta) _March 23, 2026_ diff --git a/DemoAppSwiftUI/AppConfiguration/AppConfiguration.swift b/DemoAppSwiftUI/AppConfiguration/AppConfiguration.swift index da90320a9..13399e1ad 100644 --- a/DemoAppSwiftUI/AppConfiguration/AppConfiguration.swift +++ b/DemoAppSwiftUI/AppConfiguration/AppConfiguration.swift @@ -21,28 +21,31 @@ final class AppConfiguration { var reactionsPlacement: ReactionsPlacement = .top /// The visual style used across the app (regular or liquid glass). var appStyle: AppStyle = .regular + /// When enabled, releasing a hold-to-record gesture sends the voice message instantly. + var isVoiceRecordingAutoSendEnabled = false enum AppStyle: String, CaseIterable { case regular case liquidGlass } + /// Builds the demo app's `ComposerConfig` using current app configuration. + @MainActor static func makeComposerConfig() -> ComposerConfig { + ComposerConfig( + isVoiceRecordingAutoSendEnabled: AppConfiguration.default.isVoiceRecordingAutoSendEnabled + ) + } + /// Builds the demo app's `MessageListConfig` using current app configuration. @MainActor static func makeMessageListConfig() -> MessageListConfig { MessageListConfig( messageDisplayOptions: MessageDisplayOptions( reactionsPlacement: AppConfiguration.default.reactionsPlacement, - reactionsStyle: AppConfiguration.default.reactionsStyle, - showOriginalTranslatedButton: true + reactionsStyle: AppConfiguration.default.reactionsStyle ), - dateIndicatorPlacement: .messageList, - userBlockingEnabled: true, - bouncedMessagesAlertActionsEnabled: true, skipEditedMessageLabel: { message in message.extraData["ai_generated"]?.boolValue == true - }, - draftMessagesEnabled: true, - downloadFileAttachmentsEnabled: true + } ) } } diff --git a/DemoAppSwiftUI/AppConfiguration/AppConfigurationView.swift b/DemoAppSwiftUI/AppConfiguration/AppConfigurationView.swift index b301d9332..afe77556f 100644 --- a/DemoAppSwiftUI/AppConfiguration/AppConfigurationView.swift +++ b/DemoAppSwiftUI/AppConfiguration/AppConfigurationView.swift @@ -11,12 +11,8 @@ struct AppConfigurationView: View { @State private var reactionsStyle = AppConfiguration.default.reactionsStyle @State private var reactionsPlacement = AppConfiguration.default.reactionsPlacement @State private var appStyle = AppConfiguration.default.appStyle - - var forceRTL: Binding = Binding { - AppConfiguration.default.forceRTL - } set: { newValue in - AppConfiguration.default.forceRTL = newValue - } + @State private var forceRTL = AppConfiguration.default.forceRTL + @State private var voiceRecordingAutoSend = AppConfiguration.default.isVoiceRecordingAutoSendEnabled var body: some View { NavigationView { @@ -43,14 +39,18 @@ struct AppConfigurationView: View { Text("Liquid Glass").tag(AppConfiguration.AppStyle.liquidGlass) } } + Section("Voice Recording") { + Toggle("Auto-send on release", isOn: $voiceRecordingAutoSend) + } Section("Layout") { - Toggle("Force RTL (preview)", isOn: forceRTL) + Toggle("Force RTL (preview)", isOn: $forceRTL) } } .navigationBarTitleDisplayMode(.inline) .navigationTitle("App Configuration") } .onChange(of: channelPinningEnabled, perform: { AppConfiguration.default.isChannelPinningFeatureEnabled = $0 }) + .onChange(of: forceRTL) { AppConfiguration.default.forceRTL = $0 } .onChange(of: reactionsStyle) { newStyle in AppConfiguration.default.reactionsStyle = newStyle InjectedValues[\.utils].messageListConfig = AppConfiguration.makeMessageListConfig() @@ -62,6 +62,10 @@ struct AppConfigurationView: View { .onChange(of: appStyle) { newStyle in AppConfiguration.default.appStyle = newStyle } + .onChange(of: voiceRecordingAutoSend) { newValue in + AppConfiguration.default.isVoiceRecordingAutoSendEnabled = newValue + InjectedValues[\.utils].composerConfig = AppConfiguration.makeComposerConfig() + } } } diff --git a/DemoAppSwiftUI/AppDelegate.swift b/DemoAppSwiftUI/AppDelegate.swift index 18fbfeca5..0e07756ea 100644 --- a/DemoAppSwiftUI/AppDelegate.swift +++ b/DemoAppSwiftUI/AppDelegate.swift @@ -70,11 +70,8 @@ class AppDelegate: NSObject, UIApplicationDelegate { } let utils = Utils( - channelListConfig: ChannelListConfig( - channelItemMutedStyle: .bottomRightCorner - ), messageListConfig: AppConfiguration.makeMessageListConfig(), - composerConfig: ComposerConfig(isVoiceRecordingEnabled: true) + composerConfig: AppConfiguration.makeComposerConfig() ) streamChat = StreamChat(chatClient: chatClient, utils: utils) diff --git a/DemoAppSwiftUI/AppleMessageComposerView.swift b/DemoAppSwiftUI/AppleMessageComposerView.swift index 35a7c5b0a..3b5d5830a 100644 --- a/DemoAppSwiftUI/AppleMessageComposerView.swift +++ b/DemoAppSwiftUI/AppleMessageComposerView.swift @@ -24,6 +24,8 @@ struct AppleMessageComposerView: View, KeyboardReadable { @State private var state: AnimationState = .initial @State private var listScale: CGFloat = 0 + @StateObject var viewModel: MessageComposerViewModel + public init( viewFactory: Factory, viewModel: MessageComposerViewModel? = nil, @@ -31,25 +33,22 @@ struct AppleMessageComposerView: View, KeyboardReadable { messageController: ChatMessageController? = nil, quotedMessage: Binding, editedMessage: Binding, - onMessageSent: @escaping () -> Void + willSendMessage: @escaping () -> Void ) { factory = viewFactory channelConfig = channelController.channel?.config let vm = viewModel ?? ViewModelsFactory.makeMessageComposerViewModel( with: channelController, messageController: messageController, - quotedMessage: quotedMessage + quotedMessage: quotedMessage, + editedMessage: editedMessage, + willSendMessage: willSendMessage ) _viewModel = StateObject(wrappedValue: vm) _quotedMessage = quotedMessage _editedMessage = editedMessage - self.onMessageSent = onMessageSent } - @StateObject var viewModel: MessageComposerViewModel - - var onMessageSent: () -> Void - var body: some View { VStack(spacing: 0) { HStack(alignment: .bottom) { @@ -68,7 +67,7 @@ struct AppleMessageComposerView: View, KeyboardReadable { Image(systemName: "plus") .padding(.all, 12) .foregroundColor(Color.gray) - .background(Color(colors.background1)) + .background(Color(colors.backgroundCoreSurfaceSubtle)) .clipShape(Circle()) } .padding(.bottom, 4) @@ -218,11 +217,7 @@ struct AppleMessageComposerView: View, KeyboardReadable { } private func sendMessage() { - onMessageSent() - viewModel.sendMessage(quotedMessage: quotedMessage, editedMessage: editedMessage) { - quotedMessage = nil - editedMessage = nil - } + viewModel.sendMessage() } } diff --git a/DemoAppSwiftUI/ChannelHeader/NewChatView.swift b/DemoAppSwiftUI/ChannelHeader/NewChatView.swift index eef18f504..748192e38 100644 --- a/DemoAppSwiftUI/ChannelHeader/NewChatView.swift +++ b/DemoAppSwiftUI/ChannelHeader/NewChatView.swift @@ -23,7 +23,7 @@ struct NewChatView: View, KeyboardReadable { HStack { Text("TO:") .font(fonts.footnote) - .foregroundColor(Color(colors.textLowEmphasis)) + .foregroundColor(Color(colors.textTertiary)) VStack { if !viewModel.selectedUsers.isEmpty { @@ -77,13 +77,13 @@ struct NewChatView: View, KeyboardReadable { VerticallyCenteredView { Text("No user matches these keywords") .font(.title2) - .foregroundColor(Color(colors.textLowEmphasis)) + .foregroundColor(Color(colors.textTertiary)) } } else if viewModel.state == .error { VerticallyCenteredView { Text("Error loading the users") .font(.title2) - .foregroundColor(Color(colors.textLowEmphasis)) + .foregroundColor(Color(colors.textTertiary)) } } else if viewModel.state == .channel, let controller = viewModel.channelController { Divider() @@ -137,7 +137,7 @@ struct SelectedUserView: View { .padding(.vertical, 2) .padding(.trailing) } - .background(Color(colors.background1)) + .background(Color(colors.backgroundCoreSurfaceSubtle)) .cornerRadius(16) } } @@ -190,7 +190,7 @@ struct CreateGroupButton: View { Text("Create a group") .font(fonts.bodyBold) - .foregroundColor(Color(colors.text)) + .foregroundColor(Color(colors.textPrimary)) Spacer() } @@ -220,7 +220,7 @@ struct ChatUserView: View { .font(fonts.bodyBold) Text(onlineText) .font(fonts.footnote) - .foregroundColor(Color(colors.textLowEmphasis)) + .foregroundColor(Color(colors.textTertiary)) } Spacer() @@ -245,10 +245,10 @@ struct UsersHeaderView: View { .padding(.horizontal) .padding(.vertical, 2) .font(fonts.body) - .foregroundColor(Color(colors.textLowEmphasis)) + .foregroundColor(Color(colors.textTertiary)) Spacer() } - .background(Color(colors.background1)) + .background(Color(colors.backgroundCoreSurfaceSubtle)) } } diff --git a/DemoAppSwiftUI/CreateGroupView.swift b/DemoAppSwiftUI/CreateGroupView.swift index 268fd21a4..e2777f3bf 100644 --- a/DemoAppSwiftUI/CreateGroupView.swift +++ b/DemoAppSwiftUI/CreateGroupView.swift @@ -125,7 +125,7 @@ struct SearchBar: View { TextField("Search ...", text: $text) .padding(7) .padding(.horizontal, 25) - .background(Color(colors.background1)) + .background(Color(colors.backgroundCoreSurfaceSubtle)) .cornerRadius(16) .overlay( HStack { diff --git a/DemoAppSwiftUI/CustomComposerAttachmentView.swift b/DemoAppSwiftUI/CustomComposerAttachmentView.swift index 3e9c4ed53..60a344c11 100644 --- a/DemoAppSwiftUI/CustomComposerAttachmentView.swift +++ b/DemoAppSwiftUI/CustomComposerAttachmentView.swift @@ -157,7 +157,7 @@ struct CustomAttachmentTypePickerView: View { } .padding(.horizontal, 16) .frame(height: 56) - .background(Color(colors.background1)) + .background(Color(colors.backgroundCoreSurfaceSubtle)) } } @@ -272,15 +272,15 @@ struct CustomContactAttachmentPreview: View { HStack { Image(systemName: "person.crop.circle") .renderingMode(.template) - .foregroundColor(Color(colors.textLowEmphasis)) + .foregroundColor(Color(colors.textTertiary)) VStack(alignment: .leading) { Text(payload.name) .font(fonts.bodyBold) - .foregroundColor(Color(colors.text)) + .foregroundColor(Color(colors.textPrimary)) Text(payload.phoneNumber) .font(fonts.footnote) - .foregroundColor(Color(colors.textLowEmphasis)) + .foregroundColor(Color(colors.textTertiary)) } if hasSpacing { @@ -290,7 +290,7 @@ struct CustomContactAttachmentPreview: View { if isAttachmentSelected { Image(systemName: "checkmark") .renderingMode(.template) - .foregroundColor(Color(colors.textLowEmphasis)) + .foregroundColor(Color(colors.textTertiary)) } } } diff --git a/DemoAppSwiftUI/GroupNameView.swift b/DemoAppSwiftUI/GroupNameView.swift index ba9ae7335..b1e1820d7 100644 --- a/DemoAppSwiftUI/GroupNameView.swift +++ b/DemoAppSwiftUI/GroupNameView.swift @@ -20,7 +20,7 @@ struct GroupNameView: View, KeyboardReadable { HStack { Text("NAME") .font(fonts.footnote) - .foregroundColor(Color(colors.textLowEmphasis)) + .foregroundColor(Color(colors.textTertiary)) TextField( "Choose a group chat name", @@ -53,7 +53,7 @@ struct GroupNameView: View, KeyboardReadable { } label: { Image(systemName: "xmark") .renderingMode(.template) - .foregroundColor(Color(colors.text)) + .foregroundColor(Color(colors.textPrimary)) } .buttonStyle(PlainButtonStyle()) } @@ -85,7 +85,7 @@ struct GroupControlsView: View { Image(systemName: "checkmark") .renderingMode(.template) .foregroundColor( - viewModel.canCreateGroup ? Color(colors.accentPrimary) : Color(colors.textLowEmphasis) + viewModel.canCreateGroup ? Color(colors.accentPrimary) : Color(colors.textTertiary) ) } .disabled(!viewModel.canCreateGroup) @@ -95,7 +95,7 @@ struct GroupControlsView: View { } label: { Image(systemName: "xmark.circle") .renderingMode(.template) - .foregroundColor(Color(colors.textLowEmphasis)) + .foregroundColor(Color(colors.textTertiary)) } NavigationLink( diff --git a/DemoAppSwiftUI/LoginView.swift b/DemoAppSwiftUI/LoginView.swift index 18b986bc4..48556b565 100644 --- a/DemoAppSwiftUI/LoginView.swift +++ b/DemoAppSwiftUI/LoginView.swift @@ -67,7 +67,7 @@ struct DemoUserView: View { .foregroundColor(Color(colors.accentPrimary)) .frame(width: imageSize, height: imageSize) .aspectRatio(contentMode: .fit) - .background(Color(colors.background6)) + .background(Color(colors.backgroundCoreSurfaceDefault)) .clipShape(Circle()) } else { UserAvatar( @@ -83,7 +83,7 @@ struct DemoUserView: View { .font(fonts.bodyBold) Text(user.isGuest ? "Login as Guest" : "Stream test account") .font(fonts.footnote) - .foregroundColor(Color(colors.textLowEmphasis)) + .foregroundColor(Color(colors.textTertiary)) } Spacer() diff --git a/DemoAppSwiftUI/PinChannelHelpers.swift b/DemoAppSwiftUI/PinChannelHelpers.swift index ff684203b..46b054bcc 100644 --- a/DemoAppSwiftUI/PinChannelHelpers.swift +++ b/DemoAppSwiftUI/PinChannelHelpers.swift @@ -15,7 +15,7 @@ struct DemoAppChatChannelListItem: View { var channel: ChatChannel var channelName: String - var injectedChannelInfo: InjectedChannelInfo? + var isSelected: Bool = false var disabled = false var onItemTap: (ChatChannel) -> Void @@ -35,7 +35,7 @@ struct DemoAppChatChannelListItem: View { Spacer() - if injectedChannelInfo == nil && channel.unreadCount != .noUnread { + if !isSelected && channel.unreadCount != .noUnread { BadgeNotificationView( count: channel.unreadCount.messages ) @@ -52,12 +52,12 @@ struct DemoAppChatChannelListItem: View { MessageReadIndicatorView( readUsers: channel.readUsers( currentUserId: chatClient.currentUserId, - message: channel.latestMessages.first + message: previewMessage ), - localState: channel.latestMessages.first?.localState + localState: previewMessage?.localState ) } - SubtitleText(text: injectedChannelInfo?.timestamp ?? channel.timestampText) + SubtitleText(text: timestampText) .accessibilityIdentifier("timestampView") } } @@ -70,27 +70,59 @@ struct DemoAppChatChannelListItem: View { .background(channel.isPinned ? Color(colors.backgroundCoreHighlight) : .clear) } + private var previewMessage: ChatMessage? { + channel.latestMessages.first(where: { $0.type != .ephemeral }) + } + + private var shouldShowTypingIndicator: Bool { + !channel.currentlyTypingUsersFiltered( + currentUserId: chatClient.currentUserId + ).isEmpty && channel.config.typingEventsEnabled + } + + private var draftMessageText: String? { + guard let draftMessage = channel.draftMessage else { return nil } + return utils.messagePreviewFormatter.formatContent(for: ChatMessage(draftMessage), in: channel) + } + + private var timestampText: String { + if let lastMessageAt = channel.lastMessageAt { + return utils.messageTimestampFormatter.format(lastMessageAt) + } + return "" + } + + private var subtitleText: String { + if shouldShowTypingIndicator { + return channel.typingIndicatorString(currentUserId: chatClient.currentUserId) + } + if let previewMessage { + return utils.messagePreviewFormatter.format(previewMessage, in: channel) + } + return "No messages yet" + } + private var subtitleView: some View { HStack(spacing: 4) { if let image { Image(uiImage: image) .customizable() .frame(maxHeight: 12) - .foregroundColor(Color(colors.subtitleText)) + .foregroundColor(Color(colors.textSecondary)) } else { - if channel.shouldShowTypingIndicator { + if shouldShowTypingIndicator { TypingIndicatorDotsView() } } - if let draftText = channel.draftMessageText { + if let draftText = draftMessageText { HStack(spacing: 2) { Text("Draft:") .font(fonts.caption1).bold() - .foregroundColor(Color(colors.highlightedAccentBackground)) + .foregroundColor(Color(colors.accentPrimary)) SubtitleText(text: draftText) } } else { - SubtitleText(text: injectedChannelInfo?.subtitle ?? channel.subtitleText) + SubtitleText(text: subtitleText) } Spacer() } @@ -98,7 +130,7 @@ struct DemoAppChatChannelListItem: View { } private var shouldShowReadEvents: Bool { - if let message = channel.latestMessages.first, + if let message = previewMessage, message.isSentByCurrentUser, !message.isDeleted { return channel.config.readEventsEnabled @@ -120,7 +152,7 @@ struct DemoAppChatChannelNavigatableListItem: View { private var channelName: String private var disabled: Bool @Binding private var selectedChannel: ChannelSelectionInfo? - private var channelDestination: (ChannelSelectionInfo) -> ChannelDestination + private var channelDestination: ((ChannelSelectionInfo) -> ChannelDestination)? private var onItemTap: (ChatChannel) -> Void init( @@ -128,7 +160,7 @@ struct DemoAppChatChannelNavigatableListItem: View { channelName: String, disabled: Bool = false, selectedChannel: Binding, - channelDestination: @escaping (ChannelSelectionInfo) -> ChannelDestination, + channelDestination: ((ChannelSelectionInfo) -> ChannelDestination)? = nil, onItemTap: @escaping (ChatChannel) -> Void ) { self.channel = channel @@ -145,7 +177,7 @@ struct DemoAppChatChannelNavigatableListItem: View { DemoAppChatChannelListItem( channel: channel, channelName: channelName, - injectedChannelInfo: injectedChannelInfo, + isSelected: isSelected, disabled: disabled, onItemTap: onItemTap ) @@ -153,28 +185,30 @@ struct DemoAppChatChannelNavigatableListItem: View { ChatChannelListItem( channel: channel, channelName: channelName, - injectedChannelInfo: injectedChannelInfo, + isSelected: isSelected, disabled: disabled, onItemTap: onItemTap ) } - NavigationLink( - tag: channel.channelSelectionInfo, - selection: $selectedChannel - ) { - LazyView( - channelDestination(channel.channelSelectionInfo) - .modifier(TabBarVisibilityModifier()) - ) - } label: { - EmptyView() + if let channelDestination { + NavigationLink( + tag: channel.channelSelectionInfo, + selection: $selectedChannel + ) { + LazyView( + channelDestination(channel.channelSelectionInfo) + .modifier(TabBarVisibilityModifier()) + ) + } label: { + EmptyView() + } + .opacity(0) // Fixes showing accessibility button shape } - .opacity(0) // Fixes showing accessibility button shape } } - private var injectedChannelInfo: InjectedChannelInfo? { - selectedChannel?.channel.cid.rawValue == channel.cid.rawValue ? selectedChannel?.injectedChannelInfo : nil + private var isSelected: Bool { + selectedChannel?.channel.cid == channel.cid } } diff --git a/DemoAppSwiftUI/ViewFactoryExamples.swift b/DemoAppSwiftUI/ViewFactoryExamples.swift index 9d85a18a6..faef1528e 100644 --- a/DemoAppSwiftUI/ViewFactoryExamples.swift +++ b/DemoAppSwiftUI/ViewFactoryExamples.swift @@ -316,7 +316,7 @@ class CustomFactory: ViewFactory { } } - func makeNoChannelsView(options: NoChannelsViewOptions) -> some View { + func makeEmptyChannelsView(options: EmptyChannelsViewOptions) -> some View { VStack { Spacer() Text("This is our own custom no channels view.") diff --git a/DemoAppSwiftUI/WhatsAppChannelHeader.swift b/DemoAppSwiftUI/WhatsAppChannelHeader.swift index 5d9eb8586..bf64210c7 100644 --- a/DemoAppSwiftUI/WhatsAppChannelHeader.swift +++ b/DemoAppSwiftUI/WhatsAppChannelHeader.swift @@ -48,7 +48,7 @@ struct WhatsAppChannelHeader: ToolbarContent { .font(fonts.bodyBold) Text(channelSubtitle) .font(fonts.caption1) - .foregroundColor(Color(colors.textLowEmphasis)) + .foregroundColor(Color(colors.textTertiary)) } } } diff --git a/Gemfile.lock b/Gemfile.lock index 396290c37..65bcf9519 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -165,7 +165,7 @@ GEM fastlane pry fastlane-plugin-sonarcloud_metric_kit (0.2.1) - fastlane-plugin-stream_actions (0.3.110) + fastlane-plugin-stream_actions (0.4.0) xctest_list (= 1.2.1) fastlane-plugin-versioning (0.7.1) fastlane-plugin-xcsize (1.2.0) @@ -273,12 +273,12 @@ GEM puma (6.6.1) nio4r (~> 2.0) racc (1.8.1) - rack (3.2.3) + rack (3.2.6) rack-protection (4.2.0) base64 (>= 0.1.0) logger (>= 1.6.0) rack (>= 3.0.0, < 4) - rack-session (2.1.1) + rack-session (2.1.2) base64 (>= 0.1.0) rack (>= 3.0.0) rackup (2.2.1) @@ -385,7 +385,7 @@ DEPENDENCIES fastlane fastlane-plugin-lizard fastlane-plugin-sonarcloud_metric_kit - fastlane-plugin-stream_actions (= 0.3.110) + fastlane-plugin-stream_actions (= 0.4.0) fastlane-plugin-versioning fastlane-plugin-xcsize (= 1.2.0) faye-websocket diff --git a/Package.swift b/Package.swift index a66dd22f3..702f90f3f 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: "5.0.0-beta") + .package(url: "https://github.com/GetStream/stream-chat-swift.git", from: "5.0.0") ], targets: [ .target( diff --git a/README.md b/README.md index 289e12a97..8c00d814d 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@

- StreamChatSwiftUI + StreamChatSwiftUI

## SwiftUI StreamChat SDK diff --git a/Sources/StreamChatSwiftUI/Appearance.swift b/Sources/StreamChatSwiftUI/Appearance.swift index a80334a89..a2833bbee 100644 --- a/Sources/StreamChatSwiftUI/Appearance.swift +++ b/Sources/StreamChatSwiftUI/Appearance.swift @@ -2,7 +2,6 @@ // Copyright © 2026 Stream.io Inc. All rights reserved. // -import StreamChatCommonUI import SwiftUI // MARK: - Appearance + Default diff --git a/Sources/StreamChatSwiftUI/ChatChannel/ChannelInfo/ChatChannelInfoHelperViews.swift b/Sources/StreamChatSwiftUI/ChatChannel/ChannelInfo/ChatChannelInfoHelperViews.swift index 73b34cc3a..18a9916e7 100644 --- a/Sources/StreamChatSwiftUI/ChatChannel/ChannelInfo/ChatChannelInfoHelperViews.swift +++ b/Sources/StreamChatSwiftUI/ChatChannel/ChannelInfo/ChatChannelInfoHelperViews.swift @@ -30,26 +30,29 @@ public struct InfoSectionCard: View { /// Header view shown at the top of the group info screen. /// Displays the channel avatar stack, channel name, and member count. -public struct ChatInfoGroupHeaderView: View { +public struct ChatInfoGroupHeaderView: View { @Injected(\.fonts) private var fonts @Injected(\.colors) private var colors @Injected(\.tokens) private var tokens + let factory: Factory @ObservedObject var viewModel: ChatChannelInfoViewModel - public init(viewModel: ChatChannelInfoViewModel) { + public init(factory: Factory = DefaultViewFactory.shared, viewModel: ChatChannelInfoViewModel) { + self.factory = factory self.viewModel = viewModel } public var body: some View { VStack(spacing: tokens.spacingXs) { - ChannelAvatar( - channel: viewModel.channel, - size: AvatarSize.extraExtraLarge, - showsIndicator: false, - showsBorder: true + factory.makeChannelAvatarView( + options: ChannelAvatarViewOptions( + channel: viewModel.channel, + size: AvatarSize.extraExtraLarge, + showsIndicator: false, + showsBorder: true + ) ) - Text(viewModel.channelName) .font(fonts.title3.weight(.semibold)) .foregroundColor(Color(colors.textPrimary)) @@ -254,94 +257,6 @@ public struct ChannelInfoItemView: View { } } -// MARK: - Member List View - -/// A view that displays the full member list for a group channel, presented as a sheet. -public struct MemberListView: View { - @Injected(\.colors) private var colors - @Injected(\.fonts) private var fonts - @Injected(\.tokens) private var tokens - @Injected(\.images) private var images - @Injected(\.chatClient) private var chatClient - - let factory: Factory - @ObservedObject var viewModel: ChatChannelInfoViewModel - @State private var selectedParticipant: ParticipantInfo? - @State private var addUsersShown = false - - public init(factory: Factory = DefaultViewFactory.shared, viewModel: ChatChannelInfoViewModel) { - self.factory = factory - self.viewModel = viewModel - } - - public var body: some View { - NavigationView { - ScrollView { - LazyVStack(spacing: 0) { - ForEach(viewModel.allParticipants) { participant in - ChatInfoMemberView( - factory: factory, - participant: participant, - backgroundColor: colors.backgroundCoreApp, - onAppear: { viewModel.onMemberAppear(participant) }, - onTap: { - selectedParticipant = participant - } - ) - } - } - } - .background(Color(colors.backgroundCoreApp).edgesIgnoringSafeArea(.all)) - .toolbarThemed { - ToolbarItem(placement: .principal) { - Text(L10n.ChatInfo.Members.count(viewModel.channel.memberCount)) - .font(fonts.bodyBold) - .foregroundColor(Color(colors.navigationBarTitle)) - } - ToolbarItem(placement: .navigationBarLeading) { - Button { - viewModel.memberListSheetShown = false - } label: { - Image(uiImage: images.close) - .foregroundColor(Color(colors.textSecondary)) - } - } - ToolbarItem(placement: .navigationBarTrailing) { - if viewModel.shouldShowAddUserButton { - StreamIconButton(role: .primary, style: .solid, size: .small) { - addUsersShown = true - } icon: { - Image(systemName: "person.badge.plus") - } - } - } - } - .navigationBarTitleDisplayMode(.inline) - } - .sheet(item: $selectedParticipant) { participant in - ParticipantInfoView( - factory: factory, - participant: participant, - actions: viewModel.participantActions(for: participant) - ) { - selectedParticipant = nil - } - .modifier(PresentationDetentsModifier(sheetSizes: [.custom(280), .medium])) - } - .sheet(isPresented: $addUsersShown) { - factory.makeAddUsersView( - options: AddUsersViewOptions( - options: .init(loadedUserIds: viewModel.allMemberIds), - onConfirm: { users in - viewModel.addUsersTapped(users) - addUsersShown = false - } - ) - ) - } - } -} - public final class ParticipantInfo: Identifiable { public var id: String { chatUser.id diff --git a/Sources/StreamChatSwiftUI/ChatChannel/ChannelInfo/ChatChannelInfoView.swift b/Sources/StreamChatSwiftUI/ChatChannel/ChannelInfo/ChatChannelInfoView.swift index 0b4275c33..a572a7dfb 100644 --- a/Sources/StreamChatSwiftUI/ChatChannel/ChannelInfo/ChatChannelInfoView.swift +++ b/Sources/StreamChatSwiftUI/ChatChannel/ChannelInfo/ChatChannelInfoView.swift @@ -82,8 +82,8 @@ public struct ChatChannelInfoView: View, KeyboardReadable EditGroupView(factory: factory, viewModel: viewModel) } .sheet(isPresented: $viewModel.addUsersShown) { - factory.makeAddUsersView( - options: AddUsersViewOptions( + factory.makeMemberAddView( + options: MemberAddViewOptions( options: .init(loadedUserIds: viewModel.allMemberIds), onConfirm: viewModel.addUsersTapped(_:) ) @@ -153,7 +153,7 @@ public struct ChatChannelInfoView: View, KeyboardReadable participant: participant ) } else { - ChatInfoGroupHeaderView(viewModel: viewModel) + ChatInfoGroupHeaderView(factory: factory, viewModel: viewModel) } } @@ -216,7 +216,7 @@ public struct ChatChannelInfoView: View, KeyboardReadable Spacer() - if viewModel.shouldShowAddUserButton { + if viewModel.shouldShowAddMemberButton { StreamTextButton(role: .secondary, style: .outline, size: .small) { viewModel.addUsersShown = true } text: { @@ -324,7 +324,7 @@ public struct ChatChannelInfoView: View, KeyboardReadable .padding(.horizontal, tokens.spacingMd) .padding(.vertical, tokens.spacingMd) .font(fonts.body) - .foregroundColor(Color(colors.alert)) + .foregroundColor(Color(colors.accentError)) .background(Color(colors.backgroundCoreSurfaceSubtle)) } } @@ -378,7 +378,7 @@ struct ChatChannelInfoViewHeaderViewModifier: ViewModifier { Text(L10n.ChatInfo.edit) .font(fonts.bodyBold) } - .modifier(LiquidGlassModifier(shape: Capsule(), isInteractive: true)) + .modifier(LiquidGlassBorderlessModifier(shape: Capsule(), isInteractive: true)) } else { StreamTextButton(role: .secondary, style: .outline, size: .medium) { viewModel.editGroupShown = true diff --git a/Sources/StreamChatSwiftUI/ChatChannel/ChannelInfo/ChatChannelInfoViewModel.swift b/Sources/StreamChatSwiftUI/ChatChannel/ChannelInfo/ChatChannelInfoViewModel.swift index 13281a125..ed2cd1513 100644 --- a/Sources/StreamChatSwiftUI/ChatChannel/ChannelInfo/ChatChannelInfoViewModel.swift +++ b/Sources/StreamChatSwiftUI/ChatChannel/ChannelInfo/ChatChannelInfoViewModel.swift @@ -5,7 +5,6 @@ import Combine import Foundation import StreamChat -import StreamChatCommonUI import SwiftUI // View model for the `ChatChannelInfoView`. @@ -73,7 +72,7 @@ import SwiftUI channel.ownCapabilities.contains(.updateChannel) } - open var shouldShowAddUserButton: Bool { + open var shouldShowAddMemberButton: Bool { if channel.isDirectMessageChannel { false } else { @@ -563,7 +562,7 @@ import SwiftUI ) return ParticipantAction( title: title, - iconName: "icn_block_user", + iconName: "nosign", action: action, confirmationPopup: confirmationPopup, isDestructive: false diff --git a/Sources/StreamChatSwiftUI/ChatChannel/ChannelInfo/EditGroupView.swift b/Sources/StreamChatSwiftUI/ChatChannel/ChannelInfo/EditGroupView.swift index 4d70ae336..e43c307db 100644 --- a/Sources/StreamChatSwiftUI/ChatChannel/ChannelInfo/EditGroupView.swift +++ b/Sources/StreamChatSwiftUI/ChatChannel/ChannelInfo/EditGroupView.swift @@ -88,11 +88,13 @@ public struct EditGroupView: View { .frame(width: AvatarSize.extraExtraLarge, height: AvatarSize.extraExtraLarge) .clipShape(Circle()) } else { - ChannelAvatar( - channel: viewModel.channel, - size: AvatarSize.extraExtraLarge, - showsIndicator: false, - showsBorder: false + factory.makeChannelAvatarView( + options: ChannelAvatarViewOptions( + channel: viewModel.channel, + size: AvatarSize.extraExtraLarge, + showsIndicator: false, + showsBorder: false + ) ) } } @@ -160,7 +162,7 @@ struct GroupAvatarPickerSheetView: View { ) Spacer() } - .background(Color(colors.backgroundElevationElevation1).edgesIgnoringSafeArea(.all)) + .background(Color(colors.backgroundCoreElevation1).edgesIgnoringSafeArea(.all)) .navigationBarTitleDisplayMode(.inline) .toolbar { ToolbarItem(placement: .principal) { @@ -190,10 +192,10 @@ struct GroupAvatarPickerSheetView: View { HStack(spacing: tokens.spacingMd) { Image(systemName: iconName) .frame(width: tokens.spacingLg) - .foregroundColor(isDestructive ? Color(colors.alert) : Color(colors.textPrimary)) + .foregroundColor(isDestructive ? Color(colors.accentError) : Color(colors.textPrimary)) Text(title) .font(fonts.body) - .foregroundColor(isDestructive ? Color(colors.alert) : Color(colors.textPrimary)) + .foregroundColor(isDestructive ? Color(colors.accentError) : Color(colors.textPrimary)) Spacer() } .padding(.horizontal, tokens.spacingMd) diff --git a/Sources/StreamChatSwiftUI/ChatChannel/ChannelInfo/FileAttachmentsView.swift b/Sources/StreamChatSwiftUI/ChatChannel/ChannelInfo/FileAttachmentsView.swift index b0690d3ad..03872beb6 100644 --- a/Sources/StreamChatSwiftUI/ChatChannel/ChannelInfo/FileAttachmentsView.swift +++ b/Sources/StreamChatSwiftUI/ChatChannel/ChannelInfo/FileAttachmentsView.swift @@ -30,7 +30,7 @@ public struct FileAttachmentsView: View { if viewModel.loading { LoadingView() } else if viewModel.attachmentsDataSource.isEmpty { - NoContentView( + EmptyContentView( image: images.noMedia, title: L10n.ChatInfo.Files.emptyTitle, description: L10n.ChatInfo.Files.emptyDesc @@ -39,7 +39,7 @@ public struct FileAttachmentsView: View { ScrollView { LazyVStack(spacing: 0) { ForEach(viewModel.attachmentsDataSource) { monthlyDataSource in - ForEach(monthlyDataSource.attachments, id: \.self) { attachment in + ForEach(monthlyDataSource.attachments) { attachment in let url = attachment.assetURL Button { @@ -62,7 +62,6 @@ public struct FileAttachmentsView: View { } .padding(.vertical, tokens.spacingSm) .padding(.horizontal) - .withDownloadingStateIndicator(for: attachment.downloadingState, url: attachment.assetURL) .sheet(item: $viewModel.selectedAttachment) { item in FileAttachmentPreview(attachment: item) } diff --git a/Sources/StreamChatSwiftUI/ChatChannel/ChannelInfo/MediaAttachmentsView.swift b/Sources/StreamChatSwiftUI/ChatChannel/ChannelInfo/MediaAttachmentsView.swift index 75e29299c..e62459bc7 100644 --- a/Sources/StreamChatSwiftUI/ChatChannel/ChannelInfo/MediaAttachmentsView.swift +++ b/Sources/StreamChatSwiftUI/ChatChannel/ChannelInfo/MediaAttachmentsView.swift @@ -4,7 +4,6 @@ import AVFoundation import StreamChat -import StreamChatCommonUI import SwiftUI /// View displaying media attachments. @@ -37,7 +36,7 @@ public struct MediaAttachmentsView: View { if viewModel.loading { LoadingView() } else if viewModel.mediaItems.isEmpty { - NoContentView( + EmptyContentView( image: images.noMedia, title: L10n.ChatInfo.Media.emptyTitle, description: L10n.ChatInfo.Media.emptyDesc @@ -66,12 +65,14 @@ public struct MediaAttachmentsView: View { /// View displaying a grid of media attachments using an adaptive column layout. struct MediaAttachmentsGridView: View { @Injected(\.tokens) private var tokens + @Injected(\.colors) private var colors let factory: Factory let attachments: [MediaAttachment] let mediaItems: [MediaItem]? let showAvatars: Bool let onItemAppear: ((Int) -> Void)? + let onItemSelected: ((Int) -> Void)? private let targetItemWidth: CGFloat = 120 @@ -80,13 +81,15 @@ struct MediaAttachmentsGridView: View { attachments: [MediaAttachment], mediaItems: [MediaItem]? = nil, showAvatars: Bool = true, - onItemAppear: ((Int) -> Void)? = nil + onItemAppear: ((Int) -> Void)? = nil, + onItemSelected: ((Int) -> Void)? = nil ) { self.factory = factory self.attachments = attachments self.mediaItems = mediaItems self.showAvatars = showAvatars self.onItemAppear = onItemAppear + self.onItemSelected = onItemSelected } public var body: some View { @@ -149,13 +152,26 @@ struct MediaAttachmentsGridView: View { ) .overlay( Circle() - .stroke(Color.white, lineWidth: 1) + .stroke(colors.borderCoreInverse.toColor, lineWidth: 2) ) .padding(.all, 8) } } } ) + } else if let onItemSelected { + Button { + onItemSelected(index) + } label: { + LazyLoadingImage( + source: attachments[index], + width: itemWidth, + height: itemWidth, + showVideoIcon: false + ) + .frame(width: itemWidth, height: itemWidth) + .clipped() + } } else { LazyLoadingImage( source: attachments[index], diff --git a/Sources/StreamChatSwiftUI/ChatChannel/ChannelInfo/MediaAttachmentsViewModel.swift b/Sources/StreamChatSwiftUI/ChatChannel/ChannelInfo/MediaAttachmentsViewModel.swift index b2f5a8afd..5f79d8d8c 100644 --- a/Sources/StreamChatSwiftUI/ChatChannel/ChannelInfo/MediaAttachmentsViewModel.swift +++ b/Sources/StreamChatSwiftUI/ChatChannel/ChannelInfo/MediaAttachmentsViewModel.swift @@ -129,9 +129,9 @@ public final class MediaItem: Identifiable { @MainActor public var mediaAttachment: MediaAttachment? { if let videoAttachment { - return MediaAttachment(url: videoAttachment.videoURL, type: .video) + return MediaAttachment(from: videoAttachment) } else if let imageAttachment { - return MediaAttachment(url: imageAttachment.imageURL, type: .image) + return MediaAttachment(from: imageAttachment) } return nil } diff --git a/Sources/StreamChatSwiftUI/ChatChannel/ChannelInfo/AddUsersView.swift b/Sources/StreamChatSwiftUI/ChatChannel/ChannelInfo/MemberAddView.swift similarity index 78% rename from Sources/StreamChatSwiftUI/ChatChannel/ChannelInfo/AddUsersView.swift rename to Sources/StreamChatSwiftUI/ChatChannel/ChannelInfo/MemberAddView.swift index f38f5286c..f04a316ac 100644 --- a/Sources/StreamChatSwiftUI/ChatChannel/ChannelInfo/AddUsersView.swift +++ b/Sources/StreamChatSwiftUI/ChatChannel/ChannelInfo/MemberAddView.swift @@ -7,13 +7,13 @@ import SwiftUI /// Full-sheet view for adding members to a channel. /// Supports search, pagination, and multi-select with a batch confirm action. -public struct AddUsersView: View { +public struct MemberAddView: View { @Injected(\.colors) private var colors @Environment(\.presentationMode) private var presentationMode private let factory: Factory - @StateObject private var viewModel: AddUsersViewModel + @StateObject private var viewModel: MemberAddViewModel var onConfirm: @MainActor ([ChatUser]) -> Void public init( @@ -22,7 +22,7 @@ public struct AddUsersView: View { onConfirm: @escaping @MainActor ([ChatUser]) -> Void ) { _viewModel = StateObject( - wrappedValue: AddUsersViewModel(loadedUserIds: loadedUserIds) + wrappedValue: MemberAddViewModel(loadedUserIds: loadedUserIds) ) self.onConfirm = onConfirm self.factory = factory @@ -30,7 +30,7 @@ public struct AddUsersView: View { init( factory: Factory = DefaultViewFactory.shared, - viewModel: AddUsersViewModel, + viewModel: MemberAddViewModel, onConfirm: @escaping @MainActor ([ChatUser]) -> Void ) { _viewModel = StateObject(wrappedValue: viewModel) @@ -62,7 +62,8 @@ public struct AddUsersView: View { )) .background(Color(colors.backgroundCoreApp).edgesIgnoringSafeArea(.all)) .modifier( - AddMembersToolbarModifier( + MemberAddToolbarModifier( + factory: factory, viewModel: viewModel, onConfirm: { onConfirm(viewModel.selectedUsers) }, onDismiss: { presentationMode.wrappedValue.dismiss() } @@ -73,8 +74,8 @@ public struct AddUsersView: View { } } -/// Options used in the add users view. -public final class AddUsersOptions: Sendable { +/// Options used in the member add view. +public final class MemberAddOptions: Sendable { public let loadedUserIds: [String] public init(loadedUserIds: [String]) { @@ -155,54 +156,51 @@ private struct AddMembersUserRow: View { // MARK: - Toolbar -private struct AddMembersToolbarModifier: ViewModifier { +private struct MemberAddToolbarModifier: ViewModifier { @Injected(\.colors) private var colors @Injected(\.fonts) private var fonts - @Injected(\.images) private var images @Injected(\.tokens) private var tokens - @ObservedObject var viewModel: AddUsersViewModel + let factory: Factory + @ObservedObject var viewModel: MemberAddViewModel let onConfirm: () -> Void let onDismiss: () -> Void func body(content: Content) -> some View { - if #available(iOS 26.0, *) { - content - .toolbarThemed { - toolbarContent() - #if compiler(>=6.2) - .sharedBackgroundVisibility(.hidden) - #endif - } - } else { - content - .toolbarThemed { - toolbarContent() - } - } + content + .toolbarThemed { + toolbarContent() + } } @ToolbarContentBuilder private func toolbarContent() -> some ToolbarContent { + ToolbarItem(placement: .navigationBarLeading) { + Button(action: onDismiss) { + Image(systemName: "xmark") + .renderingMode(.template) + .font(.system(size: 12)) + .foregroundColor(Color(colors.buttonSecondaryText)) + } + } + ToolbarItem(placement: .principal) { Text(L10n.ChatInfo.Members.addMembersTitle) .font(fonts.bodyBold) .foregroundColor(Color(colors.navigationBarTitle)) } - ToolbarItem(placement: .navigationBarLeading) { - Button(action: onDismiss) { - Image(uiImage: images.close) - .foregroundColor(Color(colors.textSecondary)) - } + + ToolbarItem(placement: .topBarTrailing) { + confirmButton } - ToolbarItem(placement: .navigationBarTrailing) { - Button(action: onConfirm) { - Image(uiImage: images.selectionBadgeIcon) - .customizable() - .frame(width: tokens.iconSizeSm) - .foregroundColor(Color(colors.buttonPrimaryTextOnAccent)) - } - .frame(width: tokens.buttonVisualHeightMd) - .background(Circle().fill(Color(colors.accentPrimary))) + } + + private var confirmButton: some View { + Button(action: onConfirm) { + Image(systemName: "checkmark") + .renderingMode(.template) + .font(.system(size: 16)) + .foregroundColor(Color(colors.buttonPrimaryTextOnAccent)) } + .modifier(factory.styles.makeToolbarConfirmActionModifier(options: .init())) } } diff --git a/Sources/StreamChatSwiftUI/ChatChannel/ChannelInfo/AddUsersViewModel.swift b/Sources/StreamChatSwiftUI/ChatChannel/ChannelInfo/MemberAddViewModel.swift similarity index 96% rename from Sources/StreamChatSwiftUI/ChatChannel/ChannelInfo/AddUsersViewModel.swift rename to Sources/StreamChatSwiftUI/ChatChannel/ChannelInfo/MemberAddViewModel.swift index 0b8339d88..6cb54d887 100644 --- a/Sources/StreamChatSwiftUI/ChatChannel/ChannelInfo/AddUsersViewModel.swift +++ b/Sources/StreamChatSwiftUI/ChatChannel/ChannelInfo/MemberAddViewModel.swift @@ -6,8 +6,8 @@ import Combine import StreamChat import SwiftUI -/// View model for the `AddUsersView`. -@MainActor class AddUsersViewModel: ObservableObject { +/// View model for the `MemberAddView`. +@MainActor class MemberAddViewModel: ObservableObject { @Injected(\.chatClient) private var chatClient @Published var users = [ChatUser]() diff --git a/Sources/StreamChatSwiftUI/ChatChannel/ChannelInfo/MemberListView.swift b/Sources/StreamChatSwiftUI/ChatChannel/ChannelInfo/MemberListView.swift new file mode 100644 index 000000000..2419cadc0 --- /dev/null +++ b/Sources/StreamChatSwiftUI/ChatChannel/ChannelInfo/MemberListView.swift @@ -0,0 +1,97 @@ +// +// Copyright © 2026 Stream.io Inc. All rights reserved. +// + +import StreamChat +import SwiftUI + +/// A view that displays the full member list for a group channel, presented as a sheet. +public struct MemberListView: View { + @Injected(\.colors) private var colors + @Injected(\.fonts) private var fonts + @Injected(\.tokens) private var tokens + @Injected(\.chatClient) private var chatClient + + let factory: Factory + @ObservedObject var viewModel: ChatChannelInfoViewModel + @State private var selectedParticipant: ParticipantInfo? + @State private var addUsersShown = false + + public init(factory: Factory = DefaultViewFactory.shared, viewModel: ChatChannelInfoViewModel) { + self.factory = factory + self.viewModel = viewModel + } + + public var body: some View { + NavigationView { + ScrollView { + LazyVStack(spacing: 0) { + ForEach(viewModel.allParticipants) { participant in + ChatInfoMemberView( + factory: factory, + participant: participant, + backgroundColor: colors.backgroundCoreApp, + onAppear: { viewModel.onMemberAppear(participant) }, + onTap: { + selectedParticipant = participant + } + ) + } + } + } + .background(Color(colors.backgroundCoreApp).edgesIgnoringSafeArea(.all)) + .toolbarThemed { + ToolbarItem(placement: .navigationBarLeading) { + Button { + viewModel.memberListSheetShown = false + } label: { + Image(systemName: "xmark") + .renderingMode(.template) + .font(.system(size: 12)) + .foregroundColor(Color(colors.buttonSecondaryText)) + } + } + ToolbarItem(placement: .principal) { + Text(L10n.ChatInfo.Members.count(viewModel.channel.memberCount)) + .font(fonts.bodyBold) + .foregroundColor(Color(colors.navigationBarTitle)) + } + ToolbarItem(placement: .topBarTrailing) { + if viewModel.shouldShowAddMemberButton { + Button { + addUsersShown = true + } label: { + Image(systemName: "person.badge.plus") + .renderingMode(.template) + .font(.system(size: 16)) + .foregroundColor(Color(colors.buttonPrimaryTextOnAccent)) + } + .modifier(factory.styles.makeToolbarConfirmActionModifier(options: .init())) + } + } + } + .navigationBarTitleDisplayMode(.inline) + } + .sheet(item: $selectedParticipant) { participant in + ParticipantInfoView( + factory: factory, + participant: participant, + actions: viewModel.participantActions(for: participant) + ) { + selectedParticipant = nil + } + .modifier(PresentationDetentsModifier(sheetSizes: [.custom(280), .medium])) + } + .sheet(isPresented: $addUsersShown) { + factory.makeMemberAddView( + options: MemberAddViewOptions( + options: .init(loadedUserIds: viewModel.allMemberIds), + onConfirm: { users in + viewModel.addUsersTapped(users) + addUsersShown = false + } + ) + ) + } + } +} diff --git a/Sources/StreamChatSwiftUI/ChatChannel/ChannelInfo/ParticipantInfoView.swift b/Sources/StreamChatSwiftUI/ChatChannel/ChannelInfo/ParticipantInfoView.swift index b5ed6211e..a8b488c04 100644 --- a/Sources/StreamChatSwiftUI/ChatChannel/ChannelInfo/ParticipantInfoView.swift +++ b/Sources/StreamChatSwiftUI/ChatChannel/ChannelInfo/ParticipantInfoView.swift @@ -67,7 +67,7 @@ struct ParticipantInfoView: View { Spacer() } } - .background(Color(colors.backgroundElevationElevation1).edgesIgnoringSafeArea(.all)) + .background(Color(colors.backgroundCoreSurfaceCard).edgesIgnoringSafeArea(.all)) .navigationBarHidden(true) } .alert(isPresented: $alertShown) { @@ -130,6 +130,7 @@ struct ParticipantInfoView: View { .frame(width: tokens.spacingLg) .foregroundColor(action.isDestructive ? Color(colors.accentError) : Color(colors.textSecondary)) Text(action.title) + .lineLimit(1) .font(fonts.body) .foregroundColor(action.isDestructive ? Color(colors.accentError) : Color(colors.textPrimary)) Spacer() diff --git a/Sources/StreamChatSwiftUI/ChatChannel/ChannelInfo/PinnedMessagesView.swift b/Sources/StreamChatSwiftUI/ChatChannel/ChannelInfo/PinnedMessagesView.swift index 433d33bd0..f4563ed9f 100644 --- a/Sources/StreamChatSwiftUI/ChatChannel/ChannelInfo/PinnedMessagesView.swift +++ b/Sources/StreamChatSwiftUI/ChatChannel/ChannelInfo/PinnedMessagesView.swift @@ -67,7 +67,7 @@ public struct PinnedMessagesView: View { } } } else { - NoContentView( + EmptyContentView( image: images.pin, title: L10n.ChatInfo.PinnedMessages.emptyTitle, description: L10n.ChatInfo.PinnedMessages.emptyDesc @@ -130,7 +130,7 @@ struct PinnedMessageView: View { VStack(alignment: .leading, spacing: tokens.spacingXxs) { Text(message.author.name ?? message.author.id) .font(fonts.bodyBold) - .foregroundColor(Color(colors.text)) + .foregroundColor(Color(colors.textPrimary)) HStack { HStack(spacing: tokens.spacingXxs) { @@ -139,7 +139,7 @@ struct PinnedMessageView: View { } .lineLimit(1) .font(fonts.footnote) - .foregroundColor(Color(colors.textLowEmphasis)) + .foregroundColor(Color(colors.textTertiary)) Spacer() @@ -163,7 +163,7 @@ struct PinnedMessageView: View { if let iconImage = previewAttachmentIconImage { Image(uiImage: iconImage) .customizable() - .frame(maxHeight: 12) + .frame(width: tokens.iconSizeSm, height: tokens.iconSizeSm) .accessibilityHidden(true) } } diff --git a/Sources/StreamChatSwiftUI/ChatChannel/ChatChannelView.swift b/Sources/StreamChatSwiftUI/ChatChannel/ChatChannelView.swift index bfd64abfc..c7791f179 100644 --- a/Sources/StreamChatSwiftUI/ChatChannel/ChatChannelView.swift +++ b/Sources/StreamChatSwiftUI/ChatChannel/ChatChannelView.swift @@ -86,7 +86,10 @@ public struct ChatChannelView: View, KeyboardReadable { } .overlay( viewModel.currentDateString != nil ? - factory.makeDateIndicatorView(options: DateIndicatorViewOptions(dateString: viewModel.currentDateString!)) + VStack { + factory.makeDateIndicatorView(options: DateIndicatorViewOptions(dateString: viewModel.currentDateString!)) + Spacer() + } : nil ) } else { @@ -210,7 +213,7 @@ public struct ChatChannelView: View, KeyboardReadable { messageDisplayInfo = nil } .background( - Color(factory.styles.composerPlacement == .docked ? colors.composerBackground : .clear) + Color(factory.styles.composerPlacement == .docked ? colors.backgroundCoreElevation1 : .clear) .background( TabBarAccessor { _ in tabBarAvailable = utils.messageListConfig.handleTabBarVisibility @@ -241,7 +244,7 @@ public struct ChatChannelView: View, KeyboardReadable { messageController: viewModel.messageController, quotedMessage: $viewModel.quotedMessage, editedMessage: $viewModel.editedMessage, - onMessageSent: { + willSendMessage: { viewModel.messageSentTapped() } ) diff --git a/Sources/StreamChatSwiftUI/ChatChannel/ChatChannelViewModel.swift b/Sources/StreamChatSwiftUI/ChatChannel/ChatChannelViewModel.swift index 13f82a125..e9888a008 100644 --- a/Sources/StreamChatSwiftUI/ChatChannel/ChatChannelViewModel.swift +++ b/Sources/StreamChatSwiftUI/ChatChannel/ChatChannelViewModel.swift @@ -266,7 +266,7 @@ import SwiftUI resignFirstResponder() guard let messageId = notification.userInfo?[MessageRepliesConstants.channelMessageMessageId] as? String else { return } threadMessageShown = false - _ = jumpToMessage(messageId: messageId) + _ = jumpToMessage(messageId: messageId, skipThreadNavigation: true) } @objc @@ -310,6 +310,10 @@ import SwiftUI } public func jumpToMessage(messageId: String) -> Bool { + jumpToMessage(messageId: messageId, skipThreadNavigation: false) + } + + private func jumpToMessage(messageId: String, skipThreadNavigation: Bool) -> Bool { if messageId == .unknownMessageId { if firstUnreadMessageId == nil, let lastReadMessageId { scrollsToUnreadAfterJumpToMessage = true @@ -339,7 +343,7 @@ import SwiftUI return true } else { let message = channelController.dataStore.message(id: baseId) - if let parentMessageId = message?.parentMessageId, !isMessageThread { + if let parentMessageId = message?.parentMessageId, !isMessageThread, !skipThreadNavigation { let parentMessage = channelController.dataStore.message(id: parentMessageId) threadMessage = parentMessage threadMessageShown = true diff --git a/Sources/StreamChatSwiftUI/ChatChannel/Utils/ChatChannelExtensions.swift b/Sources/StreamChatSwiftUI/ChatChannel/Utils/ChatChannelExtensions.swift index 6e5f5f2a4..f0fbd3b0e 100644 --- a/Sources/StreamChatSwiftUI/ChatChannel/Utils/ChatChannelExtensions.swift +++ b/Sources/StreamChatSwiftUI/ChatChannel/Utils/ChatChannelExtensions.swift @@ -4,7 +4,6 @@ import Foundation import StreamChat -import StreamChatCommonUI extension ChatChannel { /// Returns the online info text for a channel. diff --git a/Sources/StreamChatSwiftUI/ChatChannelList/ChatChannelList.swift b/Sources/StreamChatSwiftUI/ChatChannelList/ChatChannelList.swift index 5654b0fb7..5bdad7c6a 100644 --- a/Sources/StreamChatSwiftUI/ChatChannelList/ChatChannelList.swift +++ b/Sources/StreamChatSwiftUI/ChatChannelList/ChatChannelList.swift @@ -18,7 +18,7 @@ public struct ChannelList: View { private var scrollable: Bool private var onItemTap: @MainActor (ChatChannel) -> Void private var onItemAppear: @MainActor (Int) -> Void - private var channelDestination: @MainActor (ChannelSelectionInfo) -> Factory.ChannelDestination + private var channelDestination: (@MainActor (ChannelSelectionInfo) -> Factory.ChannelDestination)? private var trailingSwipeRightButtonTapped: @MainActor (ChatChannel) -> Void private var trailingSwipeLeftButtonTapped: @MainActor (ChatChannel) -> Void private var leadingSwipeButtonTapped: @MainActor (ChatChannel) -> Void @@ -32,7 +32,7 @@ public struct ChannelList: View { scrollable: Bool = true, onItemTap: @escaping @MainActor (ChatChannel) -> Void, onItemAppear: @escaping @MainActor (Int) -> Void, - channelDestination: @escaping @MainActor (ChannelSelectionInfo) -> Factory.ChannelDestination, + channelDestination: (@MainActor (ChannelSelectionInfo) -> Factory.ChannelDestination)? = nil, trailingSwipeRightButtonTapped: @escaping @MainActor (ChatChannel) -> Void = { _ in }, trailingSwipeLeftButtonTapped: @escaping @MainActor (ChatChannel) -> Void = { _ in }, leadingSwipeButtonTapped: @escaping @MainActor (ChatChannel) -> Void = { _ in } @@ -100,7 +100,7 @@ public struct ChannelsLazyVStack: View { @Binding var swipedChannelId: String? private var onItemTap: @MainActor (ChatChannel) -> Void private var onItemAppear: @MainActor (Int) -> Void - private var channelDestination: @MainActor (ChannelSelectionInfo) -> Factory.ChannelDestination + private var channelDestination: (@MainActor (ChannelSelectionInfo) -> Factory.ChannelDestination)? private var trailingSwipeRightButtonTapped: @MainActor (ChatChannel) -> Void private var trailingSwipeLeftButtonTapped: @MainActor (ChatChannel) -> Void private var leadingSwipeButtonTapped: @MainActor (ChatChannel) -> Void @@ -112,7 +112,7 @@ public struct ChannelsLazyVStack: View { swipedChannelId: Binding, onItemTap: @escaping @MainActor (ChatChannel) -> Void, onItemAppear: @escaping @MainActor (Int) -> Void, - channelDestination: @escaping @MainActor (ChannelSelectionInfo) -> Factory.ChannelDestination, + channelDestination: (@MainActor (ChannelSelectionInfo) -> Factory.ChannelDestination)? = nil, trailingSwipeRightButtonTapped: @escaping @MainActor (ChatChannel) -> Void, trailingSwipeLeftButtonTapped: @escaping @MainActor (ChatChannel) -> Void, leadingSwipeButtonTapped: @escaping @MainActor (ChatChannel) -> Void diff --git a/Sources/StreamChatSwiftUI/ChatChannelList/ChatChannelListItem.swift b/Sources/StreamChatSwiftUI/ChatChannelList/ChatChannelListItem.swift index c4c4dadb2..b58c71af3 100644 --- a/Sources/StreamChatSwiftUI/ChatChannelList/ChatChannelListItem.swift +++ b/Sources/StreamChatSwiftUI/ChatChannelList/ChatChannelListItem.swift @@ -3,7 +3,6 @@ // import StreamChat -import StreamChatCommonUI import SwiftUI /// View for the channel list item. @@ -18,7 +17,7 @@ public struct ChatChannelListItem: View { var factory: Factory var channel: ChatChannel var channelName: String - var injectedChannelInfo: InjectedChannelInfo? + var isSelected: Bool var disabled = false var onItemTap: (ChatChannel) -> Void @@ -26,14 +25,14 @@ public struct ChatChannelListItem: View { factory: Factory = DefaultViewFactory.shared, channel: ChatChannel, channelName: String, - injectedChannelInfo: InjectedChannelInfo? = nil, + isSelected: Bool = false, disabled: Bool = false, onItemTap: @escaping (ChatChannel) -> Void ) { self.factory = factory self.channel = channel self.channelName = channelName - self.injectedChannelInfo = injectedChannelInfo + self.isSelected = isSelected self.disabled = disabled self.onItemTap = onItemTap } @@ -63,23 +62,13 @@ public struct ChatChannelListItem: View { Spacer() - HStack(spacing: tokens.spacingXs) { - SubtitleText( - text: injectedChannelInfo?.timestamp ?? channel.timestampText, - color: Color(colors.textTertiary) - ) - .accessibilityIdentifier("timestampView") - - if lastMessageFailedToSend { - Image(uiImage: images.messageListErrorIndicator) - .customizable() - .frame(width: 16, height: 16) - .foregroundColor(Color(colors.badgeBackgroundError)) - .accessibilityHidden(true) - } - } + SubtitleText( + text: timestampText, + color: Color(colors.textTertiary) + ) + .accessibilityIdentifier("timestampView") - if injectedChannelInfo == nil && channel.unreadCount != .noUnread { + if !isSelected && channel.unreadCount != .noUnread { BadgeNotificationView( count: channel.unreadCount.messages ) @@ -91,9 +80,10 @@ public struct ChatChannelListItem: View { MessageReadIndicatorView( readUsers: channel.readUsers( currentUserId: chatClient.currentUserId, - message: channel.previewMessage + message: previewMessage ), - showDelivered: channel.previewMessage?.deliveryStatus(for: channel) == .delivered + showDelivered: previewMessage?.deliveryStatus(for: channel) == .delivered, + localState: previewMessage?.localState ) } @@ -118,26 +108,72 @@ public struct ChatChannelListItem: View { utils.channelListConfig.channelItemMutedStyle } + private var previewMessage: ChatMessage? { + channel.latestMessages.first(where: { $0.type != .ephemeral }) + } + + private var shouldShowTypingIndicator: Bool { + !channel.currentlyTypingUsersFiltered( + currentUserId: chatClient.currentUserId + ).isEmpty && channel.config.typingEventsEnabled + } + + private var draftMessageText: String? { + guard let draftMessage = channel.draftMessage else { return nil } + return utils.messagePreviewFormatter.formatContent(for: ChatMessage(draftMessage), in: channel) + } + + private var timestampText: String { + if let lastMessageAt = channel.lastMessageAt { + return utils.messageTimestampFormatter.format(lastMessageAt) + } + return "" + } + private var subtitleView: some View { HStack(spacing: 4) { if lastMessageFailedToSend { - Text(L10n.Channel.Item.messageFailedToSend) - .font(fonts.subheadline) - .foregroundColor(Color(colors.accentError)) - .lineLimit(1) - } else if channel.shouldShowTypingIndicator { + HStack(spacing: tokens.spacingXxs) { + Image(uiImage: images.messageListErrorIndicator) + .customizable() + .frame(width: 16, height: 16) + .foregroundColor(Color(colors.badgeBackgroundError)) + .accessibilityHidden(true) + Text(L10n.Channel.Item.messageFailedToSend) + } + .font(fonts.subheadline) + .foregroundColor(Color(colors.accentError)) + .lineLimit(1) + } else if shouldShowTypingIndicator { factory.makeSubtitleTypingIndicatorView( options: SubtitleTypingIndicatorViewOptions(channel: channel) ) - } else if utils.messageListConfig.draftMessagesEnabled, let draftText = channel.draftMessageText { + } else if utils.messageListConfig.draftMessagesEnabled, let draftText = draftMessageText { HStack(spacing: 2) { Text("\(L10n.Message.Preview.draft): ") .font(fonts.subheadline).fontWeight(.semibold) .foregroundColor(Color(colors.accentPrimary)) SubtitleText(text: draftText) } + } else if previewMessage?.isDeleted == true { + HStack(spacing: tokens.spacingXxs) { + if previewMessage?.isSentByCurrentUser == true { + Text("\(L10n.Channel.Item.you):") + .font(fonts.subheadline) + .fontWeight(.semibold) + } + Image(systemName: "nosign") + .resizable() + .scaledToFit() + .frame(width: 16, height: 16) + .accessibilityHidden(true) + Text(L10n.Message.deletedMessagePlaceholder) + } + .lineLimit(1) + .font(fonts.subheadline) + .foregroundColor(Color(colors.textTertiary)) } else if let authorName = subtitleAuthorName { - let contentString = channel.previewMessage.map { + let contentString = previewMessage.map { utils.messagePreviewFormatter.formatContent(for: $0, in: channel) } ?? subtitleText HStack(spacing: tokens.spacingXxs) { @@ -168,8 +204,8 @@ public struct ChatChannelListItem: View { } private var previewAttachmentIconImage: UIImage? { - guard let previewMessage = channel.previewMessage else { return nil } - let resolver = MessageAttachmentPreviewResolver(message: previewMessage) + guard let message = previewMessage else { return nil } + let resolver = MessageAttachmentPreviewResolver(message: message) guard let previewIcon = resolver.previewIcon else { return nil } return utils.messageAttachmentPreviewIconProvider.image(for: previewIcon) } @@ -179,15 +215,14 @@ public struct ChatChannelListItem: View { if let iconImage = previewAttachmentIconImage { Image(uiImage: iconImage) .customizable() - .frame(maxHeight: 14) + .frame(width: tokens.iconSizeSm, height: tokens.iconSizeSm) .accessibilityHidden(true) } } private var subtitleAuthorName: String? { - guard let previewMessage = channel.previewMessage, + guard let previewMessage, previewMessage.poll == nil, - injectedChannelInfo?.subtitle == nil, !(channel.isDirectMessageChannel && channel.memberCount == 2) else { return nil } @@ -198,42 +233,36 @@ public struct ChatChannelListItem: View { } private var subtitleText: String { - if let injectedSubtitle = injectedChannelInfo?.subtitle { - return injectedSubtitle + if shouldShowTypingIndicator { + return channel.typingIndicatorString(currentUserId: chatClient.currentUserId) } - return channel.subtitleText - } - - private var channelSubtitleText: String { - if channel.shouldShowTypingIndicator { - channel.typingIndicatorString(currentUserId: chatClient.currentUserId) - } else if let previewMessageText = channel.previewMessageText { - previewMessageText - } else { - L10n.Channel.Item.emptyMessages + if let previewMessage { + return utils.messagePreviewFormatter.format(previewMessage, in: channel) } + return L10n.Channel.Item.emptyMessages } private var mutedIcon: some View { Image(uiImage: images.muted) .customizable() - .frame(maxHeight: 12) - .foregroundColor(Color(colors.subtitleText)) + .frame(height: tokens.iconSizeMd) + .foregroundColor(Color(colors.textTertiary)) } private var lastMessageFailedToSend: Bool { - channel.previewMessage?.localState == .sendingFailed + previewMessage?.localState == .sendingFailed } private var shouldShowReadEvents: Bool { - if channel.shouldShowTypingIndicator || lastMessageFailedToSend { + if shouldShowTypingIndicator || lastMessageFailedToSend { return false } - if utils.messageListConfig.draftMessagesEnabled && channel.draftMessageText != nil { + if utils.messageListConfig.draftMessagesEnabled && draftMessageText != nil { return false } - if let message = channel.previewMessage, - message.isSentByCurrentUser { + if let message = previewMessage, + message.isSentByCurrentUser, + !message.isDeleted { return channel.config.readEventsEnabled } @@ -248,74 +277,6 @@ public struct ChatChannelListItem: View { } } -public final class InjectedChannelInfo: Sendable { - public let subtitle: String? - public let unreadCount: Int - public let timestamp: String? - public let lastMessageAt: Date? - public let latestMessages: [ChatMessage]? - - public init( - subtitle: String? = nil, - unreadCount: Int, - timestamp: String? = nil, - lastMessageAt: Date? = nil, - latestMessages: [ChatMessage]? = nil - ) { - self.subtitle = subtitle - self.unreadCount = unreadCount - self.timestamp = timestamp - self.lastMessageAt = lastMessageAt - self.latestMessages = latestMessages - } -} - -extension ChatChannel { - @MainActor public var previewMessageText: String? { - guard let previewMessage else { return nil } - let messageFormatter = InjectedValues[\.utils].messagePreviewFormatter - return messageFormatter.format(previewMessage, in: self) - } - - @MainActor public var draftMessageText: String? { - guard let draftMessage else { return nil } - let messageFormatter = InjectedValues[\.utils].messagePreviewFormatter - return messageFormatter.formatContent(for: ChatMessage(draftMessage), in: self) - } - - @MainActor public var lastMessageText: String? { - guard let latestMessage = latestMessages.first else { return nil } - let messageFormatter = InjectedValues[\.utils].messagePreviewFormatter - return messageFormatter.format(latestMessage, in: self) - } - - @MainActor public var shouldShowTypingIndicator: Bool { - !currentlyTypingUsersFiltered( - currentUserId: InjectedValues[\.chatClient].currentUserId - ).isEmpty && config.typingEventsEnabled - } - - @MainActor public var subtitleText: String { - if shouldShowTypingIndicator { - typingIndicatorString(currentUserId: InjectedValues[\.chatClient].currentUserId) - } else if let previewMessageText { - previewMessageText - } else { - L10n.Channel.Item.emptyMessages - } - } - - @MainActor public var timestampText: String { - if let lastMessageAt { - let utils = InjectedValues[\.utils] - let formatter = utils.messageTimestampFormatter - return formatter.format(lastMessageAt) - } else { - return "" - } - } -} - /// The style for the muted icon in the channel list item. public final class ChannelItemMutedLayoutStyle: Hashable, Sendable { let identifier: String diff --git a/Sources/StreamChatSwiftUI/ChatChannelList/ChatChannelListView.swift b/Sources/StreamChatSwiftUI/ChatChannelList/ChatChannelListView.swift index 7d7c1c7b7..8d3637a6d 100644 --- a/Sources/StreamChatSwiftUI/ChatChannelList/ChatChannelListView.swift +++ b/Sources/StreamChatSwiftUI/ChatChannelList/ChatChannelListView.swift @@ -4,6 +4,7 @@ import StreamChat import SwiftUI +import UIKit /// View for the chat channel list. public struct ChatChannelListView: View { @@ -75,46 +76,61 @@ public struct ChatChannelListView: View { } public var body: some View { - NavigationContainerView(embedInNavigationView: embedInNavigationView) { - content() - } - .sheet(isPresented: $viewModel.channelPopupShown, content: { - channelPopup() - .modifier(PresentationDetentsModifier(sheetSizes: [.custom(280), .medium])) - }) - .if(isIphone || !utils.messageListConfig.iPadSplitViewEnabled, transform: { view in - view.navigationViewStyle(.stack) - }) - .background( - isIphone && handleTabBarVisibility ? - Color.clear.background( - TabBarAccessor { tabBar in - self.tabBar = tabBar - } - ) - .allowsHitTesting(false) - : nil - ) - .onReceive(viewModel.$hideTabBar) { newValue in - if isIphone && handleTabBarVisibility { - setupTabBarAppeareance() - tabBar?.isHidden = newValue + containerView + .sheet(isPresented: $viewModel.channelPopupShown, content: { + channelPopup() + }) + .if(isIphone || !utils.messageListConfig.iPadSplitViewEnabled, transform: { view in + view.navigationViewStyle(.stack) + }) + .background( + isIphone && handleTabBarVisibility ? + Color.clear.background( + TabBarAccessor { tabBar in + self.tabBar = tabBar + } + ) + .allowsHitTesting(false) + : nil + ) + .onReceive(viewModel.$hideTabBar) { newValue in + if isIphone && handleTabBarVisibility { + setupTabBarAppeareance() + tabBar?.isHidden = newValue + } } - } - .accessibilityIdentifier("ChatChannelListView") + .accessibilityIdentifier("ChatChannelListView") } @ViewBuilder - private func content() -> some View { + private var containerView: some View { + if usesIPadSplitView { + if #available(iOS 16, *) { + NavigationSplitView { + content + } detail: { + splitViewDetail() + } + .accentColor(Color(colors.navigationBarTintColor)) + } + } else { + NavigationContainerView(embedInNavigationView: embedInNavigationView) { + content + } + } + } + + private var content: some View { Group { if viewModel.loading { viewFactory.makeLoadingView(options: LoadingViewOptions()) } else if viewModel.channels.isEmpty { - viewFactory.makeNoChannelsView(options: NoChannelsViewOptions()) + viewFactory.makeEmptyChannelsView(options: EmptyChannelsViewOptions()) } else { ChatChannelListContentView( viewFactory: viewFactory, viewModel: viewModel, + channelDestination: usesIPadSplitView ? nil : channelDestination, onItemTap: onItemTap ) } @@ -141,6 +157,14 @@ public struct ChatChannelListView: View { }, secondaryButton: .cancel() ) + case let .muteChannel(channel): + Alert( + title: Text(channel.isMuted ? L10n.Alert.Actions.unmuteChannel : L10n.Alert.Actions.muteChannel), + primaryButton: .default(Text(channel.isMuted ? L10n.Channel.Item.unmute : L10n.Channel.Item.mute)) { + viewModel.mute(channel: channel) + }, + secondaryButton: .cancel() + ) default: Alert.defaultErrorAlert } @@ -149,6 +173,22 @@ public struct ChatChannelListView: View { .navigationBarTitleDisplayMode(utils.channelListConfig.navigationBarDisplayMode) } + private var usesIPadSplitView: Bool { + guard embedInNavigationView, isIPad, utils.messageListConfig.iPadSplitViewEnabled else { + return false + } + + if #available(iOS 16, *) { + return true + } else { + return false + } + } + + private var channelDestination: @MainActor (ChannelSelectionInfo) -> Factory.ChannelDestination { + viewFactory.makeChannelDestination(options: ChannelDestinationOptions()) + } + private func setupTabBarAppeareance() { if #available(iOS 15.0, *) { let tabBarAppearance: UITabBarAppearance = UITabBarAppearance() @@ -181,6 +221,22 @@ public struct ChatChannelListView: View { EmptyView() } } + + @available(iOS 16.0, *) + @ViewBuilder + private func splitViewDetail() -> some View { + NavigationStack { + if let selectedChannel = viewModel.selectedChannel { + channelDestination(selectedChannel) + } else { + viewFactory.makeMessageListBackground( + options: MessageListBackgroundOptions(isInThread: false) + ) + .accessibilityIdentifier("ChatChannelListSplitDetailPlaceholder") + } + } + .id(viewModel.selectedChannel?.id) + } } extension ChatChannelListView where Factory == DefaultViewFactory { @@ -196,15 +252,18 @@ public struct ChatChannelListContentView: View { private var viewFactory: Factory @ObservedObject private var viewModel: ChatChannelListViewModel + private var channelDestination: (@MainActor (ChannelSelectionInfo) -> Factory.ChannelDestination)? private var onItemTap: @MainActor (ChatChannel) -> Void public init( viewFactory: Factory, viewModel: ChatChannelListViewModel, + channelDestination: (@MainActor (ChannelSelectionInfo) -> Factory.ChannelDestination)? = nil, onItemTap: (@MainActor (ChatChannel) -> Void)? = nil ) { self.viewFactory = viewFactory self.viewModel = viewModel + self.channelDestination = channelDestination if let onItemTap { self.onItemTap = onItemTap } else { @@ -246,8 +305,8 @@ public struct ChatChannelListContentView: View { viewModel.checkTabBarAppearance() viewModel.checkForChannels(index: index) }, - channelDestination: viewFactory.makeChannelDestination(options: ChannelDestinationOptions()), - trailingSwipeRightButtonTapped: viewModel.onDeleteTapped(channel:), + channelDestination: channelDestination, + trailingSwipeRightButtonTapped: viewModel.onMuteTapped(channel:), trailingSwipeLeftButtonTapped: viewModel.onMoreTapped(channel:), leadingSwipeButtonTapped: { _ in } ) @@ -261,7 +320,7 @@ public struct ChatChannelListContentView: View { .modifier(viewFactory.styles.makeSearchableModifier( options: SearchableModifierOptions(searchText: $viewModel.searchText) )) - .background(Color(colors.backgroundElevationElevation0)) + .background(Color(colors.backgroundCoreApp)) .modifier(viewFactory.styles.makeChannelListContentModifier(options: ChannelListContentModifierOptions())) } } diff --git a/Sources/StreamChatSwiftUI/ChatChannelList/ChatChannelListViewModel.swift b/Sources/StreamChatSwiftUI/ChatChannelList/ChatChannelListViewModel.swift index c68492924..0caf98bda 100644 --- a/Sources/StreamChatSwiftUI/ChatChannelList/ChatChannelListViewModel.swift +++ b/Sources/StreamChatSwiftUI/ChatChannelList/ChatChannelListViewModel.swift @@ -245,6 +245,10 @@ import UIKit public func onDeleteTapped(channel: ChatChannel) { setChannelAlertType(.deleteChannel(channel)) } + + public func onMuteTapped(channel: ChatChannel) { + setChannelAlertType(.muteChannel(channel)) + } public func onMoreTapped(channel: ChatChannel) { channelPopupType = .moreActions(channel) @@ -263,6 +267,27 @@ import UIKit } } + public func mute(channel: ChatChannel) { + let controller = chatClient.channelController( + for: .init(type: channel.type, id: channel.cid.id) + ) + + if channel.isMuted { + controller.unmuteChannel { [weak self] error in + if error != nil { + self?.setChannelAlertType(.error) + } + } + } else { + controller.muteChannel { [weak self] error in + if error != nil { + self?.setChannelAlertType(.error) + } + } + } + swipedChannelId = nil + } + open func showErrorPopup(_ error: Error?) { setChannelAlertType(.error) } @@ -503,7 +528,7 @@ import UIKit .compactMap { channel in ChannelSelectionInfo( channel: channel, - message: channel.previewMessage, + message: channel.latestMessages.first, searchType: .channels ) } @@ -542,14 +567,8 @@ import UIKit } private func handleChannelAppearance() { - if skippedChannelUpdates && selectedChannel == nil { + if skippedChannelUpdates { updateChannels() - } else if skippedChannelUpdates { - updateSelectedChannelData() - } else if !skippedChannelUpdates && selectedChannel != nil { - if selectedChannel?.injectedChannelInfo == nil { - selectedChannel?.injectedChannelInfo = InjectedChannelInfo(unreadCount: 0) - } } } @@ -562,30 +581,6 @@ import UIKit } } } - - private func updateSelectedChannelData() { - let selected = selectedChannel?.channel - var index: Int? - var temp = Array(controller?.channels ?? []) - for i in 0.. ChannelDestination + private var channelDestination: ((ChannelSelectionInfo) -> ChannelDestination)? private var onItemTap: (ChatChannel) -> Void public init( @@ -24,7 +24,7 @@ public struct ChatChannelNavigatableListItem, - channelDestination: @escaping (ChannelSelectionInfo) -> ChannelDestination, + channelDestination: ((ChannelSelectionInfo) -> ChannelDestination)? = nil, onItemTap: @escaping (ChatChannel) -> Void ) { self.factory = factory @@ -43,32 +43,34 @@ public struct ChatChannelNavigatableListItem, channel: ChatChannel, numberOfTrailingItems: Int = 2, - widthOfTrailingItem: CGFloat = 60, + widthOfTrailingItem: CGFloat = 80, trailingRightButtonTapped: @escaping @MainActor (ChatChannel) -> Void, trailingLeftButtonTapped: @escaping @MainActor (ChatChannel) -> Void, leadingSwipeButtonTapped: @escaping @MainActor (ChatChannel) -> Void @@ -299,16 +299,14 @@ public struct TrailingSwipeActionsView: View { .foregroundColor(Color(colors.textPrimary)) .background(Color(colors.backgroundCoreSurfaceSubtle)) - if channel.ownCapabilities.contains(.deleteChannel) { - ActionItemButton(imageName: "trash", action: { - withAnimation { - rightButtonTapped(channel) - } - }) - .frame(width: buttonWidth) - .foregroundColor(Color(colors.textOnAccent)) - .background(Color(colors.accentError)) - } + ActionItemButton(imageName: channel.isMuted ? "speaker.wave.2" : "speaker.slash", action: { + withAnimation { + rightButtonTapped(channel) + } + }) + .frame(width: buttonWidth) + .foregroundColor(Color(colors.textOnAccent)) + .background(Color(colors.accentPrimary)) } } .opacity(offsetX < -5 ? 1 : 0) diff --git a/Sources/StreamChatSwiftUI/ChatChannelList/DefaultChannelActions.swift b/Sources/StreamChatSwiftUI/ChatChannelList/DefaultChannelActions.swift index d88b84ffb..e5044b4d3 100644 --- a/Sources/StreamChatSwiftUI/ChatChannelList/DefaultChannelActions.swift +++ b/Sources/StreamChatSwiftUI/ChatChannelList/DefaultChannelActions.swift @@ -34,8 +34,6 @@ extension ChannelAction { actions.append(muteAction(for: channel, chatClient: chatClient, onDismiss: onDismiss, onError: onError)) } - actions.append(archiveAction(for: channel, chatClient: chatClient, onDismiss: onDismiss, onError: onError)) - if let otherMember = channel.lastActiveMembers.first(where: { $0.id != chatClient.currentUserId }) { let blockedIds = chatClient.currentUserController().dataStore.currentUser()?.blockedUserIds ?? [] actions.append( @@ -69,8 +67,6 @@ extension ChannelAction { actions.append(muteAction(for: channel, chatClient: chatClient, onDismiss: onDismiss, onError: onError)) } - actions.append(archiveAction(for: channel, chatClient: chatClient, onDismiss: onDismiss, onError: onError)) - if channel.ownCapabilities.contains(.deleteChannel) { actions.append(deleteAction(for: channel, chatClient: chatClient, onDismiss: onDismiss, onError: onError)) } else if channel.ownCapabilities.contains(.leaveChannel), let userId = chatClient.currentUserId { @@ -177,7 +173,7 @@ extension ChannelAction { ) -> ChannelAction { ChannelAction( title: L10n.Alert.Actions.blockUser, - iconName: "icn_block_user", + iconName: "nosign", action: { chatClient.userController(userId: user.id).block { error in if let error { onError(error) } else { onDismiss() } @@ -200,7 +196,7 @@ extension ChannelAction { ) -> ChannelAction { ChannelAction( title: L10n.Alert.Actions.unblockUser, - iconName: "icn_block_user", + iconName: "nosign", action: { chatClient.userController(userId: user.id).unblock { error in if let error { onError(error) } else { onDismiss() } diff --git a/Sources/StreamChatSwiftUI/ChatChannelList/NoChannelsView.swift b/Sources/StreamChatSwiftUI/ChatChannelList/EmptyChannelsView.swift similarity index 80% rename from Sources/StreamChatSwiftUI/ChatChannelList/NoChannelsView.swift rename to Sources/StreamChatSwiftUI/ChatChannelList/EmptyChannelsView.swift index 8016cdb16..fd398d3f7 100644 --- a/Sources/StreamChatSwiftUI/ChatChannelList/NoChannelsView.swift +++ b/Sources/StreamChatSwiftUI/ChatChannelList/EmptyChannelsView.swift @@ -7,16 +7,16 @@ import SwiftUI /// Default SDK implementation for the view displayed when there are no channels available. /// /// Different view can be injected in its place. -public struct NoChannelsView: View { +public struct EmptyChannelsView: View { @Injected(\.images) private var images public var body: some View { - NoContentView( + EmptyContentView( image: images.noContent, title: L10n.Channel.NoContent.title, description: L10n.Channel.NoContent.message, shouldRotateImage: true ) - .accessibilityIdentifier("NoChannelsView") + .accessibilityIdentifier("EmptyChannelsView") } } diff --git a/Sources/StreamChatSwiftUI/ChatChannelList/MoreChannelActionsView.swift b/Sources/StreamChatSwiftUI/ChatChannelList/MoreChannelActionsView.swift index 3edac94d6..c7accbd03 100644 --- a/Sources/StreamChatSwiftUI/ChatChannelList/MoreChannelActionsView.swift +++ b/Sources/StreamChatSwiftUI/ChatChannelList/MoreChannelActionsView.swift @@ -50,12 +50,14 @@ public struct MoreChannelActionsView: View { } public var body: some View { - VStack(alignment: .leading, spacing: 0) { - channelHeader - actionsListView - Spacer() + ScrollView { + VStack(alignment: .leading, spacing: 0) { + channelHeader + actionsListView + Spacer() + } } - .background(colors.background.toColor.edgesIgnoringSafeArea(.all)) + .background(colors.backgroundCoreElevation1.toColor.edgesIgnoringSafeArea(.all)) .alert(isPresented: $viewModel.alertShown) { let title = viewModel.alertAction?.confirmationPopup?.title ?? "" let message = viewModel.alertAction?.confirmationPopup?.message ?? "" @@ -116,11 +118,13 @@ public struct MoreChannelActionsView: View { ) ) } else { - ChannelAvatar( - channel: channel, - size: AvatarSize.large, - showsIndicator: false, - showsBorder: false + factory.makeChannelAvatarView( + options: ChannelAvatarViewOptions( + channel: channel, + size: AvatarSize.large, + showsIndicator: false, + showsBorder: false + ) ) } } @@ -161,6 +165,6 @@ public struct MoreChannelActionsView: View { } } } - .foregroundColor(Color(colors.text)) + .foregroundColor(Color(colors.textPrimary)) } } diff --git a/Sources/StreamChatSwiftUI/ChatChannelList/MoreChannelActionsViewModel.swift b/Sources/StreamChatSwiftUI/ChatChannelList/MoreChannelActionsViewModel.swift index e72c57a1b..a6d56267b 100644 --- a/Sources/StreamChatSwiftUI/ChatChannelList/MoreChannelActionsViewModel.swift +++ b/Sources/StreamChatSwiftUI/ChatChannelList/MoreChannelActionsViewModel.swift @@ -17,9 +17,7 @@ import UIKit /// Private vars. private lazy var channelNameFormatter = utils.channelNameFormatter - private lazy var imageLoader = utils.imageLoader - private lazy var imageCDN = utils.imageCDN - private lazy var placeholder2 = images.userAvatarPlaceholder2 + private lazy var mediaLoader = utils.mediaLoader /// Published vars. @Published var channelActions: [ChannelAction] diff --git a/Sources/StreamChatSwiftUI/ChatChannelList/SearchResultsView.swift b/Sources/StreamChatSwiftUI/ChatChannelList/SearchResultsView.swift index d319cb3d8..5f91abb11 100644 --- a/Sources/StreamChatSwiftUI/ChatChannelList/SearchResultsView.swift +++ b/Sources/StreamChatSwiftUI/ChatChannelList/SearchResultsView.swift @@ -39,7 +39,7 @@ public struct SearchResultsView: View { VStack(spacing: 0) { HStack { Text(L10n.Message.Search.numberOfResults(searchResults.count)) - .foregroundColor(Color(colors.textLowEmphasis)) + .foregroundColor(Color(colors.textTertiary)) .standardPadding() Spacer() } @@ -69,7 +69,7 @@ public struct SearchResultsView: View { .overlay( loadingSearchResults ? ProgressView() : nil ) - .background(Color(colors.backgroundElevationElevation0)) + .background(Color(colors.backgroundCoreApp)) } } diff --git a/Sources/StreamChatSwiftUI/ChatComposer/AttachmentPicker/AttachmentCommandsPickerView.swift b/Sources/StreamChatSwiftUI/ChatComposer/AttachmentPicker/AttachmentCommandsPickerView.swift index f6bd958e9..c02073abf 100644 --- a/Sources/StreamChatSwiftUI/ChatComposer/AttachmentPicker/AttachmentCommandsPickerView.swift +++ b/Sources/StreamChatSwiftUI/ChatComposer/AttachmentPicker/AttachmentCommandsPickerView.swift @@ -51,7 +51,7 @@ public struct AttachmentCommandsPickerView: View { } .padding(.vertical, tokens.spacingXs) } - .background(Color(colors.backgroundElevationElevation1)) + .background(Color(colors.backgroundCoreElevation1)) .accessibilityElement(children: .contain) .accessibilityIdentifier("AttachmentCommandsPickerView") } @@ -59,7 +59,7 @@ public struct AttachmentCommandsPickerView: View { private var headerView: some View { Text(L10n.Composer.Suggestions.Commands.header) .font(fonts.bodyBold) - .foregroundColor(Color(colors.text)) + .foregroundColor(Color(colors.textPrimary)) .padding(.horizontal, tokens.spacingSm) .accessibilityIdentifier("AttachmentCommandsHeader") } @@ -78,17 +78,17 @@ private struct AttachmentCommandRow: View { .resizable() .scaledToFit() .frame(width: tokens.iconSizeMd, height: tokens.iconSizeMd) - .foregroundColor(Color(colors.textLowEmphasis)) + .foregroundColor(Color(colors.textTertiary)) Text(displayInfo.displayName) .font(fonts.bodyBold) - .foregroundColor(Color(colors.text)) + .foregroundColor(Color(colors.textPrimary)) .frame(width: 80, alignment: .leading) .lineLimit(1) Text(displayInfo.format) .font(fonts.body) - .foregroundColor(Color(colors.textLowEmphasis)) + .foregroundColor(Color(colors.textTertiary)) .lineLimit(1) Spacer() diff --git a/Sources/StreamChatSwiftUI/ChatComposer/AttachmentPicker/AttachmentMediaPicker/AttachmentMediaPickerItemView.swift b/Sources/StreamChatSwiftUI/ChatComposer/AttachmentPicker/AttachmentMediaPicker/AttachmentMediaPickerItemView.swift index 243cc5bdd..9a977b90d 100644 --- a/Sources/StreamChatSwiftUI/ChatComposer/AttachmentPicker/AttachmentMediaPicker/AttachmentMediaPickerItemView.swift +++ b/Sources/StreamChatSwiftUI/ChatComposer/AttachmentPicker/AttachmentMediaPicker/AttachmentMediaPickerItemView.swift @@ -3,7 +3,6 @@ // import Photos -import StreamChatCommonUI import SwiftUI /// Media item displayed in the attachment picker view. @@ -96,7 +95,7 @@ public struct AttachmentMediaPickerItemView: View { ) } } else { - Color(colors.backgroundCoreSurface) + Color(colors.backgroundCoreSurfaceDefault) .aspectRatio(1, contentMode: .fill) Image(uiImage: images.imagePlaceholder) @@ -112,7 +111,7 @@ public struct AttachmentMediaPickerItemView: View { // Selected dimming overlay if selected { RoundedRectangle(cornerRadius: tokens.radiusXxs) - .fill(Color(colors.backgroundCoreSelected)) + .fill(Color(colors.backgroundUtilitySelected)) } // Selection indicator (top-right) diff --git a/Sources/StreamChatSwiftUI/ChatComposer/AttachmentPicker/AttachmentMediaPicker/AttachmentMediaPickerView.swift b/Sources/StreamChatSwiftUI/ChatComposer/AttachmentPicker/AttachmentMediaPicker/AttachmentMediaPickerView.swift index bfffb04ef..27af90683 100644 --- a/Sources/StreamChatSwiftUI/ChatComposer/AttachmentPicker/AttachmentMediaPicker/AttachmentMediaPickerView.swift +++ b/Sources/StreamChatSwiftUI/ChatComposer/AttachmentPicker/AttachmentMediaPicker/AttachmentMediaPickerView.swift @@ -4,7 +4,6 @@ import Photos import StreamChat -import StreamChatCommonUI import SwiftUI /// View for the media attachment picker. @@ -56,7 +55,7 @@ public struct AttachmentMediaPickerView: View { LoadingView() } } - .background(Color(colors.backgroundElevationElevation1)) + .background(Color(colors.backgroundCoreElevation1)) } // MARK: - Private diff --git a/Sources/StreamChatSwiftUI/ChatComposer/AttachmentPicker/AttachmentMediaPicker/PhotoAssetLoader.swift b/Sources/StreamChatSwiftUI/ChatComposer/AttachmentPicker/AttachmentMediaPicker/PhotoAssetLoader.swift index 6c6128079..bf21b033c 100644 --- a/Sources/StreamChatSwiftUI/ChatComposer/AttachmentPicker/AttachmentMediaPicker/PhotoAssetLoader.swift +++ b/Sources/StreamChatSwiftUI/ChatComposer/AttachmentPicker/AttachmentMediaPicker/PhotoAssetLoader.swift @@ -10,6 +10,7 @@ import SwiftUI /// Helper class that loads assets from the photo library. @MainActor public class PhotoAssetLoader: NSObject, ObservableObject { @Injected(\.chatClient) private var chatClient + @Injected(\.utils) private var utils @Published var loadedImages = [String: UIImage]() @@ -57,7 +58,7 @@ import SwiftUI _ = url?.startAccessingSecurityScopedResource() if let assetURL = url, let file = try? AttachmentFile(url: assetURL), - file.size >= chatClient.maxAttachmentSize(for: assetURL) { + file.size >= chatClient.maxAttachmentSize(for: assetURL, fallbackSize: utils.composerConfig.maxAttachmentSize) { return true } else { return false diff --git a/Sources/StreamChatSwiftUI/ChatComposer/AttachmentPicker/AttachmentPickerPromptView.swift b/Sources/StreamChatSwiftUI/ChatComposer/AttachmentPicker/AttachmentPickerPromptView.swift index 1eb214df3..809549983 100644 --- a/Sources/StreamChatSwiftUI/ChatComposer/AttachmentPicker/AttachmentPickerPromptView.swift +++ b/Sources/StreamChatSwiftUI/ChatComposer/AttachmentPicker/AttachmentPickerPromptView.swift @@ -2,7 +2,6 @@ // Copyright © 2026 Stream.io Inc. All rights reserved. // -import StreamChatCommonUI import SwiftUI /// A reusable view to prompt the user of any action in the attachment picker. @@ -29,8 +28,8 @@ public struct AttachmentPickerPromptView: View { } public var body: some View { - VStack(spacing: tokens.spacingXs) { - VStack(spacing: tokens.spacingXs) { + VStack(spacing: tokens.spacingMd) { + VStack(spacing: tokens.spacingSm) { image .customizable() .frame(width: 32, height: 32) @@ -42,24 +41,21 @@ public struct AttachmentPickerPromptView: View { .foregroundColor(Color(colors.textTertiary)) .frame(width: 200) } - .frame(maxWidth: .infinity, maxHeight: .infinity) StreamTextButton( role: .secondary, style: .outline, - size: .large, + size: .medium, action: onTap ) { Text(buttonText) .font(fonts.bodyBold) - .frame(maxWidth: .infinity) } - .frame(maxWidth: .infinity, minHeight: 48, maxHeight: 48, alignment: .center) } .frame(maxWidth: .infinity, maxHeight: .infinity) .padding(.horizontal, tokens.spacing2xl) - .padding(.bottom, tokens.spacing3xl) - .background(Color(colors.backgroundElevationElevation1)) + .padding(.bottom, 60) + .background(Color(colors.backgroundCoreElevation1)) .accessibilityElement(children: .contain) .accessibilityIdentifier("AttachmentPickerPromptView") } diff --git a/Sources/StreamChatSwiftUI/ChatComposer/AttachmentPicker/AttachmentPickerView.swift b/Sources/StreamChatSwiftUI/ChatComposer/AttachmentPicker/AttachmentPickerView.swift index 2010a5132..96b27e27e 100644 --- a/Sources/StreamChatSwiftUI/ChatComposer/AttachmentPicker/AttachmentPickerView.swift +++ b/Sources/StreamChatSwiftUI/ChatComposer/AttachmentPicker/AttachmentPickerView.swift @@ -4,7 +4,6 @@ import Photos import StreamChat -import StreamChatCommonUI import SwiftUI /// Enum for the picker type state. @@ -159,7 +158,7 @@ public struct AttachmentPickerView: View { } .edgesIgnoringSafeArea(.bottom) .frame(height: height) - .background(Color(colors.backgroundElevationElevation1)) + .background(Color(colors.backgroundCoreElevation1)) .onChange(of: isDisplayed) { newValue in if newValue { askForAssetsAccessPermissions() diff --git a/Sources/StreamChatSwiftUI/ChatComposer/AttachmentPicker/AttachmentTypePickerView.swift b/Sources/StreamChatSwiftUI/ChatComposer/AttachmentPicker/AttachmentTypePickerView.swift index 03719a88d..a3f0161d6 100644 --- a/Sources/StreamChatSwiftUI/ChatComposer/AttachmentPicker/AttachmentTypePickerView.swift +++ b/Sources/StreamChatSwiftUI/ChatComposer/AttachmentPicker/AttachmentTypePickerView.swift @@ -2,7 +2,6 @@ // Copyright © 2026 Stream.io Inc. All rights reserved. // -import StreamChatCommonUI import SwiftUI /// View for picking the type of attachment (photo, files, camera, polls, commands). @@ -54,7 +53,7 @@ public struct AttachmentTypePickerView: View { if canSendPoll { AttachmentTypePickerButton( - icon: images.attachmentPickerPolls, + icon: images.attachmentPollIcon, pickerType: .polls, isSelected: selected == .polls, onTap: onTap @@ -76,7 +75,7 @@ public struct AttachmentTypePickerView: View { } .padding(.horizontal, tokens.spacingMd) .padding(.vertical, tokens.spacingSm) - .background(Color(colors.backgroundElevationElevation1)) + .background(Color(colors.backgroundCoreElevation1)) .accessibilityElement(children: .contain) .accessibilityIdentifier("AttachmentTypePickerView") } diff --git a/Sources/StreamChatSwiftUI/ChatComposer/Attachments/ComposerFileAttachmentView.swift b/Sources/StreamChatSwiftUI/ChatComposer/Attachments/ComposerFileAttachmentView.swift index 53bcff746..fb1d7a96f 100644 --- a/Sources/StreamChatSwiftUI/ChatComposer/Attachments/ComposerFileAttachmentView.swift +++ b/Sources/StreamChatSwiftUI/ChatComposer/Attachments/ComposerFileAttachmentView.swift @@ -22,11 +22,11 @@ struct ComposerFileAttachmentView: View { Text(url.lastPathComponent) .font(fonts.footnoteBold) .lineLimit(1) - .foregroundColor(Color(colors.text)) + .foregroundColor(Color(colors.textPrimary)) Text(url.sizeString) .font(fonts.caption1) .lineLimit(1) - .foregroundColor(Color(colors.textLowEmphasis)) + .foregroundColor(Color(colors.textTertiary)) } Spacer() } @@ -34,11 +34,11 @@ struct ComposerFileAttachmentView: View { .padding(.leading, tokens.spacingMd) .padding(.bottom, tokens.spacingMd) .padding(.trailing, tokens.spacingSm) - .background(Color(colors.backgroundElevationElevation1)) + .background(Color(colors.backgroundCoreElevation1)) .cornerRadius(tokens.radiusLg) .overlay( RoundedRectangle(cornerRadius: tokens.radiusLg) - .strokeBorder(Color(colors.borderCoreOpacity10), lineWidth: 1) + .strokeBorder(Color(colors.borderCoreOpacitySubtle), lineWidth: 1) ) .id(url) .dismissButtonOverlayModifier { diff --git a/Sources/StreamChatSwiftUI/ChatComposer/Attachments/ComposerImageAttachmentView.swift b/Sources/StreamChatSwiftUI/ChatComposer/Attachments/ComposerImageAttachmentView.swift index 4bd947b93..5a4d0e086 100644 --- a/Sources/StreamChatSwiftUI/ChatComposer/Attachments/ComposerImageAttachmentView.swift +++ b/Sources/StreamChatSwiftUI/ChatComposer/Attachments/ComposerImageAttachmentView.swift @@ -21,7 +21,7 @@ struct ComposerImageAttachmentView: View { .cornerRadius(tokens.messageBubbleRadiusAttachment) .overlay( RoundedRectangle(cornerRadius: tokens.messageBubbleRadiusAttachment) - .strokeBorder(Color(colors.borderCoreOpacity10), lineWidth: 1) + .strokeBorder(Color(colors.borderCoreOpacitySubtle), lineWidth: 1) ) .id(attachment.id) .dismissButtonOverlayModifier { diff --git a/Sources/StreamChatSwiftUI/ChatComposer/Attachments/ComposerVoiceRecordingAttachmentView.swift b/Sources/StreamChatSwiftUI/ChatComposer/Attachments/ComposerVoiceRecordingAttachmentView.swift index af12cff34..ebb5cd39e 100644 --- a/Sources/StreamChatSwiftUI/ChatComposer/Attachments/ComposerVoiceRecordingAttachmentView.swift +++ b/Sources/StreamChatSwiftUI/ChatComposer/Attachments/ComposerVoiceRecordingAttachmentView.swift @@ -53,7 +53,10 @@ struct ComposerVoiceRecordingAttachmentView: View { var onDiscardAttachment: (String) -> Void private var isActive: Bool { handler.isActive(for: recording.url) } - private var showContextDuration: Bool { isActive && handler.context.currentTime > 0 } + + private var displayedPlaybackTime: TimeInterval { + handler.displayedTime(for: recording.url, duration: recording.duration) + } var body: some View { HStack(spacing: tokens.spacingXs) { @@ -66,11 +69,11 @@ struct ComposerVoiceRecordingAttachmentView: View { .padding(.bottom, tokens.spacingMd) .padding(.trailing, tokens.spacingSm) .frame(height: 72) - .background(Color(colors.backgroundElevationElevation1)) + .background(Color(colors.backgroundCoreElevation1)) .cornerRadius(tokens.radiusLg) .overlay( RoundedRectangle(cornerRadius: tokens.radiusLg) - .strokeBorder(Color(colors.borderCoreOpacity10), lineWidth: 1) + .strokeBorder(Color(colors.borderCoreOpacitySubtle), lineWidth: 1) ) .dismissButtonOverlayModifier { onDiscardAttachment(recording.url.absoluteString) @@ -92,7 +95,7 @@ struct ComposerVoiceRecordingAttachmentView: View { private var contentArea: some View { HStack(spacing: tokens.spacingXs) { - Text(utils.videoDurationFormatter.format(showContextDuration ? handler.context.currentTime : recording.duration) ?? "") + Text(utils.videoDurationFormatter.format(displayedPlaybackTime) ?? "") .font(fonts.footnote.monospacedDigit()) .foregroundColor(Color(colors.textSecondary)) diff --git a/Sources/StreamChatSwiftUI/ChatComposer/Attachments/MediaBadge.swift b/Sources/StreamChatSwiftUI/ChatComposer/Attachments/MediaBadge.swift index 137bae072..0f2a316d7 100644 --- a/Sources/StreamChatSwiftUI/ChatComposer/Attachments/MediaBadge.swift +++ b/Sources/StreamChatSwiftUI/ChatComposer/Attachments/MediaBadge.swift @@ -3,7 +3,6 @@ // import StreamChat -import StreamChatCommonUI import SwiftUI /// A media badge for video. @@ -66,7 +65,7 @@ public struct MediaBadge: View { Text(durationText) .font(.system(size: 12, weight: .bold)) } - .foregroundColor(Color(colors.badgeTextInverse)) + .foregroundColor(Color(colors.badgeTextOnInverse)) .padding(.horizontal, tokens.spacingXs) .padding(.vertical, tokens.spacingXxs) .frame(minWidth: 45, minHeight: 20) diff --git a/Sources/StreamChatSwiftUI/ChatComposer/Attachments/VoiceRecording/ComposerVoiceRecordingInputView.swift b/Sources/StreamChatSwiftUI/ChatComposer/Attachments/VoiceRecording/ComposerVoiceRecordingInputView.swift index 83f00b382..47793c203 100644 --- a/Sources/StreamChatSwiftUI/ChatComposer/Attachments/VoiceRecording/ComposerVoiceRecordingInputView.swift +++ b/Sources/StreamChatSwiftUI/ChatComposer/Attachments/VoiceRecording/ComposerVoiceRecordingInputView.swift @@ -106,9 +106,7 @@ struct ComposerVoiceRecordingInputView: View { : L10n.Composer.AudioRecording.start)) VoiceRecordingDurationView( - duration: handler.context.currentTime > 0 - ? handler.context.currentTime - : audioRecordingInfo.duration, + duration: previewRecordingDurationLabel, usesAccentColor: handler.isPlaying ) } @@ -137,7 +135,7 @@ struct ComposerVoiceRecordingInputView: View { .font(.system(size: 20)) .foregroundColor(Color(colors.textPrimary)) .frame(width: 32, height: 32) - .background(Color(colors.backgroundCorePressed)) + .background(Color(colors.backgroundUtilityPressed)) .clipShape(Circle()) } .frame(width: 48, height: 48) @@ -149,10 +147,8 @@ struct ComposerVoiceRecordingInputView: View { RecordingWaveform( isRecording: !isStopped, isPlaying: handler.isPlaying, - duration: audioRecordingInfo.duration, - currentTime: isStopped - ? handler.context.currentTime - : audioRecordingInfo.duration, + duration: lockedPreviewWaveformDuration, + currentTime: lockedPreviewWaveformCurrentTime, waveform: audioRecordingInfo.waveform, onSliderChanged: { timeInterval in guard let url = pendingAudioRecordingURL else { return } @@ -163,6 +159,25 @@ struct ComposerVoiceRecordingInputView: View { .padding(.horizontal, tokens.spacingMd) } + private var lockedPreviewWaveformCurrentTime: TimeInterval { + if !isStopped { + return audioRecordingInfo.duration + } + guard let url = pendingAudioRecordingURL, handler.isActive(for: url) else { + return 0 + } + return min(max(handler.context.currentTime, 0), lockedPreviewWaveformDuration) + } + + private var lockedPreviewWaveformDuration: TimeInterval { + let fromMetering = max(audioRecordingInfo.duration, 0.001) + guard isStopped, let url = pendingAudioRecordingURL, handler.isActive(for: url) else { + return fromMetering + } + let fromPlayer = handler.context.duration + return max(fromMetering, fromPlayer, 0.001) + } + // MARK: - Recording Controls private let recordingControlsHeight: CGFloat = 48 @@ -229,6 +244,13 @@ struct ComposerVoiceRecordingInputView: View { guard gestureLocation.x < VoiceRecordingConstants.cancelMinDistance else { return 1 } return 1 - gestureLocation.x / VoiceRecordingConstants.cancelMaxDistance } + + private var previewRecordingDurationLabel: TimeInterval { + guard isStopped, let url = pendingAudioRecordingURL else { + return audioRecordingInfo.duration + } + return handler.displayedTime(for: url, duration: audioRecordingInfo.duration) + } } // MARK: - Slide to Cancel Label diff --git a/Sources/StreamChatSwiftUI/ChatComposer/Attachments/VoiceRecording/VoiceRecordingGestureOverlay.swift b/Sources/StreamChatSwiftUI/ChatComposer/Attachments/VoiceRecording/VoiceRecordingGestureOverlay.swift index f689e0865..41b287ca8 100644 --- a/Sources/StreamChatSwiftUI/ChatComposer/Attachments/VoiceRecording/VoiceRecordingGestureOverlay.swift +++ b/Sources/StreamChatSwiftUI/ChatComposer/Attachments/VoiceRecording/VoiceRecordingGestureOverlay.swift @@ -9,10 +9,17 @@ import SwiftUI struct VoiceRecordingGestureOverlay: View { @Binding var recordingState: VoiceRecordingState @Binding var gestureLocation: CGPoint - var startRecording: () -> Void - var stopRecording: () -> Void - var discardRecording: () -> Void - var showRecordingTip: () -> Void + + /// The long press was held long enough to begin recording. + var onRecordingStarted: () -> Void + /// The gesture ended outside the active recording flow. + var onGestureCompleted: () -> Void + /// The finger was lifted during an active recording (hold-and-release). + var onRecordingReleased: () -> Void + /// The drag exceeded the cancel threshold while recording. + var onRecordingCancelled: () -> Void + /// The tap was too brief to trigger recording. + var onShortTapDetected: () -> Void @State private var longPressed = false @State private var longPressStarted: Date? @@ -37,7 +44,7 @@ struct VoiceRecordingGestureOverlay: View { if longPressed { recordingState = .recording gestureLocation = translation - startRecording() + onRecordingStarted() } } } else if recordingState.isRecording { @@ -47,21 +54,23 @@ struct VoiceRecordingGestureOverlay: View { .onEnded { _ in longPressed = false if let longPressStarted, Date().timeIntervalSince(longPressStarted) <= 1 { - showRecordingTip() + onShortTapDetected() self.longPressStarted = nil return } if recordingState.isRecording { if gestureLocation.x < VoiceRecordingConstants.cancelMinDistance { - discardRecording() + withAnimation(.composerVoiceRecordingSpring) { + onRecordingCancelled() + } } else { withAnimation(.composerVoiceRecordingSpring) { - recordingState = .locked + onRecordingReleased() } } gestureLocation = .zero } else if recordingState != .locked { - stopRecording() + onGestureCompleted() } } ) diff --git a/Sources/StreamChatSwiftUI/ChatComposer/Attachments/VoiceRecording/VoiceRecordingLockView.swift b/Sources/StreamChatSwiftUI/ChatComposer/Attachments/VoiceRecording/VoiceRecordingLockView.swift index dec9bb1b0..a722a0b42 100644 --- a/Sources/StreamChatSwiftUI/ChatComposer/Attachments/VoiceRecording/VoiceRecordingLockView.swift +++ b/Sources/StreamChatSwiftUI/ChatComposer/Attachments/VoiceRecording/VoiceRecordingLockView.swift @@ -44,7 +44,7 @@ struct VoiceRecordingLockView: View { .foregroundColor(Color(colors.textSecondary)) .padding(10) .frame(width: 40) - .background(Color(colors.backgroundElevationElevation1)) + .background(Color(colors.backgroundCoreElevation1)) .clipShape(Capsule()) .overlay( Capsule() diff --git a/Sources/StreamChatSwiftUI/ChatComposer/Buttons/ComposerAttachmentPickerButton.swift b/Sources/StreamChatSwiftUI/ChatComposer/Buttons/ComposerAttachmentPickerButton.swift index 5895eb5ee..069c340f0 100644 --- a/Sources/StreamChatSwiftUI/ChatComposer/Buttons/ComposerAttachmentPickerButton.swift +++ b/Sources/StreamChatSwiftUI/ChatComposer/Buttons/ComposerAttachmentPickerButton.swift @@ -2,7 +2,6 @@ // Copyright © 2026 Stream.io Inc. All rights reserved. // -import StreamChatCommonUI import SwiftUI /// The button for opening and closing the attachment picker in the message composer. diff --git a/Sources/StreamChatSwiftUI/ChatComposer/Buttons/SendMessageButton.swift b/Sources/StreamChatSwiftUI/ChatComposer/Buttons/SendMessageButton.swift index 0f0e625b8..731e3c589 100644 --- a/Sources/StreamChatSwiftUI/ChatComposer/Buttons/SendMessageButton.swift +++ b/Sources/StreamChatSwiftUI/ChatComposer/Buttons/SendMessageButton.swift @@ -6,6 +6,8 @@ import SwiftUI /// The button for sending messages. public struct SendMessageButton: View { + @Environment(\.layoutDirection) private var layoutDirection + @Injected(\.images) private var images @Injected(\.tokens) private var tokens @@ -27,6 +29,7 @@ public struct SendMessageButton: View { Image(uiImage: images.composerSend) .renderingMode(.template) .frame(width: tokens.iconSizeMd, height: tokens.iconSizeMd) + .scaleEffect(x: layoutDirection == .rightToLeft ? -1 : 1, y: 1) } .disabled(!enabled) .accessibilityLabel(Text(L10n.Composer.Placeholder.message)) diff --git a/Sources/StreamChatSwiftUI/ChatComposer/CommandChipView.swift b/Sources/StreamChatSwiftUI/ChatComposer/CommandChipView.swift index 7dfa1f121..d96cedeeb 100644 --- a/Sources/StreamChatSwiftUI/ChatComposer/CommandChipView.swift +++ b/Sources/StreamChatSwiftUI/ChatComposer/CommandChipView.swift @@ -2,7 +2,6 @@ // Copyright © 2026 Stream.io Inc. All rights reserved. // -import StreamChatCommonUI import SwiftUI /// Chip view displayed in the composer when a slash command is active. @@ -42,7 +41,7 @@ public struct CommandChipView: View { .padding(.horizontal, tokens.spacingXs) .padding(.vertical, tokens.spacingXxxs) .frame(height: 24) - .foregroundColor(Color(colors.textOnDark)) + .foregroundColor(Color(colors.textOnInverse)) .background(Color(colors.backgroundCoreInverse)) .clipShape(Capsule()) .accessibilityElement(children: .combine) diff --git a/Sources/StreamChatSwiftUI/ChatComposer/ComposerConfig.swift b/Sources/StreamChatSwiftUI/ChatComposer/ComposerConfig.swift index 1c27ea158..2729eb9a3 100644 --- a/Sources/StreamChatSwiftUI/ChatComposer/ComposerConfig.swift +++ b/Sources/StreamChatSwiftUI/ChatComposer/ComposerConfig.swift @@ -8,6 +8,12 @@ import SwiftUI /// Config for customizing the composer. public final class ComposerConfig { public var isVoiceRecordingEnabled: Bool + + /// When enabled, releasing a hold-to-record gesture sends the voice message + /// immediately. When disabled (default), the recording is added to the + /// composer's attachment preview so the user can review before sending. + public var isVoiceRecordingAutoSendEnabled: Bool + public var inputViewMinHeight: CGFloat public var inputViewMaxHeight: CGFloat public var inputViewCornerRadius: CGFloat @@ -17,8 +23,13 @@ public final class ComposerConfig { public var adjustMessageOnSend: (String) -> (String) public var adjustMessageOnRead: (String) -> (String) + /// The fallback maximum attachment size in bytes when the server does not provide one. + /// The default value is 100 MB. + public var maxAttachmentSize: Int64 + public init( - isVoiceRecordingEnabled: Bool = false, + isVoiceRecordingEnabled: Bool = true, + isVoiceRecordingAutoSendEnabled: Bool = false, inputViewMinHeight: CGFloat = 40, inputViewMaxHeight: CGFloat = 120, inputViewCornerRadius: CGFloat = 20, @@ -26,7 +37,8 @@ public final class ComposerConfig { gallerySupportedTypes: GallerySupportedTypes = .imagesAndVideo, maxGalleryAssetsCount: Int? = nil, adjustMessageOnSend: @escaping (String) -> (String) = { $0 }, - adjustMessageOnRead: @escaping (String) -> (String) = { $0 } + adjustMessageOnRead: @escaping (String) -> (String) = { $0 }, + maxAttachmentSize: Int64 = 100 * 1024 * 1024 ) { self.inputViewMinHeight = inputViewMinHeight self.inputViewMaxHeight = inputViewMaxHeight @@ -37,6 +49,8 @@ public final class ComposerConfig { self.gallerySupportedTypes = gallerySupportedTypes self.maxGalleryAssetsCount = maxGalleryAssetsCount self.isVoiceRecordingEnabled = isVoiceRecordingEnabled + self.isVoiceRecordingAutoSendEnabled = isVoiceRecordingAutoSendEnabled + self.maxAttachmentSize = maxAttachmentSize } } diff --git a/Sources/StreamChatSwiftUI/ChatComposer/ComposerModels.swift b/Sources/StreamChatSwiftUI/ChatComposer/ComposerModels.swift index f55bb13e0..77ae1469b 100644 --- a/Sources/StreamChatSwiftUI/ChatComposer/ComposerModels.swift +++ b/Sources/StreamChatSwiftUI/ChatComposer/ComposerModels.swift @@ -152,8 +152,8 @@ public final class AddedVoiceRecording: Identifiable, Equatable, Sendable { extension AnyChatMessageAttachment { func toAddedVoiceRecording() -> AddedVoiceRecording? { guard let voiceAttachment = attachment(payloadType: VoiceRecordingAttachmentPayload.self) else { return nil } - guard let duration = voiceAttachment.duration else { return nil } - guard let waveform = voiceAttachment.waveformData else { return nil } + let duration = voiceAttachment.duration ?? 0 + let waveform = voiceAttachment.waveformData ?? [] return AddedVoiceRecording( url: voiceAttachment.voiceRecordingURL, duration: duration, diff --git a/Sources/StreamChatSwiftUI/ChatComposer/MessageComposerInputState.swift b/Sources/StreamChatSwiftUI/ChatComposer/MessageComposerInputState.swift index c0823dd3e..d8733fd3d 100644 --- a/Sources/StreamChatSwiftUI/ChatComposer/MessageComposerInputState.swift +++ b/Sources/StreamChatSwiftUI/ChatComposer/MessageComposerInputState.swift @@ -7,7 +7,7 @@ import Foundation /// The current composer's input view state. public enum MessageComposerInputState { case slowMode(cooldownDuration: Int) - case creating(hasContent: Bool) + case creating(hasContent: Bool, hasCommand: Bool) case editing(hasContent: Bool) case allowAudioRecording } diff --git a/Sources/StreamChatSwiftUI/ChatComposer/MessageComposerView.swift b/Sources/StreamChatSwiftUI/ChatComposer/MessageComposerView.swift index eecafdd81..94ce4be95 100644 --- a/Sources/StreamChatSwiftUI/ChatComposer/MessageComposerView.swift +++ b/Sources/StreamChatSwiftUI/ChatComposer/MessageComposerView.swift @@ -33,7 +33,7 @@ public struct MessageComposerView: View, KeyboardReadable messageController: ChatMessageController? = nil, quotedMessage: Binding, editedMessage: Binding, - onMessageSent: @escaping () -> Void + willSendMessage: @escaping () -> Void ) { factory = viewFactory channelConfig = channelController.channel?.config @@ -41,18 +41,17 @@ public struct MessageComposerView: View, KeyboardReadable wrappedValue: viewModel ?? ViewModelsFactory.makeMessageComposerViewModel( with: channelController, messageController: messageController, - quotedMessage: quotedMessage + quotedMessage: quotedMessage, + editedMessage: editedMessage, + willSendMessage: willSendMessage ) ) _quotedMessage = quotedMessage _editedMessage = editedMessage - self.onMessageSent = onMessageSent } @StateObject var viewModel: MessageComposerViewModel - var onMessageSent: () -> Void - private var showsLeadingComposer: Bool { viewModel.recordingState.showsComposer && viewModel.composerCommand?.displayInfo?.isInstant != true @@ -102,7 +101,7 @@ public struct MessageComposerView: View, KeyboardReadable pendingAudioRecordingURL: viewModel.pendingAudioRecording?.url, onCustomAttachmentTap: viewModel.customAttachmentTapped(_:), removeAttachmentWithId: viewModel.removeAttachment(with:), - sendMessage: sendMessage, + sendMessage: { viewModel.sendMessage() }, onImagePasted: viewModel.imagePasted, startRecording: viewModel.startRecording, stopRecording: viewModel.stopRecording, @@ -126,7 +125,7 @@ public struct MessageComposerView: View, KeyboardReadable options: TrailingComposerViewOptions( enabled: viewModel.hasContent, cooldownDuration: viewModel.cooldownDuration, - onTap: sendMessage + onTap: { viewModel.sendMessage() } ) ) .alert(isPresented: $viewModel.errorShown) { @@ -168,10 +167,13 @@ public struct MessageComposerView: View, KeyboardReadable VoiceRecordingGestureOverlay( recordingState: $viewModel.recordingState, gestureLocation: $viewModel.recordingGestureLocation, - startRecording: viewModel.startRecording, - stopRecording: viewModel.stopRecording, - discardRecording: viewModel.discardRecording, - showRecordingTip: viewModel.showRecordingTip + onRecordingStarted: viewModel.startRecording, + onGestureCompleted: viewModel.stopRecording, + onRecordingReleased: utils.composerConfig.isVoiceRecordingAutoSendEnabled + ? viewModel.sendRecording + : viewModel.saveRecording, + onRecordingCancelled: viewModel.discardRecording, + onShortTapDetected: viewModel.showRecordingTip ) } } @@ -329,19 +331,6 @@ public struct MessageComposerView: View, KeyboardReadable .accessibilityElement(children: .contain) } - public func sendMessage() { - // Calling onMessageSent() before erasing the edited and quoted message - // so that onMessageSent can use them for state handling. - onMessageSent() - viewModel.sendMessage( - quotedMessage: quotedMessage, - editedMessage: editedMessage - ) { - quotedMessage = nil - editedMessage = nil - } - } - private static var initialLockOffset: CGFloat { -70 } private func lockViewOffset(for location: CGPoint) -> CGFloat { @@ -599,6 +588,7 @@ public struct ComposerInputView: View, KeyboardReadable { options: .init( text: $text, recordingState: $recordingState, + composerCommand: $command, composerInputState: composerInputState, startRecording: startRecording, stopRecording: stopRecording, @@ -681,14 +671,14 @@ public struct ComposerInputView: View, KeyboardReadable { } if command?.displayInfo?.isInstant == true { - return .creating(hasContent: hasContent) + return .creating(hasContent: hasContent, hasCommand: true) } if utils.composerConfig.isVoiceRecordingEnabled && !hasContent { return .allowAudioRecording } - return .creating(hasContent: hasContent) + return .creating(hasContent: hasContent, hasCommand: false) } private var isInCooldown: Bool { diff --git a/Sources/StreamChatSwiftUI/ChatComposer/MessageComposerViewModel+Recording.swift b/Sources/StreamChatSwiftUI/ChatComposer/MessageComposerViewModel+Recording.swift index 979737a1e..73e94ef1d 100644 --- a/Sources/StreamChatSwiftUI/ChatComposer/MessageComposerViewModel+Recording.swift +++ b/Sources/StreamChatSwiftUI/ChatComposer/MessageComposerViewModel+Recording.swift @@ -36,7 +36,10 @@ extension MessageComposerViewModel: AudioRecordingDelegate { _ audioRecorder: AudioRecording, didFinishRecordingAtURL location: URL ) { - if audioRecordingInfo == .initial { return } + if audioRecordingInfo == .initial { + shouldSendOnRecordingFinish = false + return + } audioAnalysisFactory?.waveformVisualisation( fromAudioURL: location, for: waveformTargetSamples, @@ -58,9 +61,14 @@ extension MessageComposerViewModel: AudioRecordingDelegate { self.addedVoiceRecordings.append(recording) self.recordingState = .initial self.audioRecordingInfo = .initial + if self.shouldSendOnRecordingFinish { + self.shouldSendOnRecordingFinish = false + self.sendMessage() + } } case let .failure(error): log.error(error) + self.shouldSendOnRecordingFinish = false self.recordingState = .initial } } @@ -73,6 +81,7 @@ extension MessageComposerViewModel: AudioRecordingDelegate { didFailWithError error: Error ) { log.error(error) + shouldSendOnRecordingFinish = false let wasRecording = recordingState != .initial recordingState = .initial audioRecordingInfo = .initial @@ -83,27 +92,36 @@ extension MessageComposerViewModel: AudioRecordingDelegate { } extension MessageComposerViewModel { + /// Displays a tip snackbar explaining how to use voice recording. + /// The text adapts based on `isVoiceRecordingAutoSendEnabled`. public func showRecordingTip() { - snackBarText = L10n.Composer.Recording.tip + snackBarText = utils.composerConfig.isVoiceRecordingAutoSendEnabled + ? L10n.Composer.Recording.tip + : L10n.Composer.Recording.tipSave } + /// Begins capturing audio from the microphone. public func startRecording() { utils.audioSessionFeedbackGenerator.feedbackForBeginRecording() audioRecorder.beginRecording { log.debug("started recording") } } - + + /// Stops the audio recorder. The recording enters the locked or stopped + /// state depending on the current gesture flow. public func stopRecording() { utils.audioSessionFeedbackGenerator.feedbackForStopRecording() audioRecorder.stopRecording() } - + + /// Resumes a previously paused recording session. public func resumeRecording() { utils.audioSessionFeedbackGenerator.feedbackForBeginRecording() audioRecorder.resumeRecording() } - + + /// Pauses the current recording without discarding it. public func pauseRecording() { utils.audioSessionFeedbackGenerator.feedbackForPause() audioRecorder.pauseRecording() @@ -111,14 +129,44 @@ extension MessageComposerViewModel { } extension MessageComposerViewModel { + /// Stops recording and sends the voice message as soon as the file is ready. + /// + /// Called when the user lifts their finger during a hold-to-record gesture + /// (as opposed to locking). Sets `shouldSendOnRecordingFinish` so that the + /// `audioRecorder(_:didFinishRecordingAtURL:)` callback triggers `sendMessage()` + /// automatically once the audio file has been processed. + public func sendRecording() { + guard recordingState == .recording else { return } + shouldSendOnRecordingFinish = true + stopRecording() + } + + /// Stops recording and adds the voice message to the composer's attachment + /// preview without sending it. + /// + /// Called when the user lifts their finger during a hold-to-record gesture + /// and `isVoiceRecordingAutoSendEnabled` is `false`. The recording is + /// appended to `addedVoiceRecordings` so the user can review or discard + /// it before explicitly sending. + public func saveRecording() { + guard recordingState == .recording else { return } + shouldSendOnRecordingFinish = false + stopRecording() + } + + /// Cancels the current recording and resets all recording state. + /// Shows a snackbar confirming the voice message was deleted. public func discardRecording() { + shouldSendOnRecordingFinish = false stopRecording() recordingState = .initial audioRecordingInfo = .initial recordingGestureLocation = .zero snackBarText = L10n.Composer.Recording.voiceMessageDeleted } - + + /// Confirms a stopped recording and adds it to the composer's voice attachments. + /// If the recording is still in progress (locked state), stops it first. public func confirmRecording() { if recordingState == .stopped { if let pending = pendingAudioRecording { @@ -131,7 +179,9 @@ extension MessageComposerViewModel { stopRecording() } } - + + /// Transitions to the stopped/preview state so the user can listen + /// to the recording before confirming or discarding it. public func previewRecording() { recordingState = .stopped stopRecording() diff --git a/Sources/StreamChatSwiftUI/ChatComposer/MessageComposerViewModel.swift b/Sources/StreamChatSwiftUI/ChatComposer/MessageComposerViewModel.swift index a3bee1f73..b8af1f7a0 100644 --- a/Sources/StreamChatSwiftUI/ChatComposer/MessageComposerViewModel.swift +++ b/Sources/StreamChatSwiftUI/ChatComposer/MessageComposerViewModel.swift @@ -110,6 +110,9 @@ import SwiftUI if oldValue?.id != composerCommand?.id && composerCommand?.displayInfo?.isInstant == true { clearCommandText() + composerAssets = [] + addedVoiceRecordings = [] + addedCustomAttachments = [] } if oldValue != nil && composerCommand == nil { pickerTypeState = .expanded(.none) @@ -159,11 +162,19 @@ import SwiftUI @Published public var audioRecordingInfo = AudioRecordingInfo.initial @Published public var snackBarText: String? + @Published public private(set) var isSendingMessage = false public let channelController: ChatChannelController public var messageController: ChatMessageController? public let eventsController: EventsController public var quotedMessage: Binding? + public var editedMessage: Binding? + public var willSendMessage: (() -> Void)? + + /// When `true`, the next completed recording is automatically sent via `sendMessage()`. + /// Set by `sendRecording()` and cleared once the send fires or an error occurs. + var shouldSendOnRecordingFinish = false + public var waveformTargetSamples: Int = 100 public internal(set) var pendingAudioRecording: AddedVoiceRecording? @@ -230,12 +241,16 @@ import SwiftUI channelController: ChatChannelController, messageController: ChatMessageController?, eventsController: EventsController? = nil, - quotedMessage: Binding? = nil + quotedMessage: Binding? = nil, + editedMessage: Binding? = nil, + willSendMessage: (() -> Void)? = nil ) { self.channelController = channelController self.messageController = messageController self.eventsController = eventsController ?? channelController.client.eventsController() self.quotedMessage = quotedMessage + self.editedMessage = editedMessage + self.willSendMessage = willSendMessage self.eventsController.delegate = self @@ -350,18 +365,28 @@ import SwiftUI } open func sendMessage( - quotedMessage: ChatMessage?, - editedMessage: ChatMessage?, isSilent: Bool = false, skipPush: Bool = false, skipEnrichUrl: Bool = false, extraData: [String: RawJSON] = [:], - completion: @escaping @MainActor () -> Void + completion: (@MainActor () -> Void)? = nil ) { + guard !isSendingMessage else { return } + isSendingMessage = true + defer { checkChannelCooldown() } + willSendMessage?() + + // Reset edited and quoted message on message finish send + let completion: @MainActor () -> Void = { [weak self] in + self?.editedMessage?.wrappedValue = nil + self?.quotedMessage?.wrappedValue = nil + completion?() + } + if let composerCommand, composerCommand.id != "instantCommands" { let commandId = composerCommand.id let commandText = text @@ -383,7 +408,7 @@ import SwiftUI clearRemovedMentions() let mentionedUserIds = mentionedUsers.map(\.id) - if let editedMessage { + if let editedMessage = self.editedMessage?.wrappedValue { edit( message: editedMessage, attachments: try? convertAddedAssetsToPayloads(), @@ -401,7 +426,7 @@ import SwiftUI mentionedUserIds: mentionedUserIds, showReplyInChannel: showReplyInChannel, isSilent: isSilent, - quotedMessageId: quotedMessage?.id, + quotedMessageId: quotedMessage?.wrappedValue?.id, skipPush: skipPush, skipEnrichUrl: skipEnrichUrl, extraData: extraData @@ -410,6 +435,7 @@ import SwiftUI case .success: completion() case .failure: + self?.isSendingMessage = false self?.errorShown = true } } @@ -419,7 +445,7 @@ import SwiftUI isSilent: isSilent, attachments: attachments, mentionedUserIds: mentionedUserIds, - quotedMessageId: quotedMessage?.id, + quotedMessageId: quotedMessage?.wrappedValue?.id, skipPush: skipPush, skipEnrichUrl: skipEnrichUrl, extraData: extraData @@ -428,6 +454,7 @@ import SwiftUI case .success: completion() case .failure: + self?.isSendingMessage = false self?.errorShown = true } } @@ -435,6 +462,7 @@ import SwiftUI clearInputData() } catch { + isSendingMessage = false errorShown = true } } @@ -743,12 +771,13 @@ import SwiftUI attachments: attachments ?? [] ) { [weak self] error in if error != nil { + self?.isSendingMessage = false self?.errorShown = true } else { completion() } } - + clearInputData() } @@ -861,8 +890,11 @@ import SwiftUI // This is needed because of autocompleting text from the keyboard. // The update of the text is done in the next cycle, so it overrides // the setting of this value to empty string. + // isSendingMessage is also reset here so the guard in sendMessage() stays + // active for the full delay, preventing double-sends. DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { [weak self] in self?.text = "" + self?.isSendingMessage = false } } @@ -912,7 +944,7 @@ import SwiftUI do { let fileSize = try AttachmentFile(url: url).size - let canAdd = fileSize < chatClient.maxAttachmentSize(for: url) + let canAdd = fileSize <= chatClient.maxAttachmentSize(for: url, fallbackSize: utils.composerConfig.maxAttachmentSize) attachmentSizeExceeded = !canAdd return canAdd } catch { @@ -987,6 +1019,7 @@ final class FileAddedAsset { // The converter responsible to map attachments to assets and vice versa. @MainActor class MessageAttachmentsConverter { + @Injected(\.chatClient) private var chatClient @Injected(\.utils) var utils /// Converts the added assets to payloads. @@ -1065,8 +1098,9 @@ final class FileAddedAsset { addedAssets.fileAssets.append(fileAsset) group?.leave() case .voiceRecording: - guard let addedVoiceRecording = attachment.toAddedVoiceRecording() else { break } - addedAssets.voiceAssets.append(addedVoiceRecording) + if let addedVoiceRecording = attachment.toAddedVoiceRecording() { + addedAssets.voiceAssets.append(addedVoiceRecording) + } group?.leave() case .linkPreview, .audio, .giphy, .unknown: break @@ -1167,13 +1201,11 @@ final class FileAddedAsset { return } - utils.imageLoader.loadImage( + utils.mediaLoader.loadImage( url: imageAttachment.imageURL, - imageCDN: utils.imageCDN, - resize: false, - preferredSize: nil + options: ImageLoadOptions(resize: nil, cdnRequester: utils.cdnRequester) ) { result in - if let image = try? result.get() { + if let image = (try? result.get())?.image { let imageAsset = AddedAsset( image: image, id: imageAttachment.id.rawValue, diff --git a/Sources/StreamChatSwiftUI/ChatComposer/Polls/CreatePollView.swift b/Sources/StreamChatSwiftUI/ChatComposer/Polls/CreatePollView.swift index 435c8551c..5fe187b96 100644 --- a/Sources/StreamChatSwiftUI/ChatComposer/Polls/CreatePollView.swift +++ b/Sources/StreamChatSwiftUI/ChatComposer/Polls/CreatePollView.swift @@ -49,7 +49,7 @@ public struct CreatePollView: View { .environment(\.defaultMinListRowHeight, 1) .listStyle(.plain) } - .background(Color(colors.backgroundElevationElevation1).ignoresSafeArea()) + .background(Color(colors.backgroundCoreElevation1).ignoresSafeArea()) .modifier( CreatePollToolbarModifier( factory: factory, @@ -356,7 +356,7 @@ private struct CreatePollOptionRow: View { Text(L10n.Composer.Polls.duplicateOption) .font(fonts.subheadline) } - .foregroundColor(Color(colors.alert)) + .foregroundColor(Color(colors.accentError)) .padding(.horizontal, tokens.spacingMd) .padding(.bottom, showsError ? tokens.spacingSm : 0) .frame(height: showsError ? nil : 0, alignment: .top) @@ -441,7 +441,7 @@ private struct CreatePollMaxVotesStepper: View { .background( Circle() .strokeBorder( - Color(enabled ? colors.buttonSecondaryBorder : colors.borderUtilityDisabled), + Color(enabled ? colors.buttonSecondaryBorder : colors.borderUtilityDisabledOnSurface), lineWidth: 1 ) ) @@ -465,7 +465,7 @@ private struct CreatePollRowModifier: ViewModifier { if #available(iOS 15.0, *) { content .listRowSeparator(.hidden) - .listRowBackground(Color(colors.backgroundElevationElevation1)) + .listRowBackground(Color(colors.backgroundCoreElevation1)) .listRowInsets(EdgeInsets( top: topSpacing, leading: tokens.spacingMd, diff --git a/Sources/StreamChatSwiftUI/ChatComposer/QuotedMessageView/ComposerQuotedMessageView.swift b/Sources/StreamChatSwiftUI/ChatComposer/QuotedMessageView/ComposerQuotedMessageView.swift index 985530e2a..50ce00b17 100644 --- a/Sources/StreamChatSwiftUI/ChatComposer/QuotedMessageView/ComposerQuotedMessageView.swift +++ b/Sources/StreamChatSwiftUI/ChatComposer/QuotedMessageView/ComposerQuotedMessageView.swift @@ -3,7 +3,6 @@ // import StreamChat -import StreamChatCommonUI import SwiftUI /// A quoted message view with a dismiss button overlay. diff --git a/Sources/StreamChatSwiftUI/ChatComposer/SendInChannelView.swift b/Sources/StreamChatSwiftUI/ChatComposer/SendInChannelView.swift index 725501cfc..7f6b03bc7 100644 --- a/Sources/StreamChatSwiftUI/ChatComposer/SendInChannelView.swift +++ b/Sources/StreamChatSwiftUI/ChatComposer/SendInChannelView.swift @@ -38,14 +38,14 @@ struct SendInChannelView: View { ZStack { if sendInChannel { RoundedRectangle(cornerRadius: tokens.radiusSm) - .fill(Color(colors.controlRadiocheckBackgroundSelected)) + .fill(Color(colors.controlRadioCheckBackgroundSelected)) .frame(width: checkboxSize, height: checkboxSize) Image(systemName: "checkmark") .font(.system(size: 11, weight: .bold)) - .foregroundColor(Color(colors.controlRadiocheckIconSelected)) + .foregroundColor(Color(colors.controlRadioCheckIcon)) } else { RoundedRectangle(cornerRadius: tokens.radiusSm) - .stroke(Color(colors.controlRadiocheckBorder), lineWidth: 1) + .stroke(Color(colors.controlRadioCheckBorder), lineWidth: 1) .frame(width: checkboxSize, height: checkboxSize) } } diff --git a/Sources/StreamChatSwiftUI/ChatComposer/SlowModeView.swift b/Sources/StreamChatSwiftUI/ChatComposer/SlowModeView.swift index 335083e95..158fd948f 100644 --- a/Sources/StreamChatSwiftUI/ChatComposer/SlowModeView.swift +++ b/Sources/StreamChatSwiftUI/ChatComposer/SlowModeView.swift @@ -22,7 +22,7 @@ public struct SlowModeView: View { Text("\(cooldownDuration)") .font(fonts.bodyBold) .frame(width: size, height: size) - .background(Color(colors.backgroundCoreDisabled)) + .background(Color(colors.backgroundUtilityDisabled)) .foregroundColor(Color(colors.textDisabled)) .clipShape(Capsule()) .accessibilityIdentifier("SlowModeView") diff --git a/Sources/StreamChatSwiftUI/ChatComposer/Suggestions/Commands/CommandSuggestionsView.swift b/Sources/StreamChatSwiftUI/ChatComposer/Suggestions/Commands/CommandSuggestionsView.swift index a577fbb4a..517ca884c 100644 --- a/Sources/StreamChatSwiftUI/ChatComposer/Suggestions/Commands/CommandSuggestionsView.swift +++ b/Sources/StreamChatSwiftUI/ChatComposer/Suggestions/Commands/CommandSuggestionsView.swift @@ -3,7 +3,6 @@ // import StreamChat -import StreamChatCommonUI import SwiftUI /// View for the command suggestions. @@ -68,7 +67,7 @@ struct CommandSuggestionsHeader: View { HStack { Text(L10n.Composer.Suggestions.Commands.header) .font(fonts.subheadline) - .foregroundColor(Color(colors.textLowEmphasis)) + .foregroundColor(Color(colors.textTertiary)) .accessibilityIdentifier("CommandSuggestionsHeader") Spacer() } @@ -92,25 +91,25 @@ struct CommandSuggestionView: View { .resizable() .scaledToFit() .frame(width: tokens.iconSizeMd, height: tokens.iconSizeMd) - .foregroundColor(Color(colors.textLowEmphasis)) + .foregroundColor(Color(colors.textTertiary)) .accessibilityIdentifier("image\(displayInfo.displayName)") VStack(alignment: .leading, spacing: 0) { HStack(spacing: tokens.spacingXxs) { Text(displayInfo.displayName) .font(fonts.body) - .foregroundColor(Color(colors.text)) + .foregroundColor(Color(colors.textPrimary)) .lineLimit(1) Text(displayInfo.format) .font(fonts.body) - .foregroundColor(Color(colors.textLowEmphasis)) + .foregroundColor(Color(colors.textTertiary)) .lineLimit(1) } if let description = displayInfo.description { Text(description) .font(fonts.caption1) - .foregroundColor(Color(colors.textLowEmphasis)) + .foregroundColor(Color(colors.textTertiary)) } } diff --git a/Sources/StreamChatSwiftUI/ChatComposer/Suggestions/Mentions/UserSuggestionsView.swift b/Sources/StreamChatSwiftUI/ChatComposer/Suggestions/Mentions/UserSuggestionsView.swift index d5615f14e..dcad456e7 100644 --- a/Sources/StreamChatSwiftUI/ChatComposer/Suggestions/Mentions/UserSuggestionsView.swift +++ b/Sources/StreamChatSwiftUI/ChatComposer/Suggestions/Mentions/UserSuggestionsView.swift @@ -88,7 +88,7 @@ public struct UserSuggestionView: View { Text(user.name ?? user.id) .lineLimit(1) .font(fonts.body) - .foregroundColor(Color(colors.text)) + .foregroundColor(Color(colors.textPrimary)) Spacer() } diff --git a/Sources/StreamChatSwiftUI/ChatComposer/TrailingComposerView.swift b/Sources/StreamChatSwiftUI/ChatComposer/TrailingComposerView.swift index a11e0ff1c..ba674d27a 100644 --- a/Sources/StreamChatSwiftUI/ChatComposer/TrailingComposerView.swift +++ b/Sources/StreamChatSwiftUI/ChatComposer/TrailingComposerView.swift @@ -3,7 +3,6 @@ // import StreamChat -import StreamChatCommonUI import SwiftUI /// The button responsible to start voice recording. diff --git a/Sources/StreamChatSwiftUI/ChatComposer/TrailingInputComposerView.swift b/Sources/StreamChatSwiftUI/ChatComposer/TrailingInputComposerView.swift index 38ea3dd35..2f246382c 100644 --- a/Sources/StreamChatSwiftUI/ChatComposer/TrailingInputComposerView.swift +++ b/Sources/StreamChatSwiftUI/ChatComposer/TrailingInputComposerView.swift @@ -9,6 +9,7 @@ struct TrailingInputComposerView: View { @Binding var text: String @Binding var recordingState: VoiceRecordingState + @Binding var composerCommand: ComposerCommand? var composerInputState: MessageComposerInputState var startRecording: @MainActor () -> Void var stopRecording: @MainActor () -> Void @@ -17,13 +18,22 @@ struct TrailingInputComposerView: View { var body: some View { switch composerInputState { - case .creating(let hasContent): - factory.makeSendMessageButton( - options: SendMessageButtonOptions( - enabled: hasContent, - onTap: sendMessage + case .creating(let hasContent, let hasCommand): + if hasCommand { + factory.makeConfirmEditButton( + options: ConfirmEditButtonOptions( + enabled: hasContent, + onTap: sendMessage + ) ) - ) + } else { + factory.makeSendMessageButton( + options: SendMessageButtonOptions( + enabled: hasContent, + onTap: sendMessage + ) + ) + } case .editing(let hasContent): factory.makeConfirmEditButton( options: ConfirmEditButtonOptions( diff --git a/Sources/StreamChatSwiftUI/ChatMessageList/AsyncVoiceMessages/AudioVisualizationView.swift b/Sources/StreamChatSwiftUI/ChatMessageList/AsyncVoiceMessages/AudioVisualizationView.swift index f46eaef5b..fa70df742 100644 --- a/Sources/StreamChatSwiftUI/ChatMessageList/AsyncVoiceMessages/AudioVisualizationView.swift +++ b/Sources/StreamChatSwiftUI/ChatMessageList/AsyncVoiceMessages/AudioVisualizationView.swift @@ -40,13 +40,13 @@ open class AudioVisualizationView: UIView { // MARK: - Configuration Properties /// The colour of the waveform bar that isn't part of the "played" duration. - open var barColor: UIColor { colors.textLowEmphasis } + open var barColor: UIColor { colors.textTertiary } /// The colour of the waveform bar that is part of the "played" duration. - open var highlightedBarColor: UIColor { colors.highlightedAccentBackground } + open var highlightedBarColor: UIColor { colors.accentPrimary } /// The colour of the waveform bar's background. - open var barBackgroundColor: UIColor { colors.background } + open var barBackgroundColor: UIColor { colors.backgroundCoreApp } /// The rendering mode of the waveform. On `.write` the view scrolls to accommodate new points /// while in `.read` it scales(up or down) all dataPoints to it's current size. diff --git a/Sources/StreamChatSwiftUI/ChatMessageList/AsyncVoiceMessages/VoiceRecordingContainerView.swift b/Sources/StreamChatSwiftUI/ChatMessageList/AsyncVoiceMessages/VoiceRecordingContainerView.swift index 8ebef6613..4b4ce23ad 100644 --- a/Sources/StreamChatSwiftUI/ChatMessageList/AsyncVoiceMessages/VoiceRecordingContainerView.swift +++ b/Sources/StreamChatSwiftUI/ChatMessageList/AsyncVoiceMessages/VoiceRecordingContainerView.swift @@ -51,11 +51,10 @@ public struct VoiceRecordingContainerView: View { ), isSentByCurrentUser: message.isSentByCurrentUser ) - .padding(.all, tokens.spacingXs) - .background(MessageAttachmentsBubbleConfiguration.attachmentBackgroundColor(for: message)) - .roundWithBorder(cornerRadius: tokens.messageBubbleRadiusAttachment) + .modifier(MessageAttachmentsBubbleConfiguration.VoiceRecordingContainerModifier(message: message, isFirst: isFirst)) } } + .frame(width: width, alignment: message.isRightAligned ? .trailing : .leading) .onReceive(handler.$context, perform: { value in guard message.voiceRecordingAttachments.count > 1 else { return } if value.state == .playing { @@ -97,7 +96,10 @@ struct VoiceRecordingView: View { var isSentByCurrentUser: Bool = false private var isActive: Bool { handler.isActive(for: addedVoiceRecording.url) } - private var showContextDuration: Bool { isActive && handler.context.currentTime > 0 } + + private var displayedPlaybackTime: TimeInterval { + handler.displayedTime(for: addedVoiceRecording.url, duration: addedVoiceRecording.duration) + } private var controlBorderColor: Color? { isSentByCurrentUser ? Color(colors.chatBorderOnChatOutgoing) : Color(colors.chatBorderOnChatIncoming) @@ -138,7 +140,7 @@ struct VoiceRecordingView: View { private var durationAndWaveform: some View { HStack(spacing: tokens.spacingXs) { - Text(utils.videoDurationFormatter.format(showContextDuration ? handler.context.currentTime : addedVoiceRecording.duration) ?? "") + Text(utils.videoDurationFormatter.format(displayedPlaybackTime) ?? "") .font(fonts.footnote.monospacedDigit()) .foregroundColor(Color(handler.isPlaying && isActive ? colors.accentPrimary : colors.textPrimary)) @@ -225,7 +227,10 @@ class VoiceRecordingHandler: ObservableObject, AudioPlayingDelegate { guard context.assetLocation == url else { return } switch context.state { case .playing: - isPlaying = true + if !isPlaying { + isPlaying = true + player.updateRate(rate) + } case .stopped, .paused: isPlaying = false default: @@ -247,13 +252,27 @@ class VoiceRecordingHandler: ObservableObject, AudioPlayingDelegate { case .double: rate = .half default: rate = .normal } - player.updateRate(rate) + if isPlaying { + player.updateRate(rate) + } } func isActive(for url: URL) -> Bool { context.assetLocation == url } + /// Returns remaining playback time when playing/paused, or the total duration otherwise. + func displayedTime(for url: URL, duration: TimeInterval) -> TimeInterval { + guard isActive(for: url) else { return duration } + switch context.state { + case .playing, .paused: + let resolvedDuration = max(duration, context.duration) + return max(resolvedDuration - context.currentTime, 0) + default: + return duration + } + } + func seek(to time: TimeInterval, loadingFrom url: URL? = nil) { if let url, !isActive(for: url) { player.loadAsset(from: url) diff --git a/Sources/StreamChatSwiftUI/ChatMessageList/AsyncVoiceMessages/WaveformView.swift b/Sources/StreamChatSwiftUI/ChatMessageList/AsyncVoiceMessages/WaveformView.swift index ae1039e0e..92086e47c 100644 --- a/Sources/StreamChatSwiftUI/ChatMessageList/AsyncVoiceMessages/WaveformView.swift +++ b/Sources/StreamChatSwiftUI/ChatMessageList/AsyncVoiceMessages/WaveformView.swift @@ -77,7 +77,7 @@ open class WaveformView: UIView { open lazy var audioVisualizationView: AudioVisualizationView = .init() .withoutAutoresizingMaskConstraints - open lazy var slider: UISlider = .init() + open lazy var slider: UISlider = WaveformSlider() .withoutAutoresizingMaskConstraints // MARK: - UI Lifecycle @@ -197,8 +197,8 @@ open class WaveformView: UIView { thumb = cached } else { thumb = Self.makeSliderThumbImage( - fillColor: colors.accentPrimary, - borderColor: colors.backgroundCoreApp + fillColor: colors.controlPlaybackThumbBackgroundActive, + borderColor: colors.controlPlaybackThumbBorderActive ) Self.cachedActiveThumb = thumb } @@ -207,8 +207,8 @@ open class WaveformView: UIView { thumb = cached } else { thumb = Self.makeSliderThumbImage( - fillColor: colors.backgroundCoreApp, - borderColor: colors.borderCoreOpacity25 + fillColor: colors.controlPlaybackThumbBackgroundDefault, + borderColor: colors.controlPlaybackThumbBorderDefault ) Self.cachedInactiveThumb = thumb } @@ -218,6 +218,15 @@ open class WaveformView: UIView { } } +/// Extends the track rect so the visible thumb circle aligns with the waveform edges +/// rather than being inset by half the thumb image width (which includes the shadow). +private class WaveformSlider: UISlider { + override func trackRect(forBounds bounds: CGRect) -> CGRect { + let thumbShadow: CGFloat = 6 + return bounds.insetBy(dx: -thumbShadow, dy: 0) + } +} + /// SwiftUI wrapper used during active recording (locked/stopped states in the composer). /// Passes raw waveform data directly rather than an `AddedVoiceRecording`. struct RecordingWaveform: UIViewRepresentable { @@ -280,11 +289,13 @@ struct WaveformViewSwiftUI: UIViewRepresentable { private func updateContent(for view: WaveformView) { if let audioContext, addedVoiceRecording.url == audioContext.assetLocation { + let duration = max(audioContext.duration, addedVoiceRecording.duration, 0.001) + let currentTime = min(max(audioContext.currentTime, 0), duration) view.content = .init( isRecording: false, isPlaying: isPlaying, - duration: audioContext.duration, - currentTime: audioContext.currentTime, + duration: duration, + currentTime: currentTime, waveform: addedVoiceRecording.waveform ) } else { diff --git a/Sources/StreamChatSwiftUI/ChatMessageList/AttachmentDownloadingStateView.swift b/Sources/StreamChatSwiftUI/ChatMessageList/AttachmentDownloadingStateView.swift deleted file mode 100644 index 67ca5d307..000000000 --- a/Sources/StreamChatSwiftUI/ChatMessageList/AttachmentDownloadingStateView.swift +++ /dev/null @@ -1,65 +0,0 @@ -// -// Copyright © 2026 Stream.io Inc. All rights reserved. -// - -import StreamChat -import SwiftUI - -/// View used for displaying progress while an attachment is being downloaded. -struct AttachmentDownloadingStateView: View { - @Injected(\.images) private var images - @Injected(\.colors) private var colors - @Injected(\.fonts) private var fonts - - var downloadState: AttachmentDownloadingState - var url: URL - - var body: some View { - Group { - switch downloadState.state { - case let .downloading(progress: progress): - BottomRightView { - PercentageProgressView(progress: progress) - } - - case .downloadingFailed: - BottomRightView { - Image(uiImage: images.messageListErrorIndicator) - .foregroundColor(Color(colors.alert)) - .background(Color.white) - .clipShape(Circle()) - .offset(x: -4, y: -4) - } - - case .downloaded: - EmptyView() - @unknown default: - EmptyView() - } - } - .id("\(url.absoluteString)-\(downloadState.state))") - } -} - -/// View modifier enabling downloading state display. -struct AttachmentDownloadingStateViewModifier: ViewModifier { - var downloadState: AttachmentDownloadingState? - var url: URL - - func body(content: Content) -> some View { - content - .overlay( - downloadState != nil ? AttachmentDownloadingStateView(downloadState: downloadState!, url: url) : nil - ) - } -} - -extension View { - /// Attaches a downloading state indicator. - /// - Parameters: - /// - downloadState: the download state of the attachment. - /// - url: the url of the attachment. - public func withDownloadingStateIndicator(for downloadState: AttachmentDownloadingState?, url: URL) -> some View { - modifier(AttachmentDownloadingStateViewModifier(downloadState: downloadState, url: url)) - } -} diff --git a/Sources/StreamChatSwiftUI/ChatMessageList/AttachmentTextView.swift b/Sources/StreamChatSwiftUI/ChatMessageList/AttachmentTextView.swift index 729bcf090..1e7e19505 100644 --- a/Sources/StreamChatSwiftUI/ChatMessageList/AttachmentTextView.swift +++ b/Sources/StreamChatSwiftUI/ChatMessageList/AttachmentTextView.swift @@ -6,35 +6,46 @@ import StreamChat import SwiftUI public struct AttachmentTextView: View { - @Injected(\.colors) private var colors - @Injected(\.fonts) private var fonts @Injected(\.tokens) private var tokens var factory: Factory var message: ChatMessage - let injectedBackgroundColor: UIColor? + var availableWidth: CGFloat + var translationLanguage: TranslationLanguage? - public init(factory: Factory = DefaultViewFactory.shared, message: ChatMessage, injectedBackgroundColor: UIColor? = nil) { + public init( + factory: Factory = DefaultViewFactory.shared, + message: ChatMessage, + availableWidth: CGFloat, + translationLanguage: TranslationLanguage? = nil + ) { self.factory = factory self.message = message - self.injectedBackgroundColor = injectedBackgroundColor + self.availableWidth = availableWidth + self.translationLanguage = translationLanguage } public var body: some View { - HStack { - factory.makeStreamTextView(options: .init(message: message)) - .padding(.horizontal, tokens.spacingXxs) - .fixedSize(horizontal: false, vertical: true) - Spacer() - } - .background(Color(backgroundColor)) + factory.makeStreamTextView(options: .init( + message: message, + translationLanguage: translationLanguage + )) + .padding(.horizontal, tokens.spacingXxs) + .fixedSize(horizontal: false, vertical: true) + .frame(maxWidth: maxTextWidth, alignment: .leading) .accessibilityIdentifier("MessageTextView") } - private var backgroundColor: UIColor { - if let injectedBackgroundColor { - return injectedBackgroundColor - } - return message.isSentByCurrentUser ? colors.chatBackgroundOutgoing : colors.chatBackgroundIncoming + /// Limit text width for messages with portrait image attachment. + private var maxTextWidth: CGFloat { + guard message.hasSingleMediaAttachmentWithCaption else { return availableWidth } + let mediaAttachments = MediaAttachment.galleryOrdered(from: message) + let orientation = MediaGalleryOrientation(mediaAttachments: mediaAttachments) + let size = MessageMediaAttachmentsContainerView.containerSize( + for: mediaAttachments.count, + orientation: orientation, + maxItemWidth: availableWidth + ) + return size.width } } diff --git a/Sources/StreamChatSwiftUI/ChatMessageList/AttachmentUploadingStateView.swift b/Sources/StreamChatSwiftUI/ChatMessageList/AttachmentUploadingStateView.swift index 137b786bc..aef18ee86 100644 --- a/Sources/StreamChatSwiftUI/ChatMessageList/AttachmentUploadingStateView.swift +++ b/Sources/StreamChatSwiftUI/ChatMessageList/AttachmentUploadingStateView.swift @@ -9,7 +9,6 @@ import SwiftUI struct AttachmentUploadingStateView: View { @Injected(\.images) private var images @Injected(\.colors) private var colors - @Injected(\.fonts) private var fonts var uploadState: AttachmentUploadingState var url: URL @@ -18,18 +17,21 @@ struct AttachmentUploadingStateView: View { Group { switch uploadState.state { case let .uploading(progress: progress): - BottomRightView { - PercentageProgressView(progress: progress) + ZStack { + Color(colors.backgroundCoreOverlayLight) + LoadingSpinnerView( + size: LoadingSpinnerSize.medium, + progress: Double(progress) + ) } + .allowsHitTesting(false) case .uploadingFailed: - BottomRightView { - Image(uiImage: images.messageListErrorIndicator) - .foregroundColor(Color(colors.alert)) - .background(Color.white) - .clipShape(Circle()) - .offset(x: -4, y: -4) + ZStack { + Color(colors.backgroundCoreOverlayLight) + RetryBadgeView() } + .allowsHitTesting(false) case .uploaded: TopRightView { diff --git a/Sources/StreamChatSwiftUI/ChatMessageList/DeletedMessageView.swift b/Sources/StreamChatSwiftUI/ChatMessageList/DeletedMessageView.swift index a48922ffd..e69f63529 100644 --- a/Sources/StreamChatSwiftUI/ChatMessageList/DeletedMessageView.swift +++ b/Sources/StreamChatSwiftUI/ChatMessageList/DeletedMessageView.swift @@ -7,59 +7,33 @@ import SwiftUI /// View displayed when a message is deleted. public struct DeletedMessageView: View { - @Injected(\.chatClient) private var chatClient - @Injected(\.images) private var images @Injected(\.fonts) private var fonts @Injected(\.colors) private var colors - @Injected(\.utils) private var utils - - private var dateFormatter: DateFormatter { - utils.dateFormatter - } - - private var deletedMessageVisibility: ChatClientConfig.DeletedMessageVisibility { - chatClient.config.deletedMessagesVisibility - } + @Injected(\.tokens) private var tokens var message: ChatMessage var isFirst: Bool public var body: some View { - VStack( - alignment: message.isRightAligned ? .trailing : .leading, - spacing: 4 - ) { + HStack(spacing: tokens.spacingXxs) { + Image(systemName: "nosign") + .resizable() + .scaledToFit() + .frame(width: tokens.iconSizeSm, height: tokens.iconSizeSm) Text(L10n.Message.deletedMessagePlaceholder) .font(fonts.body) - .standardPadding() - .foregroundColor(Color(colors.textLowEmphasis)) - .messageBubble(for: message, isFirst: isFirst) - .accessibilityIdentifier("deletedMessageText") - - if message.isSentByCurrentUser { - HStack { - if message.isRightAligned { - Spacer() - } - - if deletedMessageVisibility == .visibleForCurrentUser { - Image(uiImage: images.onlyVisibleToCurrentUser) - .customizable() - .frame(maxWidth: 12) - .accessibilityIdentifier("onlyVisibleToYouImageView") - - Text(L10n.Message.onlyVisibleToYou) - .font(fonts.footnote) - .accessibilityIdentifier("onlyVisibleToYouLabel") - } - - Text(dateFormatter.string(from: message.createdAt)) - .font(fonts.footnote) - } - .foregroundColor(Color(colors.textLowEmphasis)) - } } + .foregroundColor(messageTextColor) + .standardPadding() + .messageBubble(for: message, isFirst: isFirst) + .accessibilityIdentifier("deletedMessageText") .accessibilityElement(children: .contain) .accessibilityIdentifier("DeletedMessageView") } + + private var messageTextColor: Color { + message.isSentByCurrentUser + ? Color(colors.chatTextOutgoing) + : Color(colors.chatTextIncoming) + } } diff --git a/Sources/StreamChatSwiftUI/ChatMessageList/FileAttachmentPreview.swift b/Sources/StreamChatSwiftUI/ChatMessageList/FileAttachmentPreview.swift index d86342c0d..1497376ae 100644 --- a/Sources/StreamChatSwiftUI/ChatMessageList/FileAttachmentPreview.swift +++ b/Sources/StreamChatSwiftUI/ChatMessageList/FileAttachmentPreview.swift @@ -14,9 +14,7 @@ public struct FileAttachmentPreview: View { @Injected(\.images) private var images @Injected(\.utils) private var utils - private var fileCDN: FileCDN { - utils.fileCDN - } + private var cdnRequester: CDNRequester { utils.cdnRequester } let attachment: ChatMessageFileAttachment @@ -62,12 +60,14 @@ public struct FileAttachmentPreview: View { } } .onAppear { - fileCDN.adjustedURL(for: url) { result in - switch result { - case let .success(url): - adjustedUrl = url - case let .failure(error): - self.error = error + cdnRequester.fileRequest(for: url, options: .init()) { result in + Task { @MainActor in + switch result { + case let .success(cdnRequest): + adjustedUrl = cdnRequest.url + case let .failure(error): + self.error = error + } } } } @@ -90,9 +90,7 @@ public struct FileAttachmentPreview: View { } ToolbarItem(placement: .navigationBarTrailing) { - if utils.messageListConfig.downloadFileAttachmentsEnabled { - DownloadShareAttachmentView(attachment: attachment) - } + DownloadShareAttachmentView(attachment: attachment) } } } diff --git a/Sources/StreamChatSwiftUI/ChatMessageList/FileAttachmentView.swift b/Sources/StreamChatSwiftUI/ChatMessageList/FileAttachmentView.swift index b2192fe3d..4e34d8957 100644 --- a/Sources/StreamChatSwiftUI/ChatMessageList/FileAttachmentView.swift +++ b/Sources/StreamChatSwiftUI/ChatMessageList/FileAttachmentView.swift @@ -6,7 +6,6 @@ import StreamChat import SwiftUI public struct FileAttachmentsContainer: View { - @Injected(\.colors) var colors @Injected(\.tokens) var tokens var factory: Factory var message: ChatMessage @@ -29,15 +28,19 @@ public struct FileAttachmentsContainer: View { } public var body: some View { + let attachments = message.fileAttachments VStack(spacing: tokens.spacingXxs) { - ForEach(message.fileAttachments) { attachment in + ForEach(attachments) { attachment in FileAttachmentView( attachment: attachment, width: width, isFirst: isFirst ) - .background(MessageAttachmentsBubbleConfiguration.attachmentBackgroundColor(for: message)) - .roundWithBorder(cornerRadius: tokens.messageBubbleRadiusAttachment) + .modifier(MessageAttachmentsBubbleConfiguration.AttachmentContainerModifier( + message: message, + isFirst: isFirst, + isSingleWithoutCaption: message.text.isEmpty && attachments.count == 1 + )) } } .accessibilityIdentifier("FileAttachmentsContainer") @@ -45,10 +48,6 @@ public struct FileAttachmentsContainer: View { } public struct FileAttachmentView: View { - @Injected(\.utils) private var utils - @Injected(\.images) private var images - @Injected(\.fonts) private var fonts - @Injected(\.colors) private var colors @Injected(\.tokens) private var tokens @Injected(\.chatClient) private var chatClient @@ -69,30 +68,37 @@ public struct FileAttachmentView: View { FileAttachmentDisplayView( url: attachment.assetURL, title: attachment.title ?? "", - sizeString: attachment.file.sizeString + sizeString: attachment.file.sizeString, + uploadingState: attachment.uploadingState, + onRetry: { retryUpload() } ) .onTapGesture { - fullScreenShown = true + if attachment.uploadingState?.state != .uploadingFailed { + fullScreenShown = true + } } .accessibilityAction { - fullScreenShown = true + if attachment.uploadingState?.state != .uploadingFailed { + fullScreenShown = true + } } Spacer() - - if utils.messageListConfig.downloadFileAttachmentsEnabled { - DownloadShareAttachmentView(attachment: attachment) - } } .padding(.all, tokens.spacingSm) .frame(width: width) - .withUploadingStateIndicator(for: attachment.uploadingState, url: attachment.assetURL) - .withDownloadingStateIndicator(for: attachment.downloadingState, url: attachment.assetURL) .sheet(isPresented: $fullScreenShown) { FileAttachmentPreview(attachment: attachment) } .accessibilityIdentifier("FileAttachmentView") } + + private func retryUpload() { + let messageId = attachment.id.messageId + let cid = attachment.id.cid + let controller = chatClient.messageController(cid: cid, messageId: messageId) + controller.resendMessage() + } } public struct FileAttachmentDisplayView: View { @@ -104,11 +110,21 @@ public struct FileAttachmentDisplayView: View { var url: URL var title: String var sizeString: String + var uploadingState: AttachmentUploadingState? + var onRetry: (() -> Void)? - public init(url: URL, title: String, sizeString: String) { + public init( + url: URL, + title: String, + sizeString: String, + uploadingState: AttachmentUploadingState? = nil, + onRetry: (() -> Void)? = nil + ) { self.url = url self.title = title self.sizeString = sizeString + self.uploadingState = uploadingState + self.onRetry = onRetry } public var body: some View { @@ -123,20 +139,87 @@ public struct FileAttachmentDisplayView: View { .font(fonts.body) .lineLimit(1) .foregroundColor(Color(colors.textPrimary)) - Text(sizeString) - .font(fonts.subheadline) - .lineLimit(1) - .foregroundColor(Color(colors.textTertiary)) + subtitleContent } Spacer() } .accessibilityElement(children: .combine) } + // MARK: - Private + + @ViewBuilder + private var subtitleContent: some View { + if let uploadingState { + switch uploadingState.state { + case let .uploading(progress): + uploadingSubtitle(progress: progress, file: uploadingState.file) + case .uploadingFailed: + uploadFailedSubtitle + default: + fileSizeText + } + } else { + fileSizeText + } + } + + private func uploadingSubtitle(progress: Double, file: AttachmentFile) -> some View { + HStack(spacing: tokens.spacingXxs) { + LoadingSpinnerView( + size: LoadingSpinnerSize.extraSmall, + progress: Double(progress) + ) + Text(Self.uploadProgressText(progress: progress, file: file)) + .font(fonts.subheadline) + .lineLimit(1) + .foregroundColor(Color(colors.textSecondary)) + } + } + + private var uploadFailedSubtitle: some View { + VStack(alignment: .leading, spacing: tokens.spacingXxxs) { + HStack(spacing: tokens.spacingXxs) { + Image(systemName: "exclamationmark.triangle.fill") + .resizable() + .scaledToFit() + .frame(width: tokens.iconSizeSm, height: tokens.iconSizeSm) + .foregroundColor(Color(colors.accentError)) + Text(L10n.Message.Sending.attachmentUploadFailed) + .font(fonts.subheadline) + .lineLimit(1) + .foregroundColor(Color(colors.textSecondary)) + } + if let onRetry { + Button(action: onRetry) { + Text(L10n.Message.Sending.attachmentRetryUpload) + .font(fonts.subheadline) + .foregroundColor(Color(colors.textLink)) + } + .buttonStyle(.plain) + } + } + } + + private var fileSizeText: some View { + Text(sizeString) + .font(fonts.subheadline) + .lineLimit(1) + .foregroundColor(Color(colors.textTertiary)) + } + private var previewImage: UIImage { let iconName = url.pathExtension return images.fileIconPreviews[iconName] ?? images.iconOther } + + static func uploadProgressText(progress: Double, file: AttachmentFile) -> String { + let formatter = AttachmentFile.sizeFormatter + let uploaded = Int64(progress * Double(file.size)) + let uploadedText = formatter.string(fromByteCount: uploaded) + let totalText = formatter.string(fromByteCount: file.size) + return "\(uploadedText) / \(totalText)" + } } struct DownloadShareAttachmentView: View { @@ -149,7 +232,7 @@ struct DownloadShareAttachmentView: View @State private var shareButtonShown: Bool var attachment: ChatMessageAttachment - + init(attachment: ChatMessageAttachment) { self.attachment = attachment let downloadButtonShown: Bool = (attachment.uploadingState == nil || attachment.uploadingState?.state == .uploaded) && attachment.downloadingState == nil @@ -196,12 +279,20 @@ struct DownloadShareAttachmentView: View let messageId = attachment.id.messageId let cid = attachment.id.cid let messageController = chatClient.messageController(cid: cid, messageId: messageId) - messageController.downloadAttachment(attachment) { result in - if case .failure(let error) = result { - log.error("Error downloading attachment \(error.localizedDescription)") - } else { - downloadButtonShown = false - shareButtonShown = true + let cdnRequester = InjectedValues[\.utils].cdnRequester + cdnRequester.fileRequest(for: attachment.remoteURL, options: .init()) { result in + switch result { + case let .success(cdnRequest): + messageController.downloadAttachment(attachment, remoteURL: cdnRequest.url) { result in + if case let .failure(error) = result { + log.error("Error downloading attachment: \(error.localizedDescription)") + } else { + downloadButtonShown = false + shareButtonShown = true + } + } + case let .failure(error): + log.error("Error resolving CDN URL: \(error.localizedDescription)") } } } diff --git a/Sources/StreamChatSwiftUI/ChatMessageList/Gallery/MediaViewer.swift b/Sources/StreamChatSwiftUI/ChatMessageList/Gallery/MediaViewer.swift index 293b74b19..0ab2cf5ac 100644 --- a/Sources/StreamChatSwiftUI/ChatMessageList/Gallery/MediaViewer.swift +++ b/Sources/StreamChatSwiftUI/ChatMessageList/Gallery/MediaViewer.swift @@ -4,6 +4,7 @@ import AVKit import StreamChat +import StreamChatCommonUI import SwiftUI /// View used for displaying image attachments in a gallery. @@ -61,94 +62,87 @@ public struct MediaViewer: View { } public var body: some View { - GeometryReader { reader in - VStack { - viewFactory.makeMediaViewerHeader( - options: MediaViewerHeaderOptions( - title: author.name ?? "", - subtitle: message.map { - utils.galleryHeaderViewDateFormatter.format($0.createdAt) - } ?? author.onlineText, - shown: $isShown - ) - ) - - Divider() - - TabView(selection: $selected) { - ForEach(0.. 100 { - presentationMode.wrappedValue.dismiss() + .tabViewStyle(.page(indexDisplayMode: .never)) + .background(Color(colors.backgroundCoreApp)) + .gesture( + DragGesture().onEnded { value in + if value.location.y - value.startLocation.y > 100 { + presentationMode.wrappedValue.dismiss() + } } - } - ) - - Divider() - - HStack { - ShareButtonView(content: sharingContent) - - Spacer() - - Text("\(selected + 1) of \(mediaAttachments.count)") - .font(fonts.subheadline) - .fontWeight(.semibold) - .foregroundColor(colors.textPrimary.toColor) + ) - Spacer() + Divider() - StreamIconButton(role: .primary, style: .ghost, size: .small) { - gridShown = true - } icon: { - Image(uiImage: images.gallery) - .renderingMode(.template) - .resizable() - .frame(width: 16, height: 16, alignment: .center) - .foregroundColor(Color(colors.textSecondary)) - } + viewFactory.makeMediaViewerFooterView( + options: MediaViewerFooterViewOptions( + shareContent: sharingContent, + shareFallbackURL: sharingFallbackURL, + selected: selected, + totalCount: mediaAttachments.count, + gridShown: $gridShown + ) + ) } - .padding(.all, tokens.spacingXl) } - .sheet(isPresented: $gridShown) { - GridMediaView( - factory: viewFactory, - attachments: mediaAttachments + .background(Color(colors.backgroundCoreApp).edgesIgnoringSafeArea(.all)) + .modifier( + viewFactory.makeMediaViewerToolbarModifier( + options: MediaViewerToolbarModifierOptions( + title: author.name ?? "", + subtitle: message.map { + utils.galleryHeaderViewDateFormatter.format($0.createdAt) + } ?? author.onlineText, + isShown: $isShown + ) ) - .modifier(PresentationDetentsModifier(sheetSizes: [.medium, .large])) - } + ) + .navigationBarTitleDisplayMode(.inline) + } + .sheet(isPresented: $gridShown) { + GridMediaView( + factory: viewFactory, + attachments: mediaAttachments, + onItemSelected: { index in + selected = index + gridShown = false + } + ) + .modifier(PresentationDetentsModifier(sheetSizes: [.medium, .large])) } } @@ -159,6 +153,14 @@ public struct MediaViewer: View { [] } } + + /// Used when there is no in-memory ``UIImage`` (videos never populate ``loadedImages``; images may still be loading). + private var sharingFallbackURL: URL? { + guard loadedImages[selected] == nil, + selected >= 0, + selected < mediaAttachments.count else { return nil } + return mediaAttachments[selected].url + } } struct GridMediaView: View { @@ -168,6 +170,7 @@ struct GridMediaView: View { let factory: Factory let attachments: [MediaAttachment] + var onItemSelected: ((Int) -> Void)? var body: some View { VStack(spacing: tokens.spacingLg) { @@ -178,30 +181,149 @@ struct GridMediaView: View { MediaAttachmentsGridView( factory: factory, attachments: attachments, - showAvatars: false + showAvatars: false, + onItemSelected: onItemSelected ) } .padding(.horizontal, tokens.spacingSm) .padding(.vertical, tokens.spacing2xl) - .background(colors.backgroundElevationElevation1.toColor.edgesIgnoringSafeArea(.all)) + .background(colors.backgroundCoreElevation1.toColor.edgesIgnoringSafeArea(.all)) } } -struct StreamVideoPlayer: View { - @Injected(\.utils) private var utils +// MARK: - Footer + +/// Default footer view for the media viewer. +/// Displays a share button, page counter, and grid toggle button. +public struct MediaViewerFooterView: View { + @Injected(\.colors) private var colors + @Injected(\.fonts) private var fonts + @Injected(\.images) private var images + @Injected(\.tokens) private var tokens + + let shareContent: [UIImage] + let shareFallbackURL: URL? + let selected: Int + let totalCount: Int + @Binding var gridShown: Bool + + public init( + shareContent: [UIImage], + shareFallbackURL: URL? = nil, + selected: Int, + totalCount: Int, + gridShown: Binding + ) { + self.shareContent = shareContent + self.shareFallbackURL = shareFallbackURL + self.selected = selected + self.totalCount = totalCount + _gridShown = gridShown + } + + public var body: some View { + HStack { + ShareButtonView(content: shareActivityItems) + + Spacer() + + Text(L10n.Message.Gallery.pageCount(selected + 1, totalCount)) + .font(fonts.subheadlineBold) + .foregroundColor(colors.textPrimary.toColor) + + Spacer() + + StreamIconButton(role: .secondary, style: .ghost, size: .medium) { + gridShown = true + } icon: { + Image(uiImage: images.gallery) + .customizable() + .frame(width: 16, height: 16) + .foregroundColor(Color(colors.textSecondary)) + } + } + .padding(.horizontal, tokens.spacingSm) + .frame(height: 48 + tokens.spacingSm * 2) + .background(Color(colors.backgroundCoreElevation1)) + } + + private var shareActivityItems: [Any] { + if !shareContent.isEmpty { + return shareContent + } + if let shareFallbackURL { + return [shareFallbackURL] + } + return [] + } +} + +// MARK: - Toolbar + +/// Toolbar modifier for the media viewer navigation bar. +/// Displays a back button, title/subtitle, in the navigation toolbar. +public struct MediaViewerToolbarModifier: ViewModifier { + @Injected(\.colors) private var colors + @Injected(\.fonts) private var fonts + + let title: String + let subtitle: String + @Binding var isShown: Bool + + public init(title: String, subtitle: String, isShown: Binding) { + self.title = title + self.subtitle = subtitle + _isShown = isShown + } + + public func body(content: Content) -> some View { + content + .toolbarThemed { + toolbarContent() + } + } - private var fileCDN: FileCDN { - utils.fileCDN + @ToolbarContentBuilder private func toolbarContent() -> some ToolbarContent { + ToolbarItem(placement: .navigationBarLeading) { + Button { + isShown = false + } label: { + Image(systemName: "chevron.backward") + .renderingMode(.template) + .font(.system(size: 16, weight: .medium)) + .foregroundColor(dismissButtonColor) + } + } + + ToolbarItem(placement: .principal) { + VStack(spacing: 2) { + Text(title) + .font(fonts.headline) + .foregroundColor(Color(colors.textPrimary)) + Text(subtitle) + .font(fonts.subheadline) + .foregroundColor(Color(colors.textSecondary)) + } + } } - private var avPlayerProvider: AVPlayerProvider { - utils.avPlayerProvider + private var dismissButtonColor: Color { + guard colors.navigationBarTintColor != colors.accentPrimary else { + return Color(colors.textPrimary) + } + return Color(colors.navigationBarTintColor) } +} + +struct StreamVideoPlayer: View { + @Injected(\.utils) private var utils + @Injected(\.chatClient) private var chatClient let url: URL @State var avPlayer: AVPlayer? @State var error: Error? + @State private var isVisible = false init(url: URL) { self.url = url @@ -215,17 +337,20 @@ struct StreamVideoPlayer: View { } } .onAppear { + isVisible = true guard avPlayer == nil else { avPlayer?.play() return } - fileCDN.adjustedURL(for: url) { result in + utils.mediaLoader.loadVideoAsset( + at: url, + options: VideoLoadOptions(cdnRequester: utils.cdnRequester) + ) { result in + guard isVisible else { return } switch result { - case let .success(url): - avPlayer = AVPlayer(url: url) - try? AVAudioSession.sharedInstance().setCategory(.playback, options: []) - avPlayer?.play() - self.avPlayerProvider.player(for: url) { result in + case let .success(videoAsset): + utils.avPlayerProvider.player(from: videoAsset) { result in + guard isVisible else { return } switch result { case let .success(player): self.avPlayer = player @@ -241,6 +366,7 @@ struct StreamVideoPlayer: View { } } .onDisappear { + isVisible = false avPlayer?.pause() } } diff --git a/Sources/StreamChatSwiftUI/ChatMessageList/Gallery/ShareButtonView.swift b/Sources/StreamChatSwiftUI/ChatMessageList/Gallery/ShareButtonView.swift index 7ed608da6..1faa52cd3 100644 --- a/Sources/StreamChatSwiftUI/ChatMessageList/Gallery/ShareButtonView.swift +++ b/Sources/StreamChatSwiftUI/ChatMessageList/Gallery/ShareButtonView.swift @@ -14,13 +14,13 @@ struct ShareButtonView: View { @State var isSharePresented = false var body: some View { - StreamIconButton(role: .primary, style: .ghost, size: .small) { + StreamIconButton(role: .secondary, style: .ghost, size: .medium) { isSharePresented = true } icon: { Image(uiImage: images.share) .customizable() .foregroundColor(Color(colors.textSecondary)) - .frame(width: 18, height: 22) + .frame(width: 20, height: 20) } .sheet(isPresented: $isSharePresented) { ShareActivityView(activityItems: content) diff --git a/Sources/StreamChatSwiftUI/ChatMessageList/Gallery/VideoPlayerFooterView.swift b/Sources/StreamChatSwiftUI/ChatMessageList/Gallery/VideoPlayerFooterView.swift index e740bdb46..e71e8532f 100644 --- a/Sources/StreamChatSwiftUI/ChatMessageList/Gallery/VideoPlayerFooterView.swift +++ b/Sources/StreamChatSwiftUI/ChatMessageList/Gallery/VideoPlayerFooterView.swift @@ -19,6 +19,6 @@ struct VideoPlayerFooterView: View { Spacer() } - .foregroundColor(Color(colors.text)) + .foregroundColor(Color(colors.textPrimary)) } } diff --git a/Sources/StreamChatSwiftUI/ChatMessageList/GiphyAttachmentView.swift b/Sources/StreamChatSwiftUI/ChatMessageList/GiphyAttachmentView.swift index 0482cd3dc..5916a9f1f 100644 --- a/Sources/StreamChatSwiftUI/ChatMessageList/GiphyAttachmentView.swift +++ b/Sources/StreamChatSwiftUI/ChatMessageList/GiphyAttachmentView.swift @@ -3,6 +3,7 @@ // import StreamChat +import StreamChatCommonUI import SwiftUI /// View for the giphy attachments. @@ -12,6 +13,7 @@ public struct GiphyAttachmentView: View { @Injected(\.fonts) private var fonts @Injected(\.images) private var images @Injected(\.tokens) private var tokens + @Injected(\.utils) private var utils let factory: Factory let message: ChatMessage @@ -47,7 +49,6 @@ public struct GiphyAttachmentView: View { .foregroundColor(colors.chatTextOutgoing.toColor) .padding(.all, tokens.spacingSm) } - LazyGiphyView( source: message.giphyAttachments[0].previewURL, width: width @@ -69,6 +70,8 @@ public struct GiphyAttachmentView: View { execute(action: action) } label: { Text(action.value.firstUppercased) + .lineLimit(1) + .minimumScaleFactor(0.5) .padding(.horizontal, 4) .padding(.vertical) } @@ -83,16 +86,15 @@ public struct GiphyAttachmentView: View { } } } + .frame(maxWidth: width) .modifier( factory.styles.makeMessageViewModifier( for: MessageModifierInfo( message: message, - isFirst: isFirst, - injectedBackgroundColor: colors.highlightedAccentBackground1 + isFirst: isFirst ) ) ) - .frame(maxWidth: width) .accessibilityIdentifier("GiphyAttachmentView") } @@ -124,45 +126,64 @@ struct LazyGiphyView: View { let width: CGFloat var body: some View { - LazyImage(imageURL: source) { state in - if let imageContainer = state.imageContainer { - if imageContainer.type == .gif { - AnimatedGifView(imageContainer: imageContainer) + StreamAsyncImage( + url: source, + resize: ImageResize(CGSize(width: width, height: width)) + ) { phase in + switch phase { + case .success(let result): + if result.isAnimated, let gifData = result.animatedImageData { + AnimatedGifView(gifData: gifData) } else { - state.image + Image(uiImage: result.image) + .resizable() + .scaledToFill() } - } else if state.error != nil { + case .error: Color(.secondarySystemBackground) - } else { + case .loading, .empty: ZStack { Color(.secondarySystemBackground) ProgressView() } } } - .onDisappear(.cancel) - .processors([ImageProcessors.Resize(width: width)]) - .priority(.high) - .aspectRatio(contentMode: .fit) - .frame(width: width) - .frame(maxHeight: 250) + .frame(width: width, height: width) .clipped() } } /// Recommended implementation by SwiftyGif for rendering gifs in SwiftUI /// Nuke dropped gif support and therefore it needs to be implemented separately. +/// The UIImageView is wrapped in a container with auto-layout constraints +/// to ensure contentMode scaling works correctly with SwiftyGif's +/// CADisplayLink-driven frame updates. private struct AnimatedGifView: UIViewRepresentable { - let imageContainer: ImageContainer + let gifData: Data + + func makeUIView(context: Context) -> UIView { + let container = UIView() + container.clipsToBounds = true - func makeUIView(context: Context) -> UIImageView { let imageView = UIImageView() - imageView.contentMode = .scaleAspectFit - if let gifData = imageContainer.data, let image = try? UIImage(gifData: gifData) { + imageView.contentMode = .scaleAspectFill + imageView.clipsToBounds = true + imageView.translatesAutoresizingMaskIntoConstraints = false + container.addSubview(imageView) + + NSLayoutConstraint.activate([ + imageView.leadingAnchor.constraint(equalTo: container.leadingAnchor), + imageView.trailingAnchor.constraint(equalTo: container.trailingAnchor), + imageView.topAnchor.constraint(equalTo: container.topAnchor), + imageView.bottomAnchor.constraint(equalTo: container.bottomAnchor) + ]) + + if let image = try? UIImage(gifData: gifData) { imageView.setGifImage(image) } - return imageView + + return container } - func updateUIView(_ uiView: UIImageView, context: Context) {} + func updateUIView(_ uiView: UIView, context: Context) {} } diff --git a/Sources/StreamChatSwiftUI/ChatMessageList/JumpToUnreadButton.swift b/Sources/StreamChatSwiftUI/ChatMessageList/JumpToUnreadButton.swift index 9e35f485c..0bd186206 100644 --- a/Sources/StreamChatSwiftUI/ChatMessageList/JumpToUnreadButton.swift +++ b/Sources/StreamChatSwiftUI/ChatMessageList/JumpToUnreadButton.swift @@ -5,31 +5,87 @@ import StreamChat import SwiftUI +/// A view modifier that overlays the jump-to-unread button on top of the message list. +public struct JumpToUnreadButtonOverlayModifier: ViewModifier { + @Injected(\.tokens) var tokens + + var isShown: Bool + var unreadCount: Int + var onJumpToMessage: () -> Void + var onClose: () -> Void + + public func body(content: Content) -> some View { + content.overlay( + VStack { + if isShown { + JumpToUnreadButton( + unreadCount: unreadCount, + onTap: onJumpToMessage, + onClose: onClose + ) + .padding(.top, tokens.spacingXs) + .transition( + .modifier( + active: ButtonOverlayTransitionModifier(opacity: 0, offset: -10), + identity: ButtonOverlayTransitionModifier(opacity: 1, offset: 0) + ) + ) + } + + Spacer() + } + .animation(.easeInOut(duration: 0.2), value: isShown) + ) + } +} + struct JumpToUnreadButton: View { @Injected(\.colors) var colors - + @Injected(\.tokens) var tokens + @Injected(\.fonts) var fonts + var unreadCount: Int var onTap: () -> Void var onClose: () -> Void - + var body: some View { - HStack { - Button { - onTap() - } label: { - Text(L10n.Message.Unread.count(unreadCount)) - .font(.caption) + HStack(spacing: tokens.spacingXxs) { + Button(action: onTap) { + HStack(spacing: tokens.spacingXs) { + Image(systemName: "arrow.up") + .frame(width: tokens.iconSizeSm, height: tokens.iconSizeSm) + Text(L10n.Message.Unread.count(unreadCount)) + .padding(.vertical, tokens.spacingXxxs) + } + .font(fonts.subheadline.weight(.semibold)) + .padding(.horizontal, tokens.spacingXs) + .padding(.vertical, tokens.spacingXxs) } - Button { - onClose() - } label: { + + Divider() + + Button(action: onClose) { Image(systemName: "xmark") - .font(.caption.weight(.bold)) + .font(fonts.subheadline.weight(.semibold)) + .frame(width: tokens.iconSizeSm, height: tokens.iconSizeSm) } + .frame(width: tokens.buttonVisualHeightSm, height: tokens.buttonVisualHeightSm) + .accessibilityLabel(Text("Dismiss")) } - .padding(.all, 10) - .foregroundColor(.white) - .background(Color(colors.textLowEmphasis)) - .cornerRadius(16) + .padding(tokens.spacingXxs) + .fixedSize() + .foregroundColor(Color(colors.buttonSecondaryText)) + .background(Color(colors.backgroundCoreElevation1)) + .clipShape(Capsule()) + .overlay( + Capsule() + .stroke(Color(colors.borderCoreDefault), lineWidth: 1) + ) + .shadow( + color: Color(tokens.lightElevation3.color), + radius: tokens.lightElevation3.blur / 2, + x: tokens.lightElevation3.x, + y: tokens.lightElevation3.y + ) } } diff --git a/Sources/StreamChatSwiftUI/ChatMessageList/LazyLoadingImage.swift b/Sources/StreamChatSwiftUI/ChatMessageList/LazyLoadingImage.swift index 7f8cbd0ef..e7676f1a4 100644 --- a/Sources/StreamChatSwiftUI/ChatMessageList/LazyLoadingImage.swift +++ b/Sources/StreamChatSwiftUI/ChatMessageList/LazyLoadingImage.swift @@ -64,18 +64,27 @@ struct LazyLoadingImage: View { if image != nil { return } + loadThumbnail() + } + .onChange(of: source) { newSource in + image = nil + error = nil + loadThumbnail(from: newSource) + } + } - source.generateThumbnail( - resize: resize, - preferredSize: CGSize(width: width, height: height) - ) { result in - switch result { - case let .success(image): - self.image = image - onImageLoaded(image) - case let .failure(error): - self.error = error - } + private func loadThumbnail(from attachment: MediaAttachment? = nil) { + let attachment = attachment ?? source + attachment.generateThumbnail( + resize: resize, + preferredSize: CGSize(width: width, height: height) + ) { result in + switch result { + case let .success(image): + self.image = image + onImageLoaded(image) + case let .failure(error): + self.error = error } } } diff --git a/Sources/StreamChatSwiftUI/ChatMessageList/LinkAttachmentView.swift b/Sources/StreamChatSwiftUI/ChatMessageList/LinkAttachmentView.swift index 94fe8700e..2b5e44759 100644 --- a/Sources/StreamChatSwiftUI/ChatMessageList/LinkAttachmentView.swift +++ b/Sources/StreamChatSwiftUI/ChatMessageList/LinkAttachmentView.swift @@ -3,6 +3,7 @@ // import StreamChat +import StreamChatCommonUI import SwiftUI /// Container for presenting link attachments. @@ -41,8 +42,10 @@ public struct LinkAttachmentContainer: View { linkAttachment: message.linkAttachments[0], width: width, isFirst: isFirst, + isRightAligned: message.isRightAligned, onImageTap: onImageTap ) + .frame(width: width, alignment: message.isRightAligned ? .trailing : .leading) .background(MessageAttachmentsBubbleConfiguration.attachmentBackgroundColor(for: message)) .roundWithBorder() .accessibilityIdentifier("LinkAttachmentContainer") @@ -59,17 +62,20 @@ public struct LinkAttachmentView: View { var linkAttachment: ChatMessageLinkAttachment var width: CGFloat var isFirst: Bool + let isRightAligned: Bool var onImageTap: ((ChatMessageLinkAttachment) -> Void)? public init( linkAttachment: ChatMessageLinkAttachment, width: CGFloat, isFirst: Bool, + isRightAligned: Bool, onImageTap: ((ChatMessageLinkAttachment) -> Void)? = nil ) { self.linkAttachment = linkAttachment self.width = width self.isFirst = isFirst + self.isRightAligned = isRightAligned self.onImageTap = onImageTap } @@ -77,27 +83,27 @@ public struct LinkAttachmentView: View { VStack(alignment: .leading, spacing: 0) { if !imageHidden { ZStack { - LazyImage(imageURL: linkAttachment.previewURL ?? linkAttachment.originalURL) { state in - if let image = state.image { + StreamAsyncImage( + url: linkAttachment.previewURL ?? linkAttachment.originalURL, + resize: ImageResize(CGSize(width: width, height: 0)) + ) { phase in + if let image = phase.image { image .resizable() .aspectRatio(contentMode: .fill) } } - .onDisappear(.cancel) - .processors([ImageProcessors.Resize(width: width)]) - .priority(.high) .frame(height: width / 2) .clipped() if !authorHidden { BottomLeftView { Text(linkAttachment.author ?? "") - .foregroundColor(colors.messageLinkAttachmentAuthorColor) + .foregroundColor(Color(colors.textPrimary)) .font(fonts.bodyBold) .standardPadding() .bubble( - with: Color(colors.highlightedAccentBackground1), + with: Color(colors.backgroundCoreElevation1), corners: [.topRight], borderColor: .clear ) @@ -110,14 +116,14 @@ public struct LinkAttachmentView: View { if let title = linkAttachment.title { Text(title) .font(fonts.footnoteBold) - .foregroundColor(colors.messageLinkAttachmentTitleColor) + .foregroundColor(Color(isRightAligned ? colors.chatTextOutgoing : colors.chatTextIncoming)) .lineLimit(1) } if let description = linkAttachment.text { Text(description) .font(fonts.footnote) - .foregroundColor(colors.messageLinkAttachmentTextColor) + .foregroundColor(Color(isRightAligned ? colors.chatTextOutgoing : colors.chatTextIncoming)) .lineLimit(3) } } diff --git a/Sources/StreamChatSwiftUI/ChatMessageList/MediaAttachment.swift b/Sources/StreamChatSwiftUI/ChatMessageList/MediaAttachment.swift index a540e02c7..70d2852fe 100644 --- a/Sources/StreamChatSwiftUI/ChatMessageList/MediaAttachment.swift +++ b/Sources/StreamChatSwiftUI/ChatMessageList/MediaAttachment.swift @@ -3,6 +3,7 @@ // import StreamChat +import StreamChatCommonUI import SwiftUI public final class MediaAttachment: Identifiable, Equatable, Sendable { @@ -11,19 +12,22 @@ public final class MediaAttachment: Identifiable, Equatable, Sendable { public let uploadingState: AttachmentUploadingState? public let originalWidth: Double? public let originalHeight: Double? + let videoAttachment: ChatMessageVideoAttachment? public init( url: URL, type: MediaAttachmentType, uploadingState: AttachmentUploadingState? = nil, originalWidth: Double? = nil, - originalHeight: Double? = nil + originalHeight: Double? = nil, + videoAttachment: ChatMessageVideoAttachment? = nil ) { self.url = url self.type = type self.uploadingState = uploadingState self.originalWidth = originalWidth self.originalHeight = originalHeight + self.videoAttachment = videoAttachment } public var id: String { @@ -36,19 +40,27 @@ public final class MediaAttachment: Identifiable, Equatable, Sendable { completion: @escaping @MainActor (Result) -> Void ) { let utils = InjectedValues[\.utils] + let cdnRequester = utils.cdnRequester if type == .image { - utils.imageLoader.loadImage( + let imageResize: ImageResize? = resize ? ImageResize(preferredSize) : nil + utils.mediaLoader.loadImage( url: url, - imageCDN: utils.imageCDN, - resize: resize, - preferredSize: preferredSize, - completion: completion - ) + options: ImageLoadOptions(resize: imageResize, cdnRequester: cdnRequester) + ) { result in + completion(result.map(\.image)) + } } else if type == .video { - utils.videoPreviewLoader.loadPreviewForVideo( - at: url, - completion: completion - ) + guard let videoAttachment else { + log.warning("Missing videoAttachment for .video MediaAttachment, skipping thumbnail generation") + completion(.failure(ClientError("Missing videoAttachment for .video MediaAttachment"))) + return + } + utils.mediaLoader.loadVideoPreview( + with: videoAttachment, + options: VideoLoadOptions(cdnRequester: cdnRequester) + ) { result in + completion(result.map(\.image)) + } } } @@ -58,6 +70,7 @@ public final class MediaAttachment: Identifiable, Equatable, Sendable { && lhs.uploadingState == rhs.uploadingState && lhs.originalWidth == rhs.originalWidth && lhs.originalHeight == rhs.originalHeight + && lhs.videoAttachment?.id == rhs.videoAttachment?.id } } @@ -90,7 +103,8 @@ extension MediaAttachment { type: .video, uploadingState: attachment.uploadingState, originalWidth: attachment.originalWidth, - originalHeight: attachment.originalHeight + originalHeight: attachment.originalHeight, + videoAttachment: attachment ) } diff --git a/Sources/StreamChatSwiftUI/ChatMessageList/MessageAnnotationView.swift b/Sources/StreamChatSwiftUI/ChatMessageList/MessageAnnotationView.swift index 95d948a94..52027446b 100644 --- a/Sources/StreamChatSwiftUI/ChatMessageList/MessageAnnotationView.swift +++ b/Sources/StreamChatSwiftUI/ChatMessageList/MessageAnnotationView.swift @@ -45,7 +45,9 @@ public struct MessageAnnotationView: View { HStack(spacing: tokens.spacingXxs) { Image(uiImage: icon) .renderingMode(.template) + .scaledToFit() .frame(width: tokens.iconSizeSm, height: tokens.iconSizeSm) + .padding(.horizontal, tokens.spacingXxxs) .accessibilityHidden(true) if let title { Text(title) @@ -68,7 +70,7 @@ public struct MessageAnnotationView: View { Button(action: buttonAction) { Text(buttonTitle) .font(fonts.footnote) - .foregroundColor(Color(colors.accentPrimary)) + .foregroundColor(usesInvertedStyle ? resolvedTextColor : Color(colors.accentPrimary)) } } } diff --git a/Sources/StreamChatSwiftUI/ChatMessageList/MessageAttachmentsView.swift b/Sources/StreamChatSwiftUI/ChatMessageList/MessageAttachmentsView.swift index 1d4d0f616..091f9b422 100644 --- a/Sources/StreamChatSwiftUI/ChatMessageList/MessageAttachmentsView.swift +++ b/Sources/StreamChatSwiftUI/ChatMessageList/MessageAttachmentsView.swift @@ -17,6 +17,7 @@ public struct MessageAttachmentsView: View { let message: ChatMessage let width: CGFloat let isFirst: Bool + let translationLanguage: TranslationLanguage? @Binding var scrolledId: String? public init( @@ -24,12 +25,14 @@ public struct MessageAttachmentsView: View { message: ChatMessage, width: CGFloat, isFirst: Bool, - scrolledId: Binding + scrolledId: Binding, + translationLanguage: TranslationLanguage? = nil ) { self.factory = factory self.message = message self.width = width self.isFirst = isFirst + self.translationLanguage = translationLanguage self._scrolledId = scrolledId } @@ -112,7 +115,11 @@ public struct MessageAttachmentsView: View { // Text caption if !message.text.isEmpty { factory.makeAttachmentTextView( - options: AttachmentTextViewOptions(message: message) + options: AttachmentTextViewOptions( + message: message, + availableWidth: width, + translationLanguage: translationLanguage + ) ) } } @@ -160,16 +167,94 @@ enum MessageAttachmentsBubbleConfiguration { @Injected(\.colors) var colors return Color(message.isSentByCurrentUser ? colors.chatBackgroundAttachmentOutgoing : colors.chatBackgroundAttachmentIncoming) } + + /// Applies the attachment container styling: background color, border + /// stroke, and clip shape with corners that respect the message bubble + /// shape when the attachment is the only content. + /// + /// The caller provides `isSingleWithoutCaption` because "single" + /// differs per attachment type (file count vs. voice recording count). + struct AttachmentContainerModifier: ViewModifier { + @Injected(\.colors) private var colors + @Injected(\.tokens) private var tokens + @Injected(\.utils) private var utils + @Environment(\.layoutDirection) private var layoutDirection + + let message: ChatMessage + let isFirst: Bool + let isSingleWithoutCaption: Bool + + func body(content: Content) -> some View { + let corners: UIRectCorner = isFirst && isSingleWithoutCaption + ? message.bubbleCorners( + isFirst: isFirst, + forceLeftToRight: utils.messageListConfig.messageListAlignment == .leftAligned, + layoutDirection: layoutDirection + ) + : .allCorners + content + .background(MessageAttachmentsBubbleConfiguration.attachmentBackgroundColor(for: message)) + .overlay( + BubbleBackgroundShape( + cornerRadius: tokens.messageBubbleRadiusAttachment, + corners: corners + ) + .stroke(Color(colors.borderCoreDefault), lineWidth: 1) + ) + .clipShape( + BubbleBackgroundShape( + cornerRadius: tokens.messageBubbleRadiusAttachment, + corners: corners + ) + ) + } + } + + /// Applies the voice recording attachment container styling (padding, + /// background, and rounded border). When the voice recording is a + /// quoted reply without a text caption, the background and border are + /// omitted so the player renders flat inside the message bubble. + struct VoiceRecordingContainerModifier: ViewModifier { + @Injected(\.tokens) private var tokens + + let message: ChatMessage + let isFirst: Bool + + @ViewBuilder + func body(content: Content) -> some View { + if isContainerShown { + content + .padding(.all, tokens.spacingXs) + .modifier(AttachmentContainerModifier( + message: message, + isFirst: isFirst, + isSingleWithoutCaption: message.text.isEmpty + && message.voiceRecordingAttachments.count == 1 + )) + } else { + content + } + } + + private var isContainerShown: Bool { + !(message.quotedMessage != nil && message.text.isEmpty) + } + } } -private extension ChatMessage { +extension ChatMessage { var hasSingleFileOrVoiceAttachmentWithoutCaption: Bool { - guard text.isEmpty else { return false } + guard text.isEmpty, quotedMessage == nil else { return false } return attachmentCounts.count == 1 && (attachmentCounts[.file] == 1 || attachmentCounts[.voiceRecording] == 1) } var hasSingleMediaAttachmentWithoutCaption: Bool { - guard text.isEmpty else { return false } + guard text.isEmpty, quotedMessage == nil else { return false } + return attachmentCounts.count == 1 && (attachmentCounts[.image] == 1 || attachmentCounts[.video] == 1) + } + + var hasSingleMediaAttachmentWithCaption: Bool { + guard !text.isEmpty, quotedMessage == nil else { return false } return attachmentCounts.count == 1 && (attachmentCounts[.image] == 1 || attachmentCounts[.video] == 1) } } diff --git a/Sources/StreamChatSwiftUI/ChatMessageList/MessageBubble.swift b/Sources/StreamChatSwiftUI/ChatMessageList/MessageBubble.swift index f46ebd6b2..f75e62506 100644 --- a/Sources/StreamChatSwiftUI/ChatMessageList/MessageBubble.swift +++ b/Sources/StreamChatSwiftUI/ChatMessageList/MessageBubble.swift @@ -3,7 +3,6 @@ // import StreamChat -import StreamChatCommonUI import SwiftUI /// Contains info needed for a modifier to be applied to the message view. @@ -112,7 +111,7 @@ public struct BubbleModifier: ViewModifier { cornerRadius: cornerRadius, corners: corners ) .stroke( - borderColor ?? Color(colors.innerBorder), + borderColor ?? Color(colors.borderCoreDefault), lineWidth: 1.0 ) ) @@ -275,7 +274,7 @@ extension ChatMessage { } } - func bubbleBorder(colors: Appearance.ColorPalette) -> Color { + @MainActor func bubbleBorder(colors: Appearance.ColorPalette) -> Color { isSentByCurrentUser ? colors.chatBorderOutgoing.toColor : colors.chatBorderIncoming.toColor } @@ -288,14 +287,6 @@ extension ChatMessage { if let injectedBackgroundColor { return [Color(injectedBackgroundColor)] } - if isSentByCurrentUser { - if type == .ephemeral { - return colors.messageCurrentUserEmphemeralBackground.map { Color($0) } - } else { - return [colors.chatBackgroundOutgoing.toColor] - } - } else { - return [colors.chatBackgroundIncoming.toColor] - } + return [Color(isSentByCurrentUser ? colors.chatBackgroundOutgoing : colors.chatBackgroundIncoming)] } } diff --git a/Sources/StreamChatSwiftUI/ChatMessageList/MessageContainerView.swift b/Sources/StreamChatSwiftUI/ChatMessageList/MessageContainerView.swift index 87af78e2f..cc9369bb3 100644 --- a/Sources/StreamChatSwiftUI/ChatMessageList/MessageContainerView.swift +++ b/Sources/StreamChatSwiftUI/ChatMessageList/MessageContainerView.swift @@ -81,7 +81,7 @@ struct MessageContainerView: View { ) } - if showsAllInfo && !message.isDeleted { + if showsAllInfo { deliveryStatusView } } @@ -92,10 +92,10 @@ struct MessageContainerView: View { } } .frame(maxWidth: .infinity, alignment: messageViewModel.isRightAligned ? .trailing : .leading) - .padding(.top, messageViewModel.topReactionsShown && !messageViewModel.isPinned ? messageListConfig.messageDisplayOptions.reactionsTopPadding(message) : 0) + .padding(.top, messageViewModel.topReactionsShown && !messageViewModel.annotationsShown ? messageListConfig.messageDisplayOptions.reactionsTopPadding(message) : 0) .padding(.horizontal, messageListConfig.messagePaddings.horizontal) .padding(.bottom, showsAllInfo || messageViewModel.annotationsShown ? paddingValue : groupMessageInterItemSpacing) - .padding(.top, isLast ? paddingValue : 0) + .padding(.top, isLast ? paddingValue : (messageViewModel.annotationsShown ? groupMessageInterItemSpacing : 0)) } // MARK: - Sub-views @@ -110,7 +110,8 @@ struct MessageContainerView: View { message: message, contentWidth: contentWidth, isFirst: showsAllInfo, - scrolledId: $scrolledId + scrolledId: $scrolledId, + translationLanguage: messageViewModel.translationLanguage ) } } else { @@ -119,7 +120,8 @@ struct MessageContainerView: View { message: message, contentWidth: contentWidth, isFirst: showsAllInfo, - scrolledId: $scrolledId + scrolledId: $scrolledId, + translationLanguage: messageViewModel.translationLanguage ) } } diff --git a/Sources/StreamChatSwiftUI/ChatMessageList/MessageItemView.swift b/Sources/StreamChatSwiftUI/ChatMessageList/MessageItemView.swift index 0cb2f60a9..469930fe7 100644 --- a/Sources/StreamChatSwiftUI/ChatMessageList/MessageItemView.swift +++ b/Sources/StreamChatSwiftUI/ChatMessageList/MessageItemView.swift @@ -107,7 +107,7 @@ public struct MessageItemView: View { } ) .contentShape(Rectangle()) - .allowsHitTesting(!shownAsPreview) + .allowsHitTesting(!shownAsPreview || (messageViewModel.usesScrollView)) .onTapGesture(count: 2) { if messageViewModel.isDoubleTapOverlayEnabled { handleGestureForMessage(showsMessageActions: true) @@ -144,8 +144,6 @@ public struct MessageItemView: View { ) .accessibilityElement(children: .contain) .accessibilityIdentifier("MessageItemView") - // TODO: Refactor so LinkDetectionTextView does not depend directly on the view model through @Environment. - .environment(\.messageViewModel, messageViewModel) .onChange(of: message) { message in messageViewModel.message = message } .onChange(of: channel) { channel in messageViewModel.channel = channel } } @@ -157,9 +155,11 @@ public struct MessageItemView: View { return fixedContentWidth } let minimumWidth: CGFloat = 240 - let padding = messageListConfig.messagePaddings.horizontal - let avatarWithSpacing = AvatarSize.medium + tokens.spacingXs - let available = (width ?? 0) - spacerWidth - padding - avatarWithSpacing + var padding = messageListConfig.messagePaddings.horizontal + if utils.messageListConfig.messageDisplayOptions.showAvatars(for: channel, incoming: !messageViewModel.isRightAligned) { + padding += AvatarSize.medium + tokens.spacingXs + } + let available = (width ?? 0) - spacerWidth - padding return max(minimumWidth, available) } @@ -212,6 +212,8 @@ struct SwipeToReplyModifier: ViewModifier { let isSwipeToQuoteReplyPossible: Bool @Binding var quotedMessage: ChatMessage? + @Environment(\.layoutDirection) private var layoutDirection + @Injected(\.images) private var images @Injected(\.utils) private var utils @Injected(\.colors) private var colors @@ -239,11 +241,15 @@ struct SwipeToReplyModifier: ViewModifier { private let feedbackGenerator = UIImpactFeedbackGenerator(style: .medium) + private var isRTL: Bool { + layoutDirection == .rightToLeft + } + func body(content: Content) -> some View { content .coordinateSpace(name: "swipeToReply") .offset(x: min(offsetX, maximumHorizontalSwipeDisplacement)) - .simultaneousGesture( + .gesture( DragGesture( minimumDistance: minimumSwipeDistance, coordinateSpace: .named("swipeToReply") @@ -290,7 +296,7 @@ struct SwipeToReplyModifier: ViewModifier { .padding(.all, tokens.spacingXs) .background(colors.buttonSecondaryBackground.toColor) .clipShape(Circle()) - .offset(x: min(offsetX / 2, 50)) + .offset(x: min(offsetX / 2, 50) + (message.isRightAligned ? 30 : 0)) Spacer() } : nil ) @@ -305,7 +311,7 @@ struct SwipeToReplyModifier: ViewModifier { } private func dragChanged(to value: CGFloat) { - let horizontalTranslation = value + let horizontalTranslation = isRTL ? -value : value if horizontalTranslation < 0 { return @@ -352,12 +358,15 @@ struct SendFailureIndicator: View { @Injected(\.images) private var images var body: some View { - BottomRightView { + TopRightView { Image(uiImage: images.messageListErrorIndicator) .customizable() - .frame(width: 16, height: 16) - .foregroundColor(Color(colors.alert)) - .offset(y: 4) + .frame(width: 20, height: 20) + .foregroundColor(Color(colors.badgeBackgroundError)) + .padding(2) + .background(Color(colors.badgeBorder)) + .clipShape(Circle()) + .offset(x: 14, y: 6) } .accessibilityElement(children: .contain) .accessibilityIdentifier("SendFailureIndicator") diff --git a/Sources/StreamChatSwiftUI/ChatMessageList/MessageListConfig.swift b/Sources/StreamChatSwiftUI/ChatMessageList/MessageListConfig.swift index 0d4102afa..580c2c55d 100644 --- a/Sources/StreamChatSwiftUI/ChatMessageList/MessageListConfig.swift +++ b/Sources/StreamChatSwiftUI/ChatMessageList/MessageListConfig.swift @@ -14,7 +14,7 @@ import SwiftUI groupMessages: Bool = true, messageDisplayOptions: MessageDisplayOptions = MessageDisplayOptions(), messagePaddings: MessagePaddings = MessagePaddings(), - dateIndicatorPlacement: DateIndicatorPlacement = .overlay, + dateIndicatorPlacement: DateIndicatorPlacement = .messageList, pageSize: Int = 25, messagePopoverEnabled: Bool = true, doubleTapOverlayEnabled: Bool = false, @@ -32,14 +32,14 @@ import SwiftUI uniqueReactionsEnabled: Bool = false, localLinkDetectionEnabled: Bool = true, isMessageEditedLabelEnabled: Bool = true, - markdownSupportEnabled: Bool = true, - userBlockingEnabled: Bool = false, + markdownSupportEnabled: Bool = false, + userBlockingEnabled: Bool = true, bouncedMessagesAlertActionsEnabled: Bool = true, skipEditedMessageLabel: @escaping (ChatMessage) -> Bool = { _ in false }, - draftMessagesEnabled: Bool = false, - downloadFileAttachmentsEnabled: Bool = false, + draftMessagesEnabled: Bool = true, hidesCommandsOverlayOnMessageListTap: Bool = true, hidesAttachmentsPickersOnMessageListTap: Bool = true, + attachmentPreviewWidth: CGFloat = 256, navigationBarDisplayMode: NavigationBarItem.TitleDisplayMode = .inline, supportedMessageActions: @escaping @MainActor (SupportedMessageActionsOptions) -> [MessageAction] = MessageAction.defaultActions(for:) ) { @@ -71,9 +71,9 @@ import SwiftUI self.bouncedMessagesAlertActionsEnabled = bouncedMessagesAlertActionsEnabled self.skipEditedMessageLabel = skipEditedMessageLabel self.draftMessagesEnabled = draftMessagesEnabled - self.downloadFileAttachmentsEnabled = downloadFileAttachmentsEnabled self.hidesCommandsOverlayOnMessageListTap = hidesCommandsOverlayOnMessageListTap self.hidesAttachmentsPickersOnMessageListTap = hidesAttachmentsPickersOnMessageListTap + self.attachmentPreviewWidth = attachmentPreviewWidth self.navigationBarDisplayMode = navigationBarDisplayMode self.supportedMessageActions = supportedMessageActions } @@ -113,6 +113,9 @@ import SwiftUI /// It is enabled by default. public let hidesAttachmentsPickersOnMessageListTap: Bool + /// The width used for attachment previews in the message list. + public let attachmentPreviewWidth: CGFloat + /// 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. @@ -125,9 +128,6 @@ import SwiftUI /// If enabled, the SDK will save the message content as a draft when the user navigates away from the composer. public let draftMessagesEnabled: Bool - /// A boolean value that determines if download action is shown for file attachments. - public let downloadFileAttachmentsEnabled: Bool - /// Highlights the message background when jumping to a message. /// /// By default it is enabled and it uses the color from `ColorPalette.messageCellHighlightBackground`. @@ -209,7 +209,7 @@ public final class MessageDisplayOptions { shouldAnimateReactions: Bool = true, reactionsPlacement: ReactionsPlacement = .top, reactionsStyle: ReactionsStyle = .segmented, - showOriginalTranslatedButton: Bool = false, + showOriginalTranslatedButton: Bool = true, messageLinkDisplayResolver: @escaping @MainActor (ChatMessage) -> [NSAttributedString.Key: Any] = MessageDisplayOptions .defaultLinkDisplay, spacerWidth: @escaping @MainActor (CGFloat) -> CGFloat = MessageDisplayOptions.defaultSpacerWidth, @@ -280,7 +280,7 @@ public final class MessageDisplayOptions { public static var defaultSpacerWidth: @MainActor (CGFloat) -> (CGFloat) { { availableWidth in if isIPad && availableWidth > 500 { - return 2 * availableWidth / 3 + return (availableWidth * 0.4).rounded() } else { @Injected(\.utils) var utils @Injected(\.tokens) var tokens @@ -293,7 +293,7 @@ public final class MessageDisplayOptions { } public static var defaultReactionsTopPadding: (ChatMessage) -> CGFloat { - { _ in 20 } + { _ in 19 } } } diff --git a/Sources/StreamChatSwiftUI/ChatMessageList/MessageListHelperViews.swift b/Sources/StreamChatSwiftUI/ChatMessageList/MessageListHelperViews.swift index 39797fa6e..391de236c 100644 --- a/Sources/StreamChatSwiftUI/ChatMessageList/MessageListHelperViews.swift +++ b/Sources/StreamChatSwiftUI/ChatMessageList/MessageListHelperViews.swift @@ -95,7 +95,7 @@ struct MessageDateView: View { Text(text) .font(fonts.footnote) .foregroundColor(usesInvertedStyle ? colors.textOnAccent.toColor : colors.chatTextTimestamp.toColor) - .animation(nil) + .animation(nil, value: text) .accessibilityLabel(Text(accessibilityLabel)) .accessibilityIdentifier("MessageDateView") } @@ -180,9 +180,6 @@ extension View { public func textColor(for message: ChatMessage) -> Color { @Injected(\.colors) var colors - if message.isDeleted { - return Color(colors.textLowEmphasis) - } if message.isSentByCurrentUser { return Color(colors.chatTextOutgoing) } else { diff --git a/Sources/StreamChatSwiftUI/ChatMessageList/MessageListView.swift b/Sources/StreamChatSwiftUI/ChatMessageList/MessageListView.swift index 62869db4d..309048c8f 100644 --- a/Sources/StreamChatSwiftUI/ChatMessageList/MessageListView.swift +++ b/Sources/StreamChatSwiftUI/ChatMessageList/MessageListView.swift @@ -192,6 +192,7 @@ public struct MessageListView: View, KeyboardReadable { messageIsFirstUnread && !isMessageThread let showsLastInGroupInfo = showsLastInGroupInfo(for: message, channel: channel) + let showThreadRepliesSeparator = isThreadRepliesSeparatorShown(for: message) factory.makeMessageItemView( options: MessageItemViewOptions( channel: channel, @@ -205,7 +206,6 @@ public struct MessageListView: View, KeyboardReadable { isLast: !showsLastInGroupInfo && message == messages.last ) ) - .environment(\.channelTranslationLanguage, channel.membership?.language) .onAppear { if index == nil { index = messageListDateUtils.index(for: message, in: messages) @@ -220,15 +220,17 @@ public struct MessageListView: View, KeyboardReadable { messageDate != nil ? offsetForDateIndicator( showsLastInGroupInfo: showsLastInGroupInfo, - showUnreadSeparator: showUnreadSeparator + showUnreadSeparator: showUnreadSeparator, + showThreadRepliesSeparator: showThreadRepliesSeparator ) : additionalTopPadding( showsLastInGroupInfo: showsLastInGroupInfo, - showUnreadSeparator: showUnreadSeparator + showUnreadSeparator: showUnreadSeparator, + showThreadRepliesSeparator: showThreadRepliesSeparator ) ) .overlay( - (messageDate != nil || showsLastInGroupInfo || showUnreadSeparator) ? + (messageDate != nil || showsLastInGroupInfo || showUnreadSeparator || showThreadRepliesSeparator) ? VStack(spacing: 0) { messageDate != nil ? factory.makeMessageListDateIndicator(options: MessageListDateIndicatorViewOptions(date: messageDate!)) @@ -236,8 +238,8 @@ public struct MessageListView: View, KeyboardReadable { : nil showUnreadSeparator ? - factory.makeNewMessagesIndicatorView( - options: NewMessagesIndicatorViewOptions( + factory.makeNewMessagesDividerView( + options: NewMessagesDividerViewOptions( newMessagesStartId: $firstUnreadMessageId, count: newMessagesCount(for: index, message: message) ) @@ -250,6 +252,15 @@ public struct MessageListView: View, KeyboardReadable { } : nil + showThreadRepliesSeparator ? + factory.makeThreadRepliesDividerView( + options: ThreadRepliesDividerViewOptions( + replyCount: messages.last?.replyCount ?? (messages.count - 1) + ) + ) + .frame(maxHeight: newMessagesSeparatorSize) + : nil + showsLastInGroupInfo ? factory.makeLastInGroupHeaderView(options: LastInGroupHeaderViewOptions(message: message)) .frame(maxHeight: lastInGroupHeaderSize) @@ -330,18 +341,16 @@ public struct MessageListView: View, KeyboardReadable { .frame(maxWidth: .infinity) .clipped() .onChange(of: scrolledId) { scrolledId in - DispatchQueue.main.async { - if let scrolledId { - let shouldJump = onJumpToMessage?(scrolledId) ?? false - if !shouldJump { - return - } - withAnimation { - if messages.first?.id == scrolledId { - scrollView.scrollTo(bottomId, anchor: .bottom) - } else { - scrollView.scrollTo(scrolledId, anchor: messageListConfig.scrollingAnchor) - } + if let scrolledId { + let shouldJump = onJumpToMessage?(scrolledId) ?? false + if !shouldJump { + return + } + withAnimation { + if messages.first?.id == scrolledId { + scrollView.scrollTo(bottomId, anchor: .bottom) + } else { + scrollView.scrollTo(scrolledId, anchor: messageListConfig.scrollingAnchor) } } } @@ -358,8 +367,8 @@ public struct MessageListView: View, KeyboardReadable { ) .transition( .modifier( - active: ScrollButtonTransitionModifier(opacity: 0, offset: 10), - identity: ScrollButtonTransitionModifier(opacity: 1, offset: 0) + active: ButtonOverlayTransitionModifier(opacity: 0, offset: 10), + identity: ButtonOverlayTransitionModifier(opacity: 1, offset: 0) ) ) .offset(y: -bottomInset) @@ -380,20 +389,22 @@ public struct MessageListView: View, KeyboardReadable { pendingKeyboardUpdate = nil } }) - .overlay( - (channel.unreadCount.messages > 0 && !unreadMessagesBannerShown && !isMessageThread && !unreadButtonDismissed) ? - factory.makeJumpToUnreadButton( - options: JumpToUnreadButtonOptions( - channel: channel, - onJumpToMessage: { - _ = onJumpToMessage?(firstUnreadMessageId ?? .unknownMessageId) - }, - onClose: { + .modifier( + factory.makeJumpToUnreadButtonOverlay( + options: JumpToUnreadButtonOptions( + isShown: shouldShowJumpToUnreadButton, + channel: channel, + onJumpToMessage: { + _ = onJumpToMessage?(firstUnreadMessageId ?? .unknownMessageId) + }, + onClose: { + withAnimation { chatClient.channelController(for: channel.cid).markRead() unreadButtonDismissed = true } - ) - ) : nil + } + ) + ) ) .modifier(factory.styles.makeMessageListContainerModifier(options: MessageListContainerModifierOptions())) .onDisappear { @@ -403,20 +414,49 @@ public struct MessageListView: View, KeyboardReadable { .accessibilityIdentifier("MessageListView") } - private func additionalTopPadding(showsLastInGroupInfo: Bool, showUnreadSeparator: Bool) -> CGFloat { + private var shouldShowJumpToUnreadButton: Bool { + channel.unreadCount.messages > 0 + && !unreadMessagesBannerShown + && !isMessageThread + && !unreadButtonDismissed + } + + private func additionalTopPadding( + showsLastInGroupInfo: Bool, + showUnreadSeparator: Bool, + showThreadRepliesSeparator: Bool = false + ) -> CGFloat { var padding = showsLastInGroupInfo ? lastInGroupHeaderSize : 0 if showUnreadSeparator { padding += newMessagesSeparatorSize } + if showThreadRepliesSeparator { + padding += newMessagesSeparatorSize + } return padding } - private func offsetForDateIndicator(showsLastInGroupInfo: Bool, showUnreadSeparator: Bool) -> CGFloat { + private func offsetForDateIndicator( + showsLastInGroupInfo: Bool, + showUnreadSeparator: Bool, + showThreadRepliesSeparator: Bool = false + ) -> CGFloat { var offset = messageListConfig.messageDisplayOptions.dateLabelSize - offset += additionalTopPadding(showsLastInGroupInfo: showsLastInGroupInfo, showUnreadSeparator: showUnreadSeparator) + offset += additionalTopPadding( + showsLastInGroupInfo: showsLastInGroupInfo, + showUnreadSeparator: showUnreadSeparator, + showThreadRepliesSeparator: showThreadRepliesSeparator + ) return offset } + private func isThreadRepliesSeparatorShown(for message: ChatMessage) -> Bool { + guard isMessageThread, messages.count > 1 else { return false } + let allRepliesLoaded = messages.count - 1 >= (messages.last?.replyCount ?? 0) + guard allRepliesLoaded else { return false } + return message.id == messages[messages.count - 2].id + } + private func newMessagesCount(for index: Int?, message: ChatMessage) -> Int { channel.unreadCount.messages } @@ -511,8 +551,42 @@ public enum ScrollDirection { case down } -public struct NewMessagesIndicator: View { +/// A full-width divider with centered text, a subtle background, and +/// hairline top/bottom borders. Used by ``NewMessagesDivider`` and +/// ``ThreadRepliesDivider``. +public struct MessageListDivider: View { @Injected(\.colors) var colors + @Injected(\.tokens) var tokens + @Injected(\.fonts) var fonts + + var title: String + + public init(title: String) { + self.title = title + } + + public var body: some View { + Text(title) + .font(fonts.footnote.weight(.semibold)) + .foregroundColor(Color(colors.chatTextSystem)) + .frame(maxWidth: .infinity) + .padding(.horizontal, tokens.spacingMd) + .padding(.vertical, tokens.spacingXs) + .background(Color(colors.backgroundCoreSurfaceSubtle)) + .overlay( + VStack(spacing: 0) { + Color(colors.borderCoreSubtle).frame(height: 1) + Spacer() + Color(colors.borderCoreSubtle).frame(height: 1) + } + ) + .accessibilityAddTraits(.isHeader) + } +} + +/// Divider shown between read and unread messages in the message list. +public struct NewMessagesDivider: View { + @Injected(\.tokens) var tokens @Binding var newMessagesStartId: String? var count: Int @@ -523,15 +597,21 @@ public struct NewMessagesIndicator: View { } public var body: some View { - HStack { - Text("\(L10n.MessageList.newMessages(count))") - .foregroundColor(Color(colors.textLowEmphasis)) - .font(.headline) - .padding(.all, 8) - } - .frame(maxWidth: .infinity) - .background(Color(colors.background8)) - .padding(.top, 4) + MessageListDivider(title: L10n.MessageList.newMessages(count)) + .padding(.vertical, tokens.spacingXs) + } +} + +/// Divider shown between the parent message and replies in a thread. +public struct ThreadRepliesDivider: View { + var replyCount: Int + + public init(replyCount: Int) { + self.replyCount = replyCount + } + + public var body: some View { + MessageListDivider(title: L10n.Message.Threads.count(replyCount)) } } @@ -564,7 +644,7 @@ public struct ScrollToBottomButton: View { } } -struct ScrollButtonTransitionModifier: ViewModifier { +struct ButtonOverlayTransitionModifier: ViewModifier { let opacity: Double let offset: CGFloat @@ -639,31 +719,3 @@ private class MessageRenderingUtil { return skipRendering } } - -private struct ChannelTranslationLanguageKey: EnvironmentKey { - static let defaultValue: TranslationLanguage? = nil -} - -private struct MessageViewModelKey: EnvironmentKey { - static let defaultValue: MessageViewModel? = nil -} - -extension EnvironmentValues { - var channelTranslationLanguage: TranslationLanguage? { - get { - self[ChannelTranslationLanguageKey.self] - } - set { - self[ChannelTranslationLanguageKey.self] = newValue - } - } - - var messageViewModel: MessageViewModel? { - get { - self[MessageViewModelKey.self] - } - set { - self[MessageViewModelKey.self] = newValue - } - } -} diff --git a/Sources/StreamChatSwiftUI/ChatMessageList/MessageMediaAttachmentContentView.swift b/Sources/StreamChatSwiftUI/ChatMessageList/MessageMediaAttachmentContentView.swift index 60e1f8654..87b82736a 100644 --- a/Sources/StreamChatSwiftUI/ChatMessageList/MessageMediaAttachmentContentView.swift +++ b/Sources/StreamChatSwiftUI/ChatMessageList/MessageMediaAttachmentContentView.swift @@ -24,8 +24,13 @@ public struct MessageMediaAttachmentContentView: View { let height: CGFloat /// The corner radius applied to the view. let cornerRadius: CGFloat + /// Which corners should be rounded. When `nil`, all corners are rounded + /// using a continuous `RoundedRectangle`. + let corners: UIRectCorner? /// Whether the message is sent by the current user (outgoing). let isOutgoing: Bool + /// Called when the user taps the retry badge on an upload-failed attachment. + let onUploadRetry: (() -> Void)? @State private var image: UIImage? @State private var error: Error? @@ -36,7 +41,9 @@ public struct MessageMediaAttachmentContentView: View { width: CGFloat, height: CGFloat, cornerRadius: CGFloat? = nil, - isOutgoing: Bool = false + corners: UIRectCorner? = nil, + isOutgoing: Bool = false, + onUploadRetry: (() -> Void)? = nil ) { @Injected(\.tokens) var tokens self.factory = factory @@ -44,7 +51,16 @@ public struct MessageMediaAttachmentContentView: View { self.width = width self.height = height self.cornerRadius = cornerRadius ?? tokens.messageBubbleRadiusAttachment + self.corners = corners self.isOutgoing = isOutgoing + self.onUploadRetry = onUploadRetry + } + + private var isUploading: Bool { + if case .uploading = source.uploadingState?.state { + return true + } + return false } public var body: some View { @@ -56,39 +72,93 @@ public struct MessageMediaAttachmentContentView: View { .frame(width: width, height: height) .clipped() } else if error != nil { - Color(.secondarySystemBackground) + placeholderBackground } else { placeholderGradient } - if image == nil && error == nil { - LoadingSpinnerView(size: LoadingSpinnerSize.large, bordered: true) + if image == nil && error == nil && !isUploading { + LoadingSpinnerView(size: LoadingSpinnerSize.medium) .allowsHitTesting(false) } - if source.type == .video && width > 64 && source.uploadingState == nil { + if error != nil && source.uploadingState == nil { + retryOverlay { loadThumbnail() } + } + + if let uploadingState = source.uploadingState { + uploadingOverlay(for: uploadingState) + } + + if source.type == .video && width > 64 && source.uploadingState == nil && image != nil && error == nil { VideoPlayIndicatorView(size: VideoPlayIndicatorSize.medium) .allowsHitTesting(false) } } .frame(width: width, height: height) - .clipShape(RoundedRectangle(cornerRadius: cornerRadius, style: .continuous)) + .clipShape( + BubbleBackgroundShape( + cornerRadius: cornerRadius, + corners: corners ?? [.topLeft, .topRight, .bottomLeft, .bottomRight] + ) + ) .onAppear { guard image == nil else { return } - source.generateThumbnail(resize: true, preferredSize: CGSize(width: width, height: height)) { result in - switch result { - case .success(let image): - self.image = image - case .failure(let failure): - self.error = failure - } - } + loadThumbnail() } .accessibilityIdentifier("MessageMediaAttachmentContentView") } - private var placeholderGradient: some View { + // MARK: - Private + + private func loadThumbnail() { + error = nil + source.generateThumbnail( + resize: true, + preferredSize: CGSize(width: width, height: height) + ) { result in + switch result { + case .success(let loaded): + self.image = loaded + case .failure(let failure): + self.error = failure + } + } + } + + @ViewBuilder + private func uploadingOverlay(for uploadingState: AttachmentUploadingState) -> some View { + switch uploadingState.state { + case let .uploading(progress): + Color(colors.backgroundCoreOverlayLight) + .allowsHitTesting(false) + LoadingSpinnerView( + size: LoadingSpinnerSize.medium, + progress: Double(progress) + ) + .allowsHitTesting(false) + case .uploadingFailed: + retryOverlay { onUploadRetry?() } + default: + EmptyView() + } + } + + private func retryOverlay(action: @escaping () -> Void) -> some View { + Button(action: action) { + ZStack { + Color(colors.backgroundCoreOverlayLight) + RetryBadgeView() + } + } + .buttonStyle(.plain) + } + + private var placeholderBackground: some View { Color(isOutgoing ? colors.chatBackgroundAttachmentOutgoing : colors.chatBackgroundAttachmentIncoming) - .shimmering() + } + + private var placeholderGradient: some View { + placeholderBackground.shimmering() } } diff --git a/Sources/StreamChatSwiftUI/ChatMessageList/MessageMediaAttachmentsContainerView.swift b/Sources/StreamChatSwiftUI/ChatMessageList/MessageMediaAttachmentsContainerView.swift index 6e1532bec..14a3f6fde 100644 --- a/Sources/StreamChatSwiftUI/ChatMessageList/MessageMediaAttachmentsContainerView.swift +++ b/Sources/StreamChatSwiftUI/ChatMessageList/MessageMediaAttachmentsContainerView.swift @@ -31,6 +31,17 @@ public enum MediaGalleryOrientation: Sendable { self = .square } } + + init(mediaAttachments: [MediaAttachment]) { + if let first = mediaAttachments.first { + self = MediaGalleryOrientation( + width: first.originalWidth, + height: first.originalHeight + ) + } else { + self = .landscape + } + } } /// A container view that displays media (image and video) attachments in a @@ -49,35 +60,46 @@ public enum MediaGalleryOrientation: Sendable { /// This view does **not** render message text or a bubble background. /// Tapping any cell opens the full-screen gallery. public struct MessageMediaAttachmentsContainerView: View { + @Injected(\.chatClient) private var chatClient @Injected(\.colors) private var colors @Injected(\.fonts) private var fonts @Injected(\.tokens) private var tokens + @Injected(\.utils) private var utils + @Environment(\.layoutDirection) private var layoutDirection let factory: Factory let message: ChatMessage let width: CGFloat + let isFirst: Bool @State private var galleryShown = false @State private var selectedIndex = 0 private var spacing: CGFloat { tokens.spacingXxxs } private var cornerRadius: CGFloat { tokens.messageBubbleRadiusAttachment } private let maxDisplayedItems = 4 + private let orientation: MediaGalleryOrientation + private let sources: [MediaAttachment] public init( factory: Factory, message: ChatMessage, - width: CGFloat + width: CGFloat, + isFirst: Bool = true ) { self.factory = factory self.message = message self.width = width + self.isFirst = isFirst + self.sources = MediaAttachment.galleryOrdered(from: message) + self.orientation = MediaGalleryOrientation(mediaAttachments: sources) } public var body: some View { galleryGrid - .fullScreenCover(isPresented: $galleryShown, onDismiss: { - selectedIndex = 0 - }) { + .onChange(of: selectedIndex) { _ in + galleryShown = true + } + .fullScreenCover(isPresented: $galleryShown) { factory.makeMediaViewer( options: MediaViewerOptions( mediaAttachments: sources, @@ -221,7 +243,7 @@ public struct MessageMediaAttachmentsContainerView: View { .clipShape(RoundedRectangle(cornerRadius: cornerRadius, style: .continuous)) .allowsHitTesting(false) Text("+\(remainingCount)") - .foregroundColor(Color(colors.staticColorText)) + .foregroundColor(Color(colors.backgroundCoreElevation0)) .font(fonts.title) .allowsHitTesting(false) } @@ -237,20 +259,40 @@ public struct MessageMediaAttachmentsContainerView: View { height: CGFloat, index: Int ) -> some View { - MessageMediaAttachmentContentView( + let effectiveRadius = isSingleMediaWithoutCaption ? tokens.messageBubbleRadiusGroupBottom : cornerRadius + let effectiveCorners: UIRectCorner? = isSingleMediaWithoutCaption ? noCaptionBubbleCorners : nil + return MessageMediaAttachmentContentView( factory: factory, source: item, width: width, height: height, - cornerRadius: cornerRadius, - isOutgoing: message.isSentByCurrentUser + cornerRadius: effectiveRadius, + corners: effectiveCorners, + isOutgoing: message.isSentByCurrentUser, + onUploadRetry: item.uploadingState?.state == .uploadingFailed ? { [message, chatClient] in + guard let cid = message.cid else { return } + let controller = chatClient.messageController( + cid: cid, + messageId: message.id + ) + controller.resendMessage() + } : nil + ) + .modifier( + MediaBorderOverlayModifier( + cornerRadius: effectiveRadius, + corners: effectiveCorners, + borderColor: message.bubbleBorder(colors: colors) + ) ) - .withUploadingStateIndicator(for: item.uploadingState, url: item.url) .contentShape(Rectangle()) .onTapGesture { if message.localState == nil { - selectedIndex = index - galleryShown = true + if selectedIndex == index { + galleryShown = true + } else { + selectedIndex = index + } } } .accessibilityLabel(L10n.Message.Attachment.accessibilityLabel(index + 1)) @@ -259,36 +301,39 @@ public struct MessageMediaAttachmentsContainerView: View { // MARK: - Data - private var orientation: MediaGalleryOrientation { - if let first = sources.first { - return MediaGalleryOrientation( - width: first.originalWidth, - height: first.originalHeight - ) - } - return .landscape + private var isSingleMediaWithoutCaption: Bool { + message.text.isEmpty && sources.count == 1 } - private var sources: [MediaAttachment] { - MediaAttachment.galleryOrdered(from: message) + private var noCaptionBubbleCorners: UIRectCorner { + let forceLeftToRight = utils.messageListConfig.messageListAlignment == .leftAligned + return message.bubbleCorners( + isFirst: isFirst, + forceLeftToRight: forceLeftToRight, + layoutDirection: layoutDirection + ) } private func containerSize(for itemCount: Int) -> CGSize { + Self.containerSize(for: itemCount, orientation: orientation, maxItemWidth: width) + } + + static func containerSize( + for itemCount: Int, + orientation: MediaGalleryOrientation, + maxItemWidth: CGFloat + ) -> CGSize { guard itemCount > 0 else { return .zero } - let maxItemWidth = width if itemCount == 1 { switch orientation { case .landscape: - // Width-constrained: 256×192 at max width return CGSize(width: maxItemWidth, height: maxItemWidth * 3.0 / 4.0) case .portrait: - // Height-constrained: 192×256 at max width return CGSize(width: maxItemWidth * 3.0 / 4.0, height: maxItemWidth) case .square: return CGSize(width: maxItemWidth, height: maxItemWidth) } } else { - // Multi-item always uses landscape ratio return CGSize(width: maxItemWidth, height: maxItemWidth * 3.0 / 4.0) } } @@ -297,3 +342,23 @@ public struct MessageMediaAttachmentsContainerView: View { max(sources.count - maxDisplayedItems, 0) } } + +/// Conditionally draws a bubble-shaped border stroke around the content. +/// When `corners` is `nil` (multi-item gallery cells), no overlay is drawn. +private struct MediaBorderOverlayModifier: ViewModifier { + let cornerRadius: CGFloat + let corners: UIRectCorner? + let borderColor: Color + + func body(content: Content) -> some View { + content.overlay(borderOverlay) + } + + @ViewBuilder + private var borderOverlay: some View { + if let corners { + BubbleBackgroundShape(cornerRadius: cornerRadius, corners: corners) + .stroke(borderColor, lineWidth: 1) + } + } +} diff --git a/Sources/StreamChatSwiftUI/ChatMessageList/MessageTopView.swift b/Sources/StreamChatSwiftUI/ChatMessageList/MessageTopView.swift index 0f109d10e..c5abaa3bb 100644 --- a/Sources/StreamChatSwiftUI/ChatMessageList/MessageTopView.swift +++ b/Sources/StreamChatSwiftUI/ChatMessageList/MessageTopView.swift @@ -18,11 +18,11 @@ struct MessageTopView: View { var usesInvertedStyle: Bool = false var body: some View { - VStack(alignment: messageViewModel.isRightAligned ? .trailing : .leading, spacing: tokens.spacingXxs) { + VStack(alignment: messageViewModel.isRightAligned ? .trailing : .leading, spacing: tokens.spacingXs) { if messageViewModel.isPinned { MessageAnnotationView( icon: images.pin, - title: "\(L10n.Message.Cell.pinnedBy) \(message.pinDetails?.pinnedBy.name ?? L10n.Message.Cell.unknownPin)", + title: messageViewModel.pinnedByText, usesInvertedStyle: usesInvertedStyle ) .accessibilityIdentifier("MessagePinDetailsView") diff --git a/Sources/StreamChatSwiftUI/ChatMessageList/MessageView.swift b/Sources/StreamChatSwiftUI/ChatMessageList/MessageView.swift index 7c627e61f..f7df871de 100644 --- a/Sources/StreamChatSwiftUI/ChatMessageList/MessageView.swift +++ b/Sources/StreamChatSwiftUI/ChatMessageList/MessageView.swift @@ -16,6 +16,7 @@ public struct MessageView: View { public var message: ChatMessage public var contentWidth: CGFloat public var isFirst: Bool + public var translationLanguage: TranslationLanguage? @Binding public var scrolledId: String? public init( @@ -23,12 +24,14 @@ public struct MessageView: View { message: ChatMessage, contentWidth: CGFloat, isFirst: Bool, - scrolledId: Binding + scrolledId: Binding, + translationLanguage: TranslationLanguage? = nil ) { self.factory = factory self.message = message self.contentWidth = contentWidth self.isFirst = isFirst + self.translationLanguage = translationLanguage _scrolledId = scrolledId } @@ -52,7 +55,14 @@ public struct MessageView: View { ) ) } else if let poll = message.poll { - factory.makePollView(options: PollViewOptions(message: message, poll: poll, isFirst: isFirst)) + factory.makePollView( + options: PollViewOptions( + message: message, + poll: poll, + isFirst: isFirst, + availableWidth: contentWidth + ) + ) } else if messageTypeResolver.hasGiphyAttachment(message: message) { factory.makeGiphyAttachmentView( options: GiphyAttachmentViewOptions( @@ -68,7 +78,8 @@ public struct MessageView: View { message: message, isFirst: isFirst, availableWidth: contentWidth, - scrolledId: $scrolledId + scrolledId: $scrolledId, + translationLanguage: translationLanguage ) ) } else { @@ -86,7 +97,8 @@ public struct MessageView: View { message: message, isFirst: isFirst, availableWidth: contentWidth, - scrolledId: $scrolledId + scrolledId: $scrolledId, + translationLanguage: translationLanguage ) ) } @@ -103,6 +115,7 @@ public struct MessageTextView: View { private let factory: Factory private let message: ChatMessage private let isFirst: Bool + private let translationLanguage: TranslationLanguage? private let leadingPadding: CGFloat private let trailingPadding: CGFloat private let topPadding: CGFloat @@ -113,7 +126,8 @@ public struct MessageTextView: View { factory: Factory, message: ChatMessage, isFirst: Bool, - scrolledId: Binding + scrolledId: Binding, + translationLanguage: TranslationLanguage? ) { @Injected(\.tokens) var tokens self.init( @@ -124,10 +138,11 @@ public struct MessageTextView: View { trailingPadding: tokens.spacingSm, topPadding: tokens.spacingXs, bottomPadding: tokens.spacingXs, - scrolledId: scrolledId + scrolledId: scrolledId, + translationLanguage: translationLanguage ) } - + public init( factory: Factory, message: ChatMessage, @@ -136,11 +151,13 @@ public struct MessageTextView: View { trailingPadding: CGFloat, topPadding: CGFloat, bottomPadding: CGFloat, - scrolledId: Binding + scrolledId: Binding, + translationLanguage: TranslationLanguage? ) { self.factory = factory self.message = message self.isFirst = isFirst + self.translationLanguage = translationLanguage self.leadingPadding = leadingPadding self.trailingPadding = trailingPadding self.topPadding = topPadding @@ -153,12 +170,15 @@ public struct MessageTextView: View { alignment: message.alignmentInBubble, spacing: 0 ) { - factory.makeStreamTextView(options: .init(message: message)) - .padding(.leading, leadingPadding) - .padding(.trailing, trailingPadding) - .padding(.top, topPadding) - .padding(.bottom, bottomPadding) - .fixedSize(horizontal: false, vertical: true) + factory.makeStreamTextView(options: .init( + message: message, + translationLanguage: translationLanguage + )) + .padding(.leading, leadingPadding) + .padding(.trailing, trailingPadding) + .padding(.top, topPadding) + .padding(.bottom, bottomPadding) + .fixedSize(horizontal: false, vertical: true) } .modifier( factory.styles.makeMessageViewModifier( @@ -213,117 +233,34 @@ public struct EmojiTextView: View { } struct StreamTextView: View { - @Injected(\.fonts) var fonts - - let message: ChatMessage - private let adjustedText: String - - init(message: ChatMessage) { - self.message = message - adjustedText = message.adjustedText - } - - var body: some View { - if #available(iOS 15, *) { - LinkDetectionTextView(message: message) - } else { - Text(adjustedText) - .foregroundColor(textColor(for: message)) - .font(fonts.body) - } - } -} - -@available(iOS 15, *) -public struct LinkDetectionTextView: View { @Environment(\.layoutDirection) var layoutDirection - @Environment(\.channelTranslationLanguage) var translationLanguage - @Environment(\.messageViewModel) var messageViewModel - @Injected(\.colors) var colors @Injected(\.fonts) var fonts - @Injected(\.utils) var utils - - var message: ChatMessage - // The translations store is used to detect changes so the textContent is re-rendered. - // The @Environment(\.messageViewModel) is not reactive like @EnvironmentObject. - // TODO: On v5 the TextView should be refactored and not depend directly on the view model. - @ObservedObject var originalTranslationsStore = InjectedValues[\.utils].originalTranslationsStore + let message: ChatMessage + let textContent: String + let translationLanguage: TranslationLanguage? - @State var text: AttributedString? - @State var linkDetector = TextLinkDetector() - @State var tintColor = Color(InjectedValues[\.colors].accentPrimary) - - public init( - message: ChatMessage - ) { + init(message: ChatMessage, translationLanguage: TranslationLanguage?) { self.message = message + self.textContent = message.textContent(for: translationLanguage) ?? message.adjustedText + self.translationLanguage = translationLanguage } - - public var body: some View { - Group { - Text(text ?? displayText) - } - .foregroundColor(textColor(for: message)) - .font(fonts.body) - .tint(tintColor) - .onChange(of: message) { message in - messageViewModel?.message = message - text = displayText - } - } - - var displayText: AttributedString { - let text = messageViewModel?.textContent ?? message.text - // Markdown - let attributes = AttributeContainer() - .foregroundColor(textColor(for: message)) - .font(fonts.body) - var attributedString: AttributedString - if utils.messageListConfig.markdownSupportEnabled { - attributedString = utils.markdownFormatter.format( - text, - attributes: attributes, - layoutDirection: layoutDirection + var body: some View { + if #available(iOS 15, *) { + let attributedText = message.attributedTextContent( + layoutDirection: layoutDirection, + translationLanguage: translationLanguage ) + Text(attributedText) + .foregroundColor(textColor(for: message)) + .font(fonts.body) + .tint(Color(colors.accentPrimary)) } else { - attributedString = AttributedString(message.adjustedText, attributes: attributes) - } - // Links and mentions - if utils.messageListConfig.localLinkDetectionEnabled { - for user in message.mentionedUsers { - let mention = "@\(user.name ?? user.id)" - let ranges = attributedString.ranges(of: mention, options: [.caseInsensitive]) - for range in ranges { - if let messageId = message.messageId.addingPercentEncoding(withAllowedCharacters: .urlPathAllowed), - let url = URL(string: "getstream://mention/\(messageId)/\(user.id)") { - attributedString[range].link = url - } - } - } - for link in linkDetector.links(in: String(attributedString.characters)) { - if let attributedStringRange = Range(link.range, in: attributedString) { - attributedString[attributedStringRange].link = link.url - } - } - } - // Finally change attributes for links (markdown links, text links, mentions) - var linkAttributes = utils.messageListConfig.messageDisplayOptions.messageLinkDisplayResolver(message) - if !linkAttributes.isEmpty { - var linkAttributeContainer = AttributeContainer() - if let uiColor = linkAttributes[.foregroundColor] as? UIColor { - linkAttributeContainer = linkAttributeContainer.foregroundColor(Color(uiColor: uiColor)) - linkAttributes.removeValue(forKey: .foregroundColor) - } - linkAttributeContainer.merge(AttributeContainer(linkAttributes)) - for (value, range) in attributedString.runs[\.link] { - guard value != nil else { continue } - attributedString[range].mergeAttributes(linkAttributeContainer) - } + Text(textContent) + .foregroundColor(textColor(for: message)) + .font(fonts.body) } - - return attributedString } } diff --git a/Sources/StreamChatSwiftUI/ChatMessageList/MessageViewModel.swift b/Sources/StreamChatSwiftUI/ChatMessageList/MessageViewModel.swift index ee440d1e8..be51ee418 100644 --- a/Sources/StreamChatSwiftUI/ChatMessageList/MessageViewModel.swift +++ b/Sources/StreamChatSwiftUI/ChatMessageList/MessageViewModel.swift @@ -86,6 +86,14 @@ import StreamChat message.isPinned } + public var pinnedByText: String { + if message.pinDetails?.pinnedBy.id == chatClient.currentUserId { + return L10n.Message.Cell.pinnedByYou + } + let name = message.pinDetails?.pinnedBy.name ?? L10n.Message.Cell.unknownPin + return "\(L10n.Message.Cell.pinnedBy) \(name)" + } + public var isRightAligned: Bool { message.isRightAligned } @@ -107,12 +115,13 @@ import StreamChat message.isInteractionEnabled && channel.config.quotesEnabled == true } - open var textContent: String { - if !originalTextShown, let translatedText { - return translatedText - } - - return message.adjustedText + /// The translation language to use for displaying the message text. + /// + /// Returns the channel's membership language when the original text is not shown, + /// otherwise `nil` to display the original text. + public var translationLanguage: TranslationLanguage? { + guard !originalTextShown else { return nil } + return channel.membership?.language } public var translatedText: String? { diff --git a/Sources/StreamChatSwiftUI/ChatMessageList/PercentageProgressView.swift b/Sources/StreamChatSwiftUI/ChatMessageList/PercentageProgressView.swift deleted file mode 100644 index 38f7a8a30..000000000 --- a/Sources/StreamChatSwiftUI/ChatMessageList/PercentageProgressView.swift +++ /dev/null @@ -1,37 +0,0 @@ -// -// Copyright © 2026 Stream.io Inc. All rights reserved. -// - -import SwiftUI - -/// A view used to show the progress of a task a long with the percentage. -struct PercentageProgressView: View { - @Injected(\.images) private var images - @Injected(\.colors) private var colors - @Injected(\.fonts) private var fonts - - let progress: CGFloat - - var body: some View { - HStack(spacing: 4) { - ProgressView() - .progressViewStyle( - CircularProgressViewStyle(tint: .white) - ) - .scaleEffect(0.7) - - Text(progressDisplay(for: progress)) - .font(fonts.footnote) - .foregroundColor(Color(colors.staticColorText)) - } - .padding(.all, 4) - .background(Color.black.opacity(0.7)) - .cornerRadius(8) - .padding(.all, 8) - } - - private func progressDisplay(for progress: CGFloat) -> String { - let value = Int(progress * 100) - return "\(value)%" - } -} diff --git a/Sources/StreamChatSwiftUI/ChatMessageList/Polls/PollAllOptionsView.swift b/Sources/StreamChatSwiftUI/ChatMessageList/Polls/PollAllOptionsView.swift index fbf17667a..785a12213 100644 --- a/Sources/StreamChatSwiftUI/ChatMessageList/Polls/PollAllOptionsView.swift +++ b/Sources/StreamChatSwiftUI/ChatMessageList/Polls/PollAllOptionsView.swift @@ -33,7 +33,7 @@ struct PollAllOptionsView: View { .padding(.top, tokens.spacingMd) .padding(.bottom, tokens.spacing3xl) } - .background(Color(colors.backgroundElevationElevation1).ignoresSafeArea()) + .background(Color(colors.backgroundCoreElevation1).ignoresSafeArea()) .toolbarThemed { ToolbarItem(placement: .principal) { Text(L10n.Message.Polls.Toolbar.optionsTitle) @@ -76,7 +76,8 @@ struct PollAllOptionsView: View { option: option, optionVotes: viewModel.poll.voteCount(for: option), maxVotes: viewModel.poll.currentMaximumVoteCount, - message: viewModel.message + message: viewModel.message, + forceIncomingStyle: true ) } } diff --git a/Sources/StreamChatSwiftUI/ChatMessageList/Polls/PollAttachmentView.swift b/Sources/StreamChatSwiftUI/ChatMessageList/Polls/PollAttachmentView.swift index 2384a350b..4762334aa 100644 --- a/Sources/StreamChatSwiftUI/ChatMessageList/Polls/PollAttachmentView.swift +++ b/Sources/StreamChatSwiftUI/ChatMessageList/Polls/PollAttachmentView.swift @@ -10,10 +10,12 @@ public struct PollAttachmentView: View { @Injected(\.fonts) var fonts @Injected(\.colors) var colors @Injected(\.tokens) var tokens + @Injected(\.utils) var utils private let factory: Factory private let message: ChatMessage private let isFirst: Bool + private let width: CGFloat @StateObject var viewModel: PollAttachmentViewModel @@ -21,11 +23,13 @@ public struct PollAttachmentView: View { factory: Factory, message: ChatMessage, poll: Poll, - isFirst: Bool + isFirst: Bool, + width: CGFloat ) { self.factory = factory self.message = message self.isFirst = isFirst + self.width = width _viewModel = StateObject( wrappedValue: PollAttachmentViewModel( message: message, @@ -178,6 +182,7 @@ public struct PollAttachmentView: View { ) ) ) + .frame(width: width) } private var outlineButtonRole: StreamButtonRole { @@ -218,8 +223,9 @@ struct PollOptionView: View { var optionVotes: Int? var maxVotes: Int? var message: ChatMessage - /// If true, only option name and vote count is shown, otherwise votes indicator and avatars appear as well. - var alternativeStyle: Bool = false + /// If true, forces incoming color style for the radio button border and progress track, + /// regardless of whether the message was sent by the current user. + var forceIncomingStyle: Bool = false var body: some View { HStack(alignment: .top, spacing: tokens.spacingSm) { @@ -229,45 +235,48 @@ struct PollOptionView: View { } label: { RadioCheckView( isSelected: viewModel.optionVotedByCurrentUser(option), - borderColorOverride: message.isSentByCurrentUser + borderColorOverride: (!forceIncomingStyle && message.isSentByCurrentUser) ? colors.chatBorderOnChatOutgoing : colors.chatBorderOnChatIncoming ) } + .padding(.top, tokens.spacingXxs) } VStack(spacing: tokens.spacingXxs) { - HStack(spacing: tokens.spacingXs) { + HStack(alignment: .top, spacing: tokens.spacingXs) { Text(option.text) .font(optionFont) .foregroundColor(textColor(for: message)) + .padding(.top, tokens.spacingXxxs) Spacer() - if !alternativeStyle, viewModel.showVoterAvatars { - HStack(spacing: -4) { - ForEach( - option.latestVotes.compactMap(\.user).prefix(2) - ) { user in - factory.makeUserAvatarView( - options: UserAvatarViewOptions( - user: user, - size: AvatarSize.extraSmall, - showsIndicator: false + HStack(spacing: tokens.spacingXs) { + if viewModel.showVoterAvatars { + HStack(spacing: -4) { + ForEach( + option.latestVotes.compactMap(\.user).prefix(2) + ) { user in + factory.makeUserAvatarView( + options: UserAvatarViewOptions( + user: user, + size: AvatarSize.extraSmall, + showsIndicator: false + ) ) - ) + } } + .frame(height: AvatarSize.extraSmall) } + Text("\(viewModel.poll.voteCountsByOption?[option.id] ?? 0)") + .font(fonts.footnote) + .foregroundColor(textColor(for: message)) } - Text("\(viewModel.poll.voteCountsByOption?[option.id] ?? 0)") - .font(fonts.footnote) - .foregroundColor(textColor(for: message)) - } - if !alternativeStyle { - PollVotesIndicatorView( - alternativeStyle: viewModel.poll.isClosed && viewModel.hasMostVotes(for: option), - optionVotes: optionVotes ?? 0, - maxVotes: maxVotes ?? 0, - isOutgoing: message.isSentByCurrentUser - ) } + + PollVotesIndicatorView( + optionVotes: optionVotes ?? 0, + maxVotes: maxVotes ?? 0, + isOutgoing: forceIncomingStyle ? false : message.isSentByCurrentUser + ) } } .contentShape(Rectangle()) @@ -289,7 +298,6 @@ struct PollVotesIndicatorView: View { @Injected(\.colors) var colors @Injected(\.tokens) var tokens - let alternativeStyle: Bool let optionVotes: Int let maxVotes: Int var isOutgoing: Bool = false @@ -316,10 +324,7 @@ struct PollVotesIndicatorView: View { } private var fillColor: UIColor { - if alternativeStyle { - return colors.alternativeActiveTint - } - return isOutgoing ? colors.chatPollProgressFillOutgoing : colors.chatPollProgressFillIncoming + isOutgoing ? colors.chatPollProgressFillOutgoing : colors.chatPollProgressFillIncoming } var ratio: CGFloat { diff --git a/Sources/StreamChatSwiftUI/ChatMessageList/Polls/PollAttachmentViewModel.swift b/Sources/StreamChatSwiftUI/ChatMessageList/Polls/PollAttachmentViewModel.swift index f23970d3e..334323bfe 100644 --- a/Sources/StreamChatSwiftUI/ChatMessageList/Polls/PollAttachmentViewModel.swift +++ b/Sources/StreamChatSwiftUI/ChatMessageList/Polls/PollAttachmentViewModel.swift @@ -69,7 +69,6 @@ import SwiftUI /// If true, poll controls are in enabled state, otherwise disabled. public var canInteract: Bool { guard !isClosingPoll else { return false } - guard !endVoteConfirmationShown else { return false } return true } diff --git a/Sources/StreamChatSwiftUI/ChatMessageList/Polls/PollCommentsView.swift b/Sources/StreamChatSwiftUI/ChatMessageList/Polls/PollCommentsView.swift index 184ea4c8b..e1a750a02 100644 --- a/Sources/StreamChatSwiftUI/ChatMessageList/Polls/PollCommentsView.swift +++ b/Sources/StreamChatSwiftUI/ChatMessageList/Polls/PollCommentsView.swift @@ -59,7 +59,7 @@ struct PollCommentsView: View { accept: commentAlertAcceptAction, action: { viewModel.add(comment: viewModel.newCommentText) } ) - .background(Color(colors.backgroundElevationElevation1).ignoresSafeArea()) + .background(Color(colors.backgroundCoreElevation1).ignoresSafeArea()) .alertBanner( isPresented: $viewModel.errorShown, action: viewModel.refresh diff --git a/Sources/StreamChatSwiftUI/ChatMessageList/Polls/PollOptionAllVotesView.swift b/Sources/StreamChatSwiftUI/ChatMessageList/Polls/PollOptionAllVotesView.swift index 75c73651d..7c3cda633 100644 --- a/Sources/StreamChatSwiftUI/ChatMessageList/Polls/PollOptionAllVotesView.swift +++ b/Sources/StreamChatSwiftUI/ChatMessageList/Polls/PollOptionAllVotesView.swift @@ -43,7 +43,7 @@ struct PollOptionAllVotesView: View { .padding(.top, tokens.spacingMd) .padding(.bottom, tokens.spacing3xl) } - .background(Color(colors.backgroundElevationElevation1).ignoresSafeArea()) + .background(Color(colors.backgroundCoreElevation1).ignoresSafeArea()) .alertBanner( isPresented: $viewModel.errorShown, action: viewModel.refresh diff --git a/Sources/StreamChatSwiftUI/ChatMessageList/Polls/PollResultsView.swift b/Sources/StreamChatSwiftUI/ChatMessageList/Polls/PollResultsView.swift index b4548732c..09ed6a7df 100644 --- a/Sources/StreamChatSwiftUI/ChatMessageList/Polls/PollResultsView.swift +++ b/Sources/StreamChatSwiftUI/ChatMessageList/Polls/PollResultsView.swift @@ -3,7 +3,6 @@ // import StreamChat -import StreamChatCommonUI import SwiftUI struct PollResultsView: View { @@ -36,7 +35,7 @@ struct PollResultsView: View { .padding(.top, tokens.spacingMd) .padding(.bottom, tokens.spacing3xl) } - .background(Color(colors.backgroundElevationElevation1).ignoresSafeArea()) + .background(Color(colors.backgroundCoreElevation1).ignoresSafeArea()) .toolbarThemed { ToolbarItem(placement: .principal) { Text(L10n.Message.Polls.Toolbar.resultsTitle) diff --git a/Sources/StreamChatSwiftUI/ChatMessageList/QuotedMessageView/ChatQuotedMessageView.swift b/Sources/StreamChatSwiftUI/ChatMessageList/QuotedMessageView/ChatQuotedMessageView.swift index 8bd270745..d4b5a9b1b 100644 --- a/Sources/StreamChatSwiftUI/ChatMessageList/QuotedMessageView/ChatQuotedMessageView.swift +++ b/Sources/StreamChatSwiftUI/ChatMessageList/QuotedMessageView/ChatQuotedMessageView.swift @@ -44,7 +44,6 @@ public struct ChatQuotedMessageView: View { outgoing: parentMessageSentByCurrentUser ) ) - .frame(width: availableWidth) .modifier(ReferenceMessageViewBackgroundModifier( backgroundColor: Color( parentMessageSentByCurrentUser @@ -52,7 +51,7 @@ public struct ChatQuotedMessageView: View { : colors.chatBackgroundAttachmentIncoming ) )) - .frame(height: 56) + .frame(width: availableWidth, height: 56) .onTapGesture { scrolledId = quotedMessage.messageId } diff --git a/Sources/StreamChatSwiftUI/ChatMessageList/Reactions/MessageActions/DefaultMessageActions.swift b/Sources/StreamChatSwiftUI/ChatMessageList/Reactions/MessageActions/DefaultMessageActions.swift index 5da6380a8..68591f1e1 100644 --- a/Sources/StreamChatSwiftUI/ChatMessageList/Reactions/MessageActions/DefaultMessageActions.swift +++ b/Sources/StreamChatSwiftUI/ChatMessageList/Reactions/MessageActions/DefaultMessageActions.swift @@ -368,7 +368,7 @@ public extension MessageAction { let replyAction = MessageAction( id: MessageActionId.reply, title: L10n.Message.Actions.inlineReply, - iconName: "icn_inline_reply", + iconName: "arrowshape.turn.up.left", action: { onFinish( MessageActionInfo( @@ -392,7 +392,7 @@ public extension MessageAction { let replyThread = MessageAction( id: MessageActionId.threadReply, title: L10n.Message.Actions.threadReply, - iconName: "icn_thread_reply", + iconName: "text.bubble", action: { NotificationCenter.default.post( name: MessageRepliesConstants.threadMessageNavigationNotification, @@ -527,7 +527,7 @@ public extension MessageAction { let unreadAction = MessageAction( id: MessageActionId.markUnread, title: L10n.Message.Actions.markUnread, - iconName: "message.badge", + iconName: "app.badge", action: action, confirmationPopup: nil, isDestructive: false @@ -634,7 +634,7 @@ public extension MessageAction { let blockUser = MessageAction( id: MessageActionId.block, title: L10n.Message.Actions.userBlock, - iconName: "icn_block_user", + iconName: "nosign", action: blockAction, confirmationPopup: ConfirmationPopup( title: L10n.Message.Actions.userBlock, @@ -712,7 +712,7 @@ public extension MessageAction { let unblockUser = MessageAction( id: MessageActionId.unblock, title: L10n.Message.Actions.userUnblock, - iconName: "icn_block_user", + iconName: "nosign", action: unblockAction, confirmationPopup: ConfirmationPopup( title: L10n.Message.Actions.userUnblock, diff --git a/Sources/StreamChatSwiftUI/ChatMessageList/Reactions/MessageActions/MessageActionsView.swift b/Sources/StreamChatSwiftUI/ChatMessageList/Reactions/MessageActions/MessageActionsView.swift index 0cb3cbb5c..2f1e173c1 100644 --- a/Sources/StreamChatSwiftUI/ChatMessageList/Reactions/MessageActions/MessageActionsView.swift +++ b/Sources/StreamChatSwiftUI/ChatMessageList/Reactions/MessageActions/MessageActionsView.swift @@ -63,7 +63,7 @@ public struct MessageActionsView: View { .accessibilityIdentifier("messageAction-\(action.id)") } } - .background(Color(colors.background8)) + .background(Color(colors.backgroundCoreElevation2)) .roundWithBorder(cornerRadius: 12) .alert(isPresented: $viewModel.alertShown) { let title = viewModel.alertAction?.confirmationPopup?.title ?? "" diff --git a/Sources/StreamChatSwiftUI/ChatMessageList/Reactions/MoreReactionsView.swift b/Sources/StreamChatSwiftUI/ChatMessageList/Reactions/MoreReactionsView.swift index 5d395b11f..de7db9edc 100644 --- a/Sources/StreamChatSwiftUI/ChatMessageList/Reactions/MoreReactionsView.swift +++ b/Sources/StreamChatSwiftUI/ChatMessageList/Reactions/MoreReactionsView.swift @@ -44,7 +44,7 @@ struct MoreReactionsView: View { .frame(maxWidth: .infinity, alignment: .leading) .padding() .accessibilityIdentifier("MoreReactionsView") - .background(Color(colors.backgroundElevationElevation1).edgesIgnoringSafeArea(.bottom)) + .background(Color(colors.backgroundCoreElevation1).edgesIgnoringSafeArea(.bottom)) .edgesIgnoringSafeArea(.bottom) } } diff --git a/Sources/StreamChatSwiftUI/ChatMessageList/Reactions/ReactionsBubbleView.swift b/Sources/StreamChatSwiftUI/ChatMessageList/Reactions/ReactionsBubbleView.swift index fa356d177..c8fc265f4 100644 --- a/Sources/StreamChatSwiftUI/ChatMessageList/Reactions/ReactionsBubbleView.swift +++ b/Sources/StreamChatSwiftUI/ChatMessageList/Reactions/ReactionsBubbleView.swift @@ -44,7 +44,7 @@ public struct ReactionsBubbleModifier: ViewModifier { return injectedBackground } - return colors.reactionBackground + return colors.backgroundCoreElevation3 } } diff --git a/Sources/StreamChatSwiftUI/ChatMessageList/Reactions/ReactionsDetailView.swift b/Sources/StreamChatSwiftUI/ChatMessageList/Reactions/ReactionsDetailView.swift index 793e318f6..1a2125e0e 100644 --- a/Sources/StreamChatSwiftUI/ChatMessageList/Reactions/ReactionsDetailView.swift +++ b/Sources/StreamChatSwiftUI/ChatMessageList/Reactions/ReactionsDetailView.swift @@ -5,21 +5,24 @@ import StreamChat import SwiftUI -struct ReactionsDetailView: View { +struct ReactionsDetailView: View { @Injected(\.colors) private var colors @Injected(\.fonts) private var fonts @Injected(\.tokens) private var tokens @Injected(\.images) private var images + let factory: Factory @StateObject var viewModel: ReactionsDetailViewModel @Environment(\.presentationMode) var presentationMode - init(message: ChatMessage) { + init(factory: Factory = DefaultViewFactory.shared, message: ChatMessage) { + self.factory = factory _viewModel = StateObject(wrappedValue: .init(message: message)) } - init(viewModel: ReactionsDetailViewModel) { + init(factory: Factory = DefaultViewFactory.shared, viewModel: ReactionsDetailViewModel) { + self.factory = factory _viewModel = StateObject(wrappedValue: viewModel) } @@ -27,7 +30,7 @@ struct ReactionsDetailView: View { VStack(spacing: 0) { Text(L10n.Reaction.Authors.numberOfReactions(viewModel.totalReactionsCount)) .font(fonts.bodyBold) - .foregroundColor(Color(colors.text)) + .foregroundColor(Color(colors.textPrimary)) .padding(.vertical, tokens.spacingXl) ScrollView(.horizontal, showsIndicators: false) { @@ -54,7 +57,7 @@ struct ReactionsDetailView: View { } } } - .background(Color(colors.backgroundElevationElevation1).edgesIgnoringSafeArea(.bottom)) + .background(Color(colors.backgroundCoreElevation1).edgesIgnoringSafeArea(.bottom)) .sheet(isPresented: $viewModel.moreReactionsPickerShown) { MoreReactionsView { emoji in let reaction = MessageReactionType(rawValue: emoji) @@ -83,7 +86,7 @@ struct ReactionsDetailView: View { .padding(.vertical, tokens.spacingXs) .background( Capsule() - .fill(Color(colors.backgroundElevationElevation1)) + .fill(Color(colors.backgroundCoreElevation1)) ) .overlay( Capsule() @@ -109,13 +112,13 @@ struct ReactionsDetailView: View { } Text("\(viewModel.reactionCount(for: type))") .font(fonts.footnoteBold) - .foregroundColor(Color(colors.chipText)) + .foregroundColor(Color(colors.controlChipText)) } .padding(.horizontal, tokens.spacingSm) .padding(.vertical, tokens.spacingXs) .background( Capsule() - .fill(viewModel.selectedReactionType == type ? Color(colors.backgroundCoreSelected) : Color(colors.backgroundElevationElevation1)) + .fill(viewModel.selectedReactionType == type ? Color(colors.backgroundUtilitySelected) : Color(colors.backgroundCoreElevation1)) ) .overlay( Capsule() @@ -129,11 +132,13 @@ struct ReactionsDetailView: View { private func reactionRow(reaction: ChatMessageReaction) -> some View { let isCurrentUser = viewModel.isCurrentUser(reaction) return HStack(spacing: tokens.spacingSm) { - UserAvatar( - user: reaction.author, - size: AvatarSize.large, - showsIndicator: false, - showsBorder: false + factory.makeUserAvatarView( + options: UserAvatarViewOptions( + user: reaction.author, + size: AvatarSize.large, + showsIndicator: false, + showsBorder: false + ) ) Button { diff --git a/Sources/StreamChatSwiftUI/ChatMessageList/Reactions/ReactionsDetailViewModel.swift b/Sources/StreamChatSwiftUI/ChatMessageList/Reactions/ReactionsDetailViewModel.swift index e717863c1..9f592f5b4 100644 --- a/Sources/StreamChatSwiftUI/ChatMessageList/Reactions/ReactionsDetailViewModel.swift +++ b/Sources/StreamChatSwiftUI/ChatMessageList/Reactions/ReactionsDetailViewModel.swift @@ -109,6 +109,7 @@ class ReactionsDetailViewModel: ObservableObject, ChatReactionListControllerDele func messageController(_ controller: ChatMessageController, didChangeMessage change: EntityChange) { if let message = controller.message { self.message = message + syncCurrentUserReactions(from: message) } } @@ -146,4 +147,26 @@ class ReactionsDetailViewModel: ObservableObject, ChatReactionListControllerDele private var userReactionIDs: Set { Set(message.currentUserReactions.map(\.type)) } + + private func syncCurrentUserReactions(from message: ChatMessage) { + guard let currentUserId = chatClient.currentUserId else { return } + + let currentUserReactions = message.currentUserReactions + .sorted { $0.updatedAt > $1.updatedAt } + let hadCurrentUserReactions = reactions.contains { $0.author.id == currentUserId } + + guard hadCurrentUserReactions || !currentUserReactions.isEmpty else { return } + + let mergedReactions = reactions + .filter { $0.author.id != currentUserId } + + currentUserReactions + + let sortedReactions = mergedReactions.sorted { first, second in + first.updatedAt > second.updatedAt + } + + if reactions != sortedReactions { + reactions = sortedReactions + } + } } diff --git a/Sources/StreamChatSwiftUI/ChatMessageList/Reactions/ReactionsOverlayContainer.swift b/Sources/StreamChatSwiftUI/ChatMessageList/Reactions/ReactionsOverlayContainer.swift index 0c37d098b..4c3709d6c 100644 --- a/Sources/StreamChatSwiftUI/ChatMessageList/Reactions/ReactionsOverlayContainer.swift +++ b/Sources/StreamChatSwiftUI/ChatMessageList/Reactions/ReactionsOverlayContainer.swift @@ -111,7 +111,7 @@ public struct ReactionsAnimatableView: View { .padding(tokens.spacingXs) } .padding(.leading, tokens.spacingXxs) - .reactionsBubble(for: message, background: colors.background8) + .reactionsBubble(for: message, background: colors.backgroundCoreElevation2) } } @@ -177,7 +177,7 @@ public struct ReactionAnimatableView: View { } private func reactionSelectedBackgroundColor(for reaction: MessageReactionType) -> Color? { - userReactionIDs.contains(reaction) ? Color(colors.backgroundCoreSelected) : nil + userReactionIDs.contains(reaction) ? Color(colors.backgroundUtilitySelected) : nil } private func index(for reaction: MessageReactionType) -> Int? { diff --git a/Sources/StreamChatSwiftUI/ChatMessageList/Reactions/ReactionsOverlayView.swift b/Sources/StreamChatSwiftUI/ChatMessageList/Reactions/ReactionsOverlayView.swift index 71443b15d..56165921c 100644 --- a/Sources/StreamChatSwiftUI/ChatMessageList/Reactions/ReactionsOverlayView.swift +++ b/Sources/StreamChatSwiftUI/ChatMessageList/Reactions/ReactionsOverlayView.swift @@ -105,7 +105,6 @@ public struct ReactionsOverlayView: View { ) .frame(width: messageDisplayInfo.frame.width) .frame(maxHeight: messageDisplayInfo.frame.height) - .environment(\.channelTranslationLanguage, channel.membership?.language) .scaleEffect(popIn || willPopOut ? 1 : 0.95) .animation(willPopOut ? .easeInOut : popInAnimation, value: popIn) messageActionsView(reader: reader) @@ -140,7 +139,7 @@ public struct ReactionsOverlayView: View { messageViewModel.usesScrollView = usesScrollView } .edgesIgnoringSafeArea(.all) - .background(orientationChanged ? nil : Color(colors.backgroundElevationElevation1)) + .background(orientationChanged ? nil : Color(colors.backgroundCoreElevation1)) .onAppear { popIn = true } @@ -246,7 +245,8 @@ public struct ReactionsOverlayView: View { } ) ) - .frame(width: messageActionsWidth) + .frame(minWidth: 250, alignment: isRightAligned ? .trailing : .leading) + .fixedSize(horizontal: true, vertical: false) .opacity(willPopOut ? 0 : 1) .scaleEffect(popIn ? 1 : (willPopOut ? 0.4 : 0)) .animation(willPopOut ? .easeInOut : popInAnimation, value: popIn) @@ -293,14 +293,6 @@ public struct ReactionsOverlayView: View { return messageHorizontalPadding } - private var messageActionsWidth: CGFloat { - var width = messageDisplayInfo.contentWidth + 2 * messageHorizontalPadding - if isRightAligned { - width -= 2 * messageHorizontalPadding - } - return width - } - private var overlayContentWidth: CGFloat { messageDisplayInfo.frame.width } diff --git a/Sources/StreamChatSwiftUI/ChatMessageList/ReactionsIconProvider.swift b/Sources/StreamChatSwiftUI/ChatMessageList/ReactionsIconProvider.swift index 9d3d4196d..763b3328b 100644 --- a/Sources/StreamChatSwiftUI/ChatMessageList/ReactionsIconProvider.swift +++ b/Sources/StreamChatSwiftUI/ChatMessageList/ReactionsIconProvider.swift @@ -3,7 +3,6 @@ // import StreamChat -import StreamChatCommonUI import SwiftUI import UIKit @@ -38,9 +37,7 @@ class ReactionsIconProvider { } @MainActor static func color(for reaction: MessageReactionType, userReactionIDs: Set) -> Color? { - let containsUserReaction = userReactionIDs.contains(reaction) - let color = containsUserReaction ? colors.reactionCurrentUserColor : colors.reactionOtherUserColor - return Color(color) + return Color(colors.backgroundUtilitySelected) } } diff --git a/Sources/StreamChatSwiftUI/ChatMessageList/ReferenceMessageView/AttachmentPreviews/MessageAttachmentPreviewIcon.swift b/Sources/StreamChatSwiftUI/ChatMessageList/ReferenceMessageView/AttachmentPreviews/MessageAttachmentPreviewIcon.swift index a86f61d92..2491af397 100644 --- a/Sources/StreamChatSwiftUI/ChatMessageList/ReferenceMessageView/AttachmentPreviews/MessageAttachmentPreviewIcon.swift +++ b/Sources/StreamChatSwiftUI/ChatMessageList/ReferenceMessageView/AttachmentPreviews/MessageAttachmentPreviewIcon.swift @@ -2,7 +2,6 @@ // Copyright © 2026 Stream.io Inc. All rights reserved. // -import StreamChatCommonUI import UIKit /// Represents the attachment icon to display in a message. diff --git a/Sources/StreamChatSwiftUI/ChatMessageList/ReferenceMessageView/AttachmentPreviews/MessageAttachmentPreviewIconView.swift b/Sources/StreamChatSwiftUI/ChatMessageList/ReferenceMessageView/AttachmentPreviews/MessageAttachmentPreviewIconView.swift index 4d50bda7d..0e8047e53 100644 --- a/Sources/StreamChatSwiftUI/ChatMessageList/ReferenceMessageView/AttachmentPreviews/MessageAttachmentPreviewIconView.swift +++ b/Sources/StreamChatSwiftUI/ChatMessageList/ReferenceMessageView/AttachmentPreviews/MessageAttachmentPreviewIconView.swift @@ -50,7 +50,7 @@ public struct DefaultMessageAttachmentPreviewIconProvider: MessageAttachmentPrev public func image(for icon: MessageAttachmentPreviewIcon) -> UIImage { switch icon { case .poll: - return images.attachmentPickerPolls + return images.attachmentPollIcon case .voiceRecording: return images.attachmentVoiceIcon case .photo: diff --git a/Sources/StreamChatSwiftUI/ChatMessageList/ReferenceMessageView/AttachmentPreviews/MessageAttachmentPreviewKind.swift b/Sources/StreamChatSwiftUI/ChatMessageList/ReferenceMessageView/AttachmentPreviews/MessageAttachmentPreviewKind.swift index 4cea8a570..7dda203e2 100644 --- a/Sources/StreamChatSwiftUI/ChatMessageList/ReferenceMessageView/AttachmentPreviews/MessageAttachmentPreviewKind.swift +++ b/Sources/StreamChatSwiftUI/ChatMessageList/ReferenceMessageView/AttachmentPreviews/MessageAttachmentPreviewKind.swift @@ -12,6 +12,8 @@ enum MessageAttachmentPreviewKind: Equatable { case poll(name: String) /// A voice recording attachment. case voiceRecording(duration: TimeInterval?) + /// A giphy attachment. + case giphy /// One or more photo attachments. case photo(count: Int) /// One or more video attachments. diff --git a/Sources/StreamChatSwiftUI/ChatMessageList/ReferenceMessageView/AttachmentPreviews/MessageAttachmentPreviewResolver.swift b/Sources/StreamChatSwiftUI/ChatMessageList/ReferenceMessageView/AttachmentPreviews/MessageAttachmentPreviewResolver.swift index c074deade..a8bd60ea3 100644 --- a/Sources/StreamChatSwiftUI/ChatMessageList/ReferenceMessageView/AttachmentPreviews/MessageAttachmentPreviewResolver.swift +++ b/Sources/StreamChatSwiftUI/ChatMessageList/ReferenceMessageView/AttachmentPreviews/MessageAttachmentPreviewResolver.swift @@ -43,6 +43,9 @@ public struct MessageAttachmentPreviewResolver { } return L10n.Composer.Quoted.voiceMessage + case .giphy: + return L10n.Composer.Quoted.giphy + case .photo(let count): return count == 1 ? L10n.Composer.Quoted.photo : L10n.Composer.Quoted.photos(count) @@ -75,6 +78,8 @@ public struct MessageAttachmentPreviewResolver { return .poll case .voiceRecording: return .voiceRecording + case .giphy: + return .document case .photo: return .photo case .video: @@ -146,8 +151,13 @@ public struct MessageAttachmentPreviewResolver { return .voiceRecording(duration: duration) } - // Images (including giphys) - let imageCount = message.imageAttachments.count + message.giphyAttachments.count + // Giphy + if !message.giphyAttachments.isEmpty { + return .giphy + } + + // Images + let imageCount = message.imageAttachments.count if imageCount > 0 { return .photo(count: imageCount) } diff --git a/Sources/StreamChatSwiftUI/ChatMessageList/ReferenceMessageView/AttachmentPreviews/MessageImagePreviewView.swift b/Sources/StreamChatSwiftUI/ChatMessageList/ReferenceMessageView/AttachmentPreviews/MessageImagePreviewView.swift index b1cf41d43..3a35b3406 100644 --- a/Sources/StreamChatSwiftUI/ChatMessageList/ReferenceMessageView/AttachmentPreviews/MessageImagePreviewView.swift +++ b/Sources/StreamChatSwiftUI/ChatMessageList/ReferenceMessageView/AttachmentPreviews/MessageImagePreviewView.swift @@ -7,7 +7,6 @@ import SwiftUI /// Image attachment preview for messages. public struct MessageImagePreviewView: View { @Injected(\.tokens) private var tokens - @Injected(\.colors) private var colors private let url: URL private let size: CGFloat @@ -22,28 +21,13 @@ public struct MessageImagePreviewView: View { } public var body: some View { - StreamAsyncImage( - url: url, - thumbnailSize: CGSize(width: size, height: size) - ) { phase in - Group { - switch phase { - case .success(let image): - image - .resizable() - .aspectRatio(contentMode: .fill) - .frame(width: size, height: size) - .clipShape(RoundedRectangle(cornerRadius: tokens.radiusMd, style: .continuous)) - case .loading, .empty: - placeholder - } - } - } - } - - private var placeholder: some View { - RoundedRectangle(cornerRadius: tokens.radiusMd, style: .continuous) - .fill(Color(colors.borderCoreOpacity10)) - .frame(width: size, height: size) + LazyLoadingImage( + source: MediaAttachment(url: url, type: .image), + width: size, + height: size, + resize: true, + showVideoIcon: false + ) + .clipShape(RoundedRectangle(cornerRadius: tokens.radiusMd, style: .continuous)) } } diff --git a/Sources/StreamChatSwiftUI/ChatThreadList/ChatThreadListItem.swift b/Sources/StreamChatSwiftUI/ChatThreadList/ChatThreadListItem.swift index 13a8ff979..3ed4c5c39 100644 --- a/Sources/StreamChatSwiftUI/ChatThreadList/ChatThreadListItem.swift +++ b/Sources/StreamChatSwiftUI/ChatThreadList/ChatThreadListItem.swift @@ -309,14 +309,16 @@ struct ChatThreadListItemContentView: View { return HStack(spacing: -(overlap + borderWidth * 2)) { ForEach(Array(participantUsers.prefix(3).enumerated()), id: \.offset) { index, user in - UserAvatar( - user: user, - size: avatarSize, - showsIndicator: false, - showsBorder: false + factory.makeUserAvatarView( + options: UserAvatarViewOptions( + user: user, + size: avatarSize, + showsIndicator: false, + showsBorder: false + ) ) .padding(borderWidth) - .background(Circle().fill(colors.borderCoreOnDark.toColor)) + .background(Circle().fill(colors.borderCoreOnAccent.toColor)) .zIndex(Double(index)) } } diff --git a/Sources/StreamChatSwiftUI/ChatThreadList/ChatThreadListView.swift b/Sources/StreamChatSwiftUI/ChatThreadList/ChatThreadListView.swift index a58521606..6014bcfd1 100644 --- a/Sources/StreamChatSwiftUI/ChatThreadList/ChatThreadListView.swift +++ b/Sources/StreamChatSwiftUI/ChatThreadList/ChatThreadListView.swift @@ -56,7 +56,7 @@ public struct ChatThreadListView: View { if viewModel.isLoading { viewFactory.makeThreadListLoadingView(options: ThreadListLoadingViewOptions()) } else if viewModel.isEmpty { - viewFactory.makeNoThreadsView(options: NoThreadsViewOptions()) + viewFactory.makeEmptyThreadsView(options: EmptyThreadsViewOptions()) } else { ChatThreadListContentView( viewFactory: viewFactory, diff --git a/Sources/StreamChatSwiftUI/ChatThreadList/NoThreadsView.swift b/Sources/StreamChatSwiftUI/ChatThreadList/EmptyThreadsView.swift similarity index 78% rename from Sources/StreamChatSwiftUI/ChatThreadList/NoThreadsView.swift rename to Sources/StreamChatSwiftUI/ChatThreadList/EmptyThreadsView.swift index e07bba283..65a9c70bd 100644 --- a/Sources/StreamChatSwiftUI/ChatThreadList/NoThreadsView.swift +++ b/Sources/StreamChatSwiftUI/ChatThreadList/EmptyThreadsView.swift @@ -5,18 +5,18 @@ import SwiftUI /// Default SDK implementation for the view displayed when there are no threads available. -public struct NoThreadsView: View { +public struct EmptyThreadsView: View { @Injected(\.images) private var images public init() {} public var body: some View { - NoContentView( + EmptyContentView( image: images.noThreads, title: nil, description: L10n.Thread.NoContent.message, shouldRotateImage: false ) - .accessibilityIdentifier("NoThreadsView") + .accessibilityIdentifier("EmptyThreadsView") } } diff --git a/Sources/StreamChatSwiftUI/CommonViews/ActionBannerView.swift b/Sources/StreamChatSwiftUI/CommonViews/ActionBannerView.swift index a17184336..eee2a27e2 100644 --- a/Sources/StreamChatSwiftUI/CommonViews/ActionBannerView.swift +++ b/Sources/StreamChatSwiftUI/CommonViews/ActionBannerView.swift @@ -30,7 +30,7 @@ struct ActionBannerView: View { Spacer() } .padding(.all, 16) - .background(Color(colors.backgroundCoreSurface)) + .background(Color(colors.backgroundCoreSurfaceDefault)) } } } diff --git a/Sources/StreamChatSwiftUI/CommonViews/ActionItemView.swift b/Sources/StreamChatSwiftUI/CommonViews/ActionItemView.swift index 03d7323b0..04604a6e6 100644 --- a/Sources/StreamChatSwiftUI/CommonViews/ActionItemView.swift +++ b/Sources/StreamChatSwiftUI/CommonViews/ActionItemView.swift @@ -22,13 +22,13 @@ public struct ActionItemView: View { .customizable() .frame(width: 20, height: 18) .foregroundColor( - isDestructive ? Color(colors.alert) : Color(colors.textLowEmphasis) + isDestructive ? Color(colors.accentError) : Color(colors.textTertiary) ) Text(title) .font(boldTitle ? fonts.bodyBold : fonts.body) .foregroundColor( - isDestructive ? Color(colors.alert) : Color(colors.text) + isDestructive ? Color(colors.accentError) : Color(colors.textPrimary) ) Spacer() diff --git a/Sources/StreamChatSwiftUI/CommonViews/AlertBannerViewModifier.swift b/Sources/StreamChatSwiftUI/CommonViews/AlertBannerViewModifier.swift index bad925fa1..7567abf94 100644 --- a/Sources/StreamChatSwiftUI/CommonViews/AlertBannerViewModifier.swift +++ b/Sources/StreamChatSwiftUI/CommonViews/AlertBannerViewModifier.swift @@ -43,10 +43,10 @@ private struct AlertBannerViewModifier: ViewModifier { if isPresented { Text(title) .font(.body) - .foregroundColor(Color(colors.staticColorText)) + .foregroundColor(Color(colors.backgroundCoreElevation0)) .padding(.init(top: 4, leading: 16, bottom: 4, trailing: 16)) .frame(maxWidth: .infinity) - .background(Color(colors.textLowEmphasis)) + .background(Color(colors.textTertiary)) .transition(.move(edge: .top)) } } diff --git a/Sources/StreamChatSwiftUI/CommonViews/Avatars/AvatarIndicatorViewModifier.swift b/Sources/StreamChatSwiftUI/CommonViews/Avatars/AvatarIndicatorViewModifier.swift index f9a529283..170688a42 100644 --- a/Sources/StreamChatSwiftUI/CommonViews/Avatars/AvatarIndicatorViewModifier.swift +++ b/Sources/StreamChatSwiftUI/CommonViews/Avatars/AvatarIndicatorViewModifier.swift @@ -3,7 +3,6 @@ // import StreamChat -import StreamChatCommonUI import SwiftUI /// A type that represents the presence indicator on an avatar. diff --git a/Sources/StreamChatSwiftUI/CommonViews/Avatars/AvatarPreviews.swift b/Sources/StreamChatSwiftUI/CommonViews/Avatars/AvatarPreviews.swift index cb415f7ea..ac65990e5 100644 --- a/Sources/StreamChatSwiftUI/CommonViews/Avatars/AvatarPreviews.swift +++ b/Sources/StreamChatSwiftUI/CommonViews/Avatars/AvatarPreviews.swift @@ -108,6 +108,7 @@ import SwiftUI size: group.size, stackedPlaceholders: [], memberCount: 0, + directMessageChannel: false, indicator: .online ) .frame(width: AvatarPreviewConstants.columnWidth, height: AvatarPreviewConstants.rowHeight) @@ -122,6 +123,7 @@ import SwiftUI size: group.size, stackedPlaceholders: placeholders, memberCount: index < 4 ? index + 1 : 7, + directMessageChannel: false, indicator: .online ) .frame(width: AvatarPreviewConstants.columnWidth, height: AvatarPreviewConstants.rowHeight) diff --git a/Sources/StreamChatSwiftUI/CommonViews/Avatars/AvatarSize.swift b/Sources/StreamChatSwiftUI/CommonViews/Avatars/AvatarSize.swift index e083dec9e..ccbcbabbb 100644 --- a/Sources/StreamChatSwiftUI/CommonViews/Avatars/AvatarSize.swift +++ b/Sources/StreamChatSwiftUI/CommonViews/Avatars/AvatarSize.swift @@ -3,7 +3,6 @@ // import StreamChat -import StreamChatCommonUI import SwiftUI /// Standard sizes for avatar views. diff --git a/Sources/StreamChatSwiftUI/CommonViews/Avatars/AvatarStack.swift b/Sources/StreamChatSwiftUI/CommonViews/Avatars/AvatarStack.swift index 5e59f6451..2df096289 100644 --- a/Sources/StreamChatSwiftUI/CommonViews/Avatars/AvatarStack.swift +++ b/Sources/StreamChatSwiftUI/CommonViews/Avatars/AvatarStack.swift @@ -3,7 +3,6 @@ // import StreamChat -import StreamChatCommonUI import SwiftUI /// A view that renders a horizontal row of overlapping user avatars. @@ -65,6 +64,6 @@ public struct AvatarStack: View { private func avatarView(url: URL?, initials: String, outerBorder: Bool) -> some View { UserAvatar(url: url, initials: initials, size: size, indicator: .none, showsBorder: false) - .overlay(outerBorder ? Circle().inset(by: -1).stroke(colors.borderCoreOnDark.toColor, lineWidth: 2) : nil) + .overlay(outerBorder ? Circle().inset(by: -1).stroke(colors.borderCoreInverse.toColor, lineWidth: 2) : nil) } } diff --git a/Sources/StreamChatSwiftUI/CommonViews/Avatars/ChannelAvatar.swift b/Sources/StreamChatSwiftUI/CommonViews/Avatars/ChannelAvatar.swift index 1ec8287b8..3132baefc 100644 --- a/Sources/StreamChatSwiftUI/CommonViews/Avatars/ChannelAvatar.swift +++ b/Sources/StreamChatSwiftUI/CommonViews/Avatars/ChannelAvatar.swift @@ -3,7 +3,6 @@ // import StreamChat -import StreamChatCommonUI import SwiftUI /// A view that renders a channel avatar, merging multiple member images when needed. @@ -11,6 +10,7 @@ public struct ChannelAvatar: View { @Injected(\.colors) var colors @Injected(\.utils) var utils + let directMessageChannel: Bool let indicator: AvatarIndicator let memberCount: Int let size: CGFloat @@ -26,14 +26,13 @@ public struct ChannelAvatar: View { /// - Parameters: /// - channel: The channel whose avatar to display. /// - size: The width and height of the avatar. - /// - showsIndicator: A Boolean value that indicates whether to show the - /// online status for direct message channels. Defaults to `false`. + /// - indicator: The presence indicator to display (e.g. `.online`, `.none`). /// - showsBorder: A Boolean value that indicates whether to show a circular /// border around the avatar. Defaults to `true`. public init( channel: ChatChannel, size: CGFloat, - showsIndicator: Bool = false, + indicator: AvatarIndicator = .none, showsBorder: Bool = true ) { self.init( @@ -41,7 +40,8 @@ public struct ChannelAvatar: View { size: size, stackedPlaceholders: channel.avatarUsers.map { ($0.imageURL, UserAvatar.initials(from: $0.name ?? "")) }, memberCount: channel.memberCount, - indicator: showsIndicator ? channel.avatarIndicator : .none, + directMessageChannel: channel.isDirectMessageChannel, + indicator: indicator, showsBorder: showsBorder ) } @@ -60,6 +60,8 @@ public struct ChannelAvatar: View { /// used for the stacked layout when `url` is `nil`. /// - memberCount: The total number of members in the channel, used to /// compute the overflow badge count. + /// - directMessageChannel: A Boolean value that indicates whether the + /// channel is a direct message channel. /// - indicator: The presence indicator to display. Defaults to no indicator. /// - showsBorder: A Boolean value that indicates whether to show a circular /// border around the avatar. Defaults to `true`. @@ -68,10 +70,12 @@ public struct ChannelAvatar: View { size: CGFloat, stackedPlaceholders: [(url: URL?, initials: String)], memberCount: Int, + directMessageChannel: Bool, indicator: AvatarIndicator = .none, showsBorder: Bool = true ) { self.indicator = indicator + self.directMessageChannel = directMessageChannel self.memberCount = memberCount self.showsBorder = showsBorder self.size = size @@ -86,18 +90,26 @@ public struct ChannelAvatar: View { content: { phase in Group { switch phase { - case .success(let image): - image + case .success(let result): + Image(uiImage: result.image) .resizable() .aspectRatio(contentMode: .fill) - .background(colors.backgroundCoreApp.toColor) + .background(colors.borderCoreInverse.toColor) .compositingGroup() .overlay( - showsBorder ? Circle().strokeBorder(colors.borderCoreOpacity10.toColor, lineWidth: 1) : nil + showsBorder ? Circle().strokeBorder(colors.borderCoreOpacitySubtle.toColor, lineWidth: 1) : nil ) .clipShape(Circle()) - case .empty, .loading: - if size >= AvatarSize.large, !stackedPlaceholders.isEmpty { + case .empty, .loading, .error: + if directMessageChannel, memberCount == 2, let avatar = stackedPlaceholders.first { + UserAvatar( + url: avatar.url, + initials: avatar.initials, + size: size, + indicator: indicator, + showsBorder: showsBorder + ) + } else if size >= AvatarSize.large, !stackedPlaceholders.isEmpty { StackedPlaceholderView( users: stackedPlaceholders, size: size, @@ -112,7 +124,6 @@ public struct ChannelAvatar: View { } ) .frame(width: size, height: size) - .avatarIndicator(indicator, size: size) .accessibilityIdentifier("ChannelAvatar") } @@ -294,13 +305,13 @@ private extension ChannelAvatar { showsBorder: false ) .padding(outerBorderWidth) - .background(Circle().fill(colors.borderCoreOnDark.toColor)) + .background(Circle().fill(colors.borderCoreInverse.toColor)) } } } -private extension ChatChannel { - @MainActor var avatarUsers: [ChatUser] { +extension ChatChannel { + @MainActor fileprivate var avatarUsers: [ChatUser] { let currentUserId = InjectedValues[\.chatClient].currentUserId return Array( lastActiveMembers @@ -314,10 +325,11 @@ private extension ChatChannel { ) } - @MainActor var avatarIndicator: AvatarIndicator { + /// By default online indicator is only shown for 1:1 direct message channels. + @MainActor var defaultAvatarIndicator: AvatarIndicator { guard isDirectMessageChannel, memberCount == 2 else { return .none } let currentUserId = InjectedValues[\.chatClient].currentUserId guard let otherMember = lastActiveMembers.first(where: { $0.id != currentUserId }) else { return .none } - return otherMember.isOnline ? .online : .offline + return otherMember.isOnline ? .online : .none } } diff --git a/Sources/StreamChatSwiftUI/CommonViews/Avatars/UserAvatar.swift b/Sources/StreamChatSwiftUI/CommonViews/Avatars/UserAvatar.swift index d1606d50e..409b9990d 100644 --- a/Sources/StreamChatSwiftUI/CommonViews/Avatars/UserAvatar.swift +++ b/Sources/StreamChatSwiftUI/CommonViews/Avatars/UserAvatar.swift @@ -3,7 +3,6 @@ // import StreamChat -import StreamChatCommonUI import SwiftUI /// A view that renders a user avatar with optional presence indicator. @@ -21,21 +20,20 @@ public struct UserAvatar: View { /// - Parameters: /// - user: The user whose avatar to display. /// - size: The width and height of the avatar. - /// - showsIndicator: A Boolean value that indicates whether to show the - /// user's online status. Defaults to `false`. + /// - indicator: The presence indicator to display (e.g. `.online`, `.offline`, `.none`). /// - showsBorder: A Boolean value that indicates whether to show a circular /// border around the avatar. Defaults to `true`. public init( user: ChatUser, size: CGFloat, - showsIndicator: Bool = false, + indicator: AvatarIndicator = .none, showsBorder: Bool = true ) { self.init( url: user.imageURL, initials: Self.initials(from: user.name ?? ""), size: size, - indicator: showsIndicator ? (user.isOnline ? .online : .offline) : .none, + indicator: indicator, showsBorder: showsBorder ) } @@ -70,16 +68,16 @@ public struct UserAvatar: View { content: { phase in Group { switch phase { - case .success(let image): - image + case .success(let result): + Image(uiImage: result.image) .resizable() .aspectRatio(contentMode: .fill) - .background(colors.backgroundCoreApp.toColor) + .background(colors.borderCoreInverse.toColor) .compositingGroup() .overlay( - showsBorder ? Circle().strokeBorder(colors.borderCoreOpacity10.toColor, lineWidth: 1) : nil + showsBorder ? Circle().strokeBorder(colors.borderCoreOpacitySubtle.toColor, lineWidth: 1) : nil ) - case .loading, .empty: + case .loading, .empty, .error: PlaceholderView(initials: initials, size: size) } } diff --git a/Sources/StreamChatSwiftUI/CommonViews/BadgeCountView.swift b/Sources/StreamChatSwiftUI/CommonViews/BadgeCountView.swift index 56a4c87df..d020ed812 100644 --- a/Sources/StreamChatSwiftUI/CommonViews/BadgeCountView.swift +++ b/Sources/StreamChatSwiftUI/CommonViews/BadgeCountView.swift @@ -3,7 +3,6 @@ // import StreamChat -import StreamChatCommonUI import SwiftUI /// A pill-shaped badge that shows the number of additional avatars not displayed. diff --git a/Sources/StreamChatSwiftUI/CommonViews/BadgeNotificationView.swift b/Sources/StreamChatSwiftUI/CommonViews/BadgeNotificationView.swift index bc9bea97a..8b2e37126 100644 --- a/Sources/StreamChatSwiftUI/CommonViews/BadgeNotificationView.swift +++ b/Sources/StreamChatSwiftUI/CommonViews/BadgeNotificationView.swift @@ -2,7 +2,6 @@ // Copyright © 2026 Stream.io Inc. All rights reserved. // -import StreamChatCommonUI import SwiftUI public enum BadgeNotificationType: String, CaseIterable, Sendable { diff --git a/Sources/StreamChatSwiftUI/CommonViews/NoContentView.swift b/Sources/StreamChatSwiftUI/CommonViews/EmptyContentView.swift similarity index 98% rename from Sources/StreamChatSwiftUI/CommonViews/NoContentView.swift rename to Sources/StreamChatSwiftUI/CommonViews/EmptyContentView.swift index 47526241a..82bd8a63f 100644 --- a/Sources/StreamChatSwiftUI/CommonViews/NoContentView.swift +++ b/Sources/StreamChatSwiftUI/CommonViews/EmptyContentView.swift @@ -5,7 +5,7 @@ import SwiftUI /// Default view displayed when there's no content for different types of data (channels, messages, media). -struct NoContentView: View { +struct EmptyContentView: View { @Injected(\.fonts) private var fonts @Injected(\.colors) private var colors diff --git a/Sources/StreamChatSwiftUI/CommonViews/LoadingSpinnerView.swift b/Sources/StreamChatSwiftUI/CommonViews/LoadingSpinnerView.swift index aa9af6459..1a1aeb733 100644 --- a/Sources/StreamChatSwiftUI/CommonViews/LoadingSpinnerView.swift +++ b/Sources/StreamChatSwiftUI/CommonViews/LoadingSpinnerView.swift @@ -7,52 +7,75 @@ import SwiftUI /// Predefined sizes for ``LoadingSpinnerView``. public enum LoadingSpinnerSize: Sendable { @MainActor public static var large: CGFloat = 32 + @MainActor public static var medium: CGFloat = 24 @MainActor public static var small: CGFloat = 20 @MainActor public static var extraSmall: CGFloat = 16 } -/// A circular spinner badge used as a loading indicator over media content. +/// A circular spinner badge used as a loading or progress indicator. /// -/// Renders a white circular badge with a border and an animated arc spinner -/// inside. The spinner consists of a light gray track circle with a blue -/// accent arc that rotates continuously. +/// Renders a white circular badge with a track circle and accent arc. +/// +/// - When ``progress`` is `nil` the arc rotates continuously (indeterminate). +/// - When ``progress`` is set (0…1) the arc length reflects the value (determinate). public struct LoadingSpinnerView: View { @Injected(\.colors) private var colors let size: CGFloat let bordered: Bool + let progress: Double? @State private var isAnimating = false - public init(size: CGFloat, bordered: Bool) { + /// Creates a loading spinner. + /// - Parameters: + /// - size: The diameter of the badge. + /// - bordered: Whether to draw a white border ring outside the badge. + /// - progress: `nil` for an indeterminate spinner, or a value in 0…1 for determinate progress. + public init(size: CGFloat, bordered: Bool = false, progress: Double? = nil) { self.size = size self.bordered = bordered + self.progress = progress } public var body: some View { ZStack { Circle() - .fill(Color(colors.backgroundElevationElevation0)) + .fill(Color(colors.backgroundCoreElevation0)) .overlay( Circle() .inset(by: -1) - .stroke(colors.backgroundElevationElevation0.toColor, lineWidth: bordered ? 2 : 0) + .stroke(colors.backgroundCoreElevation0.toColor, lineWidth: bordered ? 2 : 0) ) Circle() .stroke(Color(colors.borderCoreDefault), lineWidth: strokeWidth) .frame(width: spinnerDiameter, height: spinnerDiameter) - Circle() - .trim(from: 0, to: 0.25) - .stroke( - Color(colors.accentPrimary), - style: StrokeStyle(lineWidth: strokeWidth, lineCap: .round) - ) - .frame(width: spinnerDiameter, height: spinnerDiameter) - .rotationEffect(.degrees(isAnimating ? 360 : 0)) - .animation( - .linear(duration: 1).repeatForever(autoreverses: false), - value: isAnimating - ) + + if let progress { + Circle() + .trim(from: 0, to: CGFloat(min(max(progress, 0), 1))) + .stroke( + Color(colors.accentPrimary), + style: StrokeStyle(lineWidth: strokeWidth, lineCap: .round) + ) + .frame(width: spinnerDiameter, height: spinnerDiameter) + .rotationEffect(.degrees(-90)) + .animation(.easeInOut(duration: 0.3), value: progress) + } else { + Circle() + .trim(from: 0, to: 0.25) + .stroke( + Color(colors.accentPrimary), + style: StrokeStyle(lineWidth: strokeWidth, lineCap: .round) + ) + .frame(width: spinnerDiameter, height: spinnerDiameter) + .rotationEffect(.degrees(isAnimating ? 360 : 0)) + .animation( + .linear(duration: 1) + .repeatForever(autoreverses: false), + value: isAnimating + ) + } } .frame(width: size, height: size) .onAppear { isAnimating = true } diff --git a/Sources/StreamChatSwiftUI/CommonViews/LoadingView.swift b/Sources/StreamChatSwiftUI/CommonViews/LoadingView.swift index b843346d4..30d288c13 100644 --- a/Sources/StreamChatSwiftUI/CommonViews/LoadingView.swift +++ b/Sources/StreamChatSwiftUI/CommonViews/LoadingView.swift @@ -44,7 +44,7 @@ struct RedactedChannelCell: View { private let circleSize: CGFloat = 48 private var redactedColor: Color { - Color(colors.disabledColorForColor(colors.text)) + Color(colors.backgroundCoreSurfaceStrong) } public var body: some View { diff --git a/Sources/StreamChatSwiftUI/CommonViews/MediaViewerHeader.swift b/Sources/StreamChatSwiftUI/CommonViews/MediaViewerHeader.swift index ac5c642da..4108cdae6 100644 --- a/Sources/StreamChatSwiftUI/CommonViews/MediaViewerHeader.swift +++ b/Sources/StreamChatSwiftUI/CommonViews/MediaViewerHeader.swift @@ -46,7 +46,7 @@ struct MediaViewerHeader: View { private var closeImageColor: Color { // Note that default design uses `text` color - guard colors.navigationBarTintColor != colors.accentPrimary else { return Color(colors.text) } + guard colors.navigationBarTintColor != colors.accentPrimary else { return Color(colors.textPrimary) } return Color(colors.navigationBarTintColor) } } diff --git a/Sources/StreamChatSwiftUI/CommonViews/NukeImageLoader.swift b/Sources/StreamChatSwiftUI/CommonViews/NukeImageLoader.swift new file mode 100644 index 000000000..74b690811 --- /dev/null +++ b/Sources/StreamChatSwiftUI/CommonViews/NukeImageLoader.swift @@ -0,0 +1,135 @@ +// +// Copyright © 2026 Stream.io Inc. All rights reserved. +// + +import StreamChat +import UIKit + +/// Internal helper that bridges the vendored Nuke pipeline with CDN requester +/// transformations. Isolates all Nuke-specific code so views remain agnostic +/// of the underlying image loading library. +enum NukeImageLoader { + // MARK: - Synchronous Cache Lookup + + /// Synchronous lookup that queries Nuke's memory cache using a previously + /// stored ``CDNRequest/cachingKey``. + /// + /// After the first load for a given `(url, resize)` pair, the CDN + /// requester's `cachingKey` is remembered. Because the `cachingKey` + /// already encodes all resize parameters, it is the only identifier + /// needed to look up Nuke's memory cache (via `imageIdKey`). + /// + /// Returns `nil` when the image has never been loaded (no stored key) + /// or when Nuke has evicted it from memory. + static func cachedResult(url: URL, resize: ImageResize?) -> StreamAsyncImageResult? { + let key = inputKey(url: url, resize: resize) as NSString + guard let storedKey = cachingKeyMap.object(forKey: key)?.value else { return nil } + + let request = ImageRequest( + url: url, + processors: makeProcessors(resize: resize), + userInfo: [ImageRequest.UserInfoKey.imageIdKey: storedKey as Any] + ) + guard let container = ImagePipeline.shared.cache[request] else { return nil } + return StreamAsyncImageResult( + image: container.image, + isAnimated: container.type == .gif, + animatedImageData: container.data + ) + } + + // MARK: - Async Loading + + /// Loads an image from the given URL, applying CDN transformations and + /// optional resize processing. + /// + /// Checks Nuke's memory cache (using the ``CDNRequest/cachingKey``) after + /// CDN transformation. If the image is already cached, it returns + /// immediately without a network request. Otherwise, calls `onCacheMiss` + /// (so callers can show a loading state) and fetches from the network. + /// + /// Uses Nuke's async `ImageTask.response` which propagates Swift + /// concurrency cancellation to the underlying download automatically. + @MainActor + static func loadImage( + url: URL, + resize: ImageResize?, + cdnRequester: CDNRequester, + onCacheMiss: @MainActor () -> Void = {} + ) async throws -> StreamAsyncImageResult { + let cdnResize = resize.map { + CDNImageResize(width: $0.width, height: $0.height, resizeMode: $0.mode.value, crop: $0.mode.cropValue) + } + let cdnRequest = try await cdnRequester.imageRequest(for: url, options: .init(resize: cdnResize)) + + if let cachingKey = cdnRequest.cachingKey { + let key = inputKey(url: url, resize: resize) as NSString + cachingKeyMap.setObject(StringBox(cachingKey), forKey: key) + } + + let processors = makeProcessors(resize: resize) + let userInfo = cdnRequest.cachingKey.map { [ImageRequest.UserInfoKey.imageIdKey: $0 as Any] } + + let cacheRequest = ImageRequest( + url: cdnRequest.url, + processors: processors, + userInfo: userInfo + ) + + if let container = ImagePipeline.shared.cache[cacheRequest] { + return StreamAsyncImageResult( + image: container.image, + isAnimated: container.type == .gif, + animatedImageData: container.data + ) + } + + onCacheMiss() + + var urlRequest = URLRequest(url: cdnRequest.url) + if let headers = cdnRequest.headers { + for (key, value) in headers { + urlRequest.setValue(value, forHTTPHeaderField: key) + } + } + + let networkRequest = ImageRequest( + urlRequest: urlRequest, + processors: processors, + userInfo: userInfo + ) + + let task = ImagePipeline.shared.imageTask(with: networkRequest) + let response = try await task.response + return StreamAsyncImageResult( + image: response.image, + isAnimated: response.container.type == .gif, + animatedImageData: response.container.data + ) + } + + // MARK: - Private + + /// Maps `(url + resize)` → `cachingKey` so ``cachedResult(url:resize:)`` + /// can query Nuke's memory cache using the correct `imageIdKey`. + /// Populated on the first successful CDN transform for each pair. + private nonisolated(unsafe) static let cachingKeyMap = NSCache() + + private static func inputKey(url: URL, resize: ImageResize?) -> String { + let urlPart = url.absoluteString + guard let resize else { return urlPart } + return "\(urlPart)-\(resize.width)x\(resize.height)-\(resize.mode.value)" + } + + private static func makeProcessors(resize: ImageResize?) -> [any ImageProcessing] { + guard let resize else { return [] } + let size = CGSize(width: resize.width, height: resize.height) + guard size != .zero else { return [] } + return [ImageProcessors.Resize(size: size)] + } +} + +private final class StringBox: @unchecked Sendable { + let value: String + init(_ value: String) { self.value = value } +} diff --git a/Sources/StreamChatSwiftUI/CommonViews/PlayButtonOverlay.swift b/Sources/StreamChatSwiftUI/CommonViews/PlayButtonOverlay.swift index 86488e572..6ecadaf4f 100644 --- a/Sources/StreamChatSwiftUI/CommonViews/PlayButtonOverlay.swift +++ b/Sources/StreamChatSwiftUI/CommonViews/PlayButtonOverlay.swift @@ -2,7 +2,6 @@ // Copyright © 2026 Stream.io Inc. All rights reserved. // -import StreamChatCommonUI import SwiftUI /// Play button overlay for video attachment previews. @@ -16,12 +15,12 @@ public struct PlayButtonOverlay: View { public var body: some View { ZStack { Circle() - .fill(Color(colors.controlPlayControlBackground)) + .fill(Color(colors.controlPlayButtonBackground)) .frame(width: playButtonSize, height: playButtonSize) Image(uiImage: images.attachmentPlayOverlayIcon) .renderingMode(.template) - .foregroundColor(Color(colors.controlPlayControlIcon)) + .foregroundColor(Color(colors.controlPlayButtonIcon)) } .accessibilityHidden(true) } diff --git a/Sources/StreamChatSwiftUI/CommonViews/RadioCheckView.swift b/Sources/StreamChatSwiftUI/CommonViews/RadioCheckView.swift index 731b77cda..93804b531 100644 --- a/Sources/StreamChatSwiftUI/CommonViews/RadioCheckView.swift +++ b/Sources/StreamChatSwiftUI/CommonViews/RadioCheckView.swift @@ -2,7 +2,6 @@ // Copyright © 2026 Stream.io Inc. All rights reserved. // -import StreamChatCommonUI import SwiftUI /// A circular radio/checkbox component with selected and unselected states. @@ -50,21 +49,21 @@ struct RadioCheckView: View { if isDisabled { return colors.borderUtilityDisabled } - return borderColorOverride ?? colors.controlRadiocheckBorder + return borderColorOverride ?? colors.controlRadioCheckBorder } private var selectedBackgroundColor: UIColor { if isDisabled { - return colors.backgroundCoreDisabled + return colors.backgroundUtilityDisabled } - return colors.controlRadiocheckBackgroundSelected + return colors.controlRadioCheckBackgroundSelected } private var selectedIconColor: UIColor { if isDisabled { return colors.textDisabled } - return colors.controlRadiocheckIconSelected + return colors.controlRadioCheckIcon } } diff --git a/Sources/StreamChatSwiftUI/CommonViews/RetryBadgeView.swift b/Sources/StreamChatSwiftUI/CommonViews/RetryBadgeView.swift new file mode 100644 index 000000000..586239db7 --- /dev/null +++ b/Sources/StreamChatSwiftUI/CommonViews/RetryBadgeView.swift @@ -0,0 +1,39 @@ +// +// Copyright © 2026 Stream.io Inc. All rights reserved. +// + +import SwiftUI + +/// A circular badge shown when an attachment upload or download fails. +public struct RetryBadgeView: View { + @Injected(\.colors) private var colors + @Injected(\.tokens) private var tokens + + private let size: CGFloat = 32 + private let borderWidth: CGFloat = 2 + private var iconSize: CGFloat { + tokens.iconSizeSm + } + + public init() {} + + public var body: some View { + ZStack { + Circle() + .fill(Color(colors.accentError)) + .overlay( + Circle() + .inset(by: -borderWidth / 2) + .stroke(Color(colors.backgroundCoreElevation0), lineWidth: borderWidth) + ) + Image(systemName: "arrow.trianglehead.clockwise.rotate.90") + .resizable() + .scaledToFit() + .frame(width: iconSize, height: iconSize) + .font(Font.system(size: iconSize, weight: .bold)) + .foregroundColor(Color(colors.backgroundCoreElevation0)) + } + .frame(width: size, height: size) + .accessibilityIdentifier("RetryBadgeView") + } +} diff --git a/Sources/StreamChatSwiftUI/CommonViews/SearchBar.swift b/Sources/StreamChatSwiftUI/CommonViews/SearchBar.swift index c816d1f24..a9af4ba63 100644 --- a/Sources/StreamChatSwiftUI/CommonViews/SearchBar.swift +++ b/Sources/StreamChatSwiftUI/CommonViews/SearchBar.swift @@ -54,7 +54,7 @@ struct SearchBar: View, KeyboardReadable { .clipShape(RoundedRectangle(cornerRadius: tokens.radiusMax, style: .continuous)) .overlay( RoundedRectangle(cornerRadius: tokens.radiusMax, style: .continuous) - .stroke(Color(colors.inputBorderDefault), lineWidth: 1) + .stroke(Color(colors.borderCoreDefault), lineWidth: 1) ) .transition(.identity) .animation(.easeInOut, value: isEditing) @@ -77,7 +77,7 @@ struct SearchBar: View, KeyboardReadable { .padding(.top, tokens.spacingMd) .padding(.bottom, tokens.spacingXs) .padding(.horizontal, tokens.spacingMd) - .background(Color(colors.backgroundElevationElevation0)) + .background(Color(colors.backgroundCoreElevation0)) .onReceive(keyboardWillChangePublisher) { shown in if shown { isEditing = true diff --git a/Sources/StreamChatSwiftUI/CommonViews/SelectionBadgeView.swift b/Sources/StreamChatSwiftUI/CommonViews/SelectionBadgeView.swift index 37fbb6e54..b615f87dc 100644 --- a/Sources/StreamChatSwiftUI/CommonViews/SelectionBadgeView.swift +++ b/Sources/StreamChatSwiftUI/CommonViews/SelectionBadgeView.swift @@ -2,7 +2,6 @@ // Copyright © 2026 Stream.io Inc. All rights reserved. // -import StreamChatCommonUI import SwiftUI /// A circular selection indicator for gallery view items. @@ -21,14 +20,14 @@ public struct SelectionBadgeView: View { ZStack { if isSelected { Circle() - .fill(Color(colors.controlRadiocheckBackgroundSelected)) + .fill(Color(colors.controlRadioCheckBackgroundSelected)) .overlay( borderView ) Image(uiImage: images.selectionBadgeIcon) .customizable() .frame(width: tokens.iconSizeXs, height: tokens.iconSizeXs) - .foregroundColor(Color(colors.controlRadiocheckIconSelected)) + .foregroundColor(Color(colors.controlRadioCheckIcon)) } else { borderView } diff --git a/Sources/StreamChatSwiftUI/CommonViews/SnackBarView.swift b/Sources/StreamChatSwiftUI/CommonViews/SnackBarView.swift index 0d9cfe623..e2247b255 100644 --- a/Sources/StreamChatSwiftUI/CommonViews/SnackBarView.swift +++ b/Sources/StreamChatSwiftUI/CommonViews/SnackBarView.swift @@ -34,7 +34,7 @@ public struct SnackBarView: View { } .padding(.horizontal, tokens.spacingMd) .padding(.vertical, tokens.spacingSm) - .foregroundColor(Color(colors.textOnDark)) + .foregroundColor(Color(colors.textOnInverse)) .background(Color(colors.backgroundCoreInverse)) .clipShape(Capsule()) .shadow( diff --git a/Sources/StreamChatSwiftUI/CommonViews/StreamAsyncImage.swift b/Sources/StreamChatSwiftUI/CommonViews/StreamAsyncImage.swift index d9d79c6e6..6d77e7854 100644 --- a/Sources/StreamChatSwiftUI/CommonViews/StreamAsyncImage.swift +++ b/Sources/StreamChatSwiftUI/CommonViews/StreamAsyncImage.swift @@ -6,79 +6,160 @@ import StreamChat import StreamChatCommonUI import SwiftUI -/// A view that loads an image asynchronously and renders content based -/// on the current loading phase. -public struct StreamAsyncImage: View { - @Injected(\.utils) var utils - - let thumbnailSize: CGSize - let url: URL? - @ViewBuilder let content: (StreamAsyncImagePhase) -> ImageContent - @State private var phase = StreamAsyncImagePhase.loading - - /// Loads an image from the given URL and builds a view based on the - /// loading state. - /// - /// When `url` is `nil` the phase is set to ``StreamAsyncImagePhase/empty`` - /// immediately without performing a network request. +/// A view that loads an image asynchronously using the SDK's ``MediaLoader`` +/// and ``CDNRequester``, then renders content based on the current loading phase. +/// +/// This is the single image-loading view for the SwiftUI SDK. It handles: +/// - CDN requester URL transformation (signing, headers, caching keys) +/// - Optional resize parameters for server-side and client-side resizing +/// - Animated image (GIF) data passthrough +/// - Cancellation on disappear +/// +/// ```swift +/// StreamAsyncImage(url: imageURL) { phase in +/// switch phase { +/// case .success(let result): +/// Image(uiImage: result.image) +/// .resizable() +/// case .loading: +/// ProgressView() +/// case .empty, .error: +/// Color.gray +/// } +/// } +/// ``` +@MainActor +public struct StreamAsyncImage: View { + private let url: URL? + private let resize: ImageResize? + private let content: (StreamAsyncImagePhase) -> Content + + /// Creates an async image view. /// /// - Parameters: - /// - url: The URL of the image to load, or `nil` if no image is available. - /// - thumbnailSize: The requested thumbnail dimensions used by the image CDN. - /// - content: A closure that takes the current loading phase and returns - /// the view to display. + /// - url: The image URL, or `nil` for the empty phase. + /// - resize: Optional resize applied both server-side (via CDN requester) and client-side. + /// - content: A closure that receives the current phase and returns a view. public init( url: URL?, - thumbnailSize: CGSize, - content: @escaping (StreamAsyncImagePhase) -> ImageContent + resize: ImageResize? = nil, + @ViewBuilder content: @escaping (StreamAsyncImagePhase) -> Content ) { self.url = url - self.thumbnailSize = thumbnailSize + self.resize = resize self.content = content } - + public var body: some View { - content(phase) - .compatibility.task(id: url?.absoluteString ?? "") { @MainActor [imageCDN, imageLoader, url] in - guard let url else { - phase = .empty - return - } - let images = await imageLoader.loadImages( - from: [url].compactMap { $0 }, - placeholders: [], - loadThumbnails: true, - thumbnailSize: thumbnailSize, - imageCDN: imageCDN - ) - if let image = images.first { - phase = .success(Image(uiImage: image)) - } else { - phase = .empty - } + let initialPhase: StreamAsyncImagePhase = { + guard let url else { return .empty } + if let cached = NukeImageLoader.cachedResult(url: url, resize: resize) { + return .success(cached) } + return .loading + }() + StreamAsyncImageBody( + url: url, + resize: resize, + initialPhase: initialPhase, + content: content + ) } - - var imageLoader: ImageLoading { utils.imageLoader } - var imageCDN: ImageCDN { utils.imageCDN } } +/// Private inner view that owns the loading state. +/// +/// Separated from ``StreamAsyncImage`` so the public struct stays +/// lightweight during scrolling (no `@State`, no DI resolution in `init`). +/// The initial phase is resolved by the outer view via a synchronous Nuke +/// cache lookup. All subsequent loading runs asynchronously through `.task`. +@MainActor +private struct StreamAsyncImageBody: View { + @Injected(\.utils) private var utils + + let url: URL? + let resize: ImageResize? + let initialPhase: StreamAsyncImagePhase + let content: (StreamAsyncImagePhase) -> Content + + @State private var phase: StreamAsyncImagePhase? + + var body: some View { + content(phase ?? initialPhase) + .compatibility.task(id: taskIdentity) { @MainActor in + await loadImage() + } + } + + private var taskIdentity: String { + let urlPart = url?.absoluteString ?? "" + guard let resize else { return urlPart } + return "\(urlPart)-\(resize.width)x\(resize.height)-\(resize.mode.value)" + } + + @MainActor + private func loadImage() async { + phase = nil + guard let url else { + phase = .empty + return + } + + do { + let result = try await NukeImageLoader.loadImage( + url: url, + resize: resize, + cdnRequester: utils.cdnRequester, + onCacheMiss: { phase = .loading } + ) + phase = .success(result) + } catch { + if !(error is CancellationError) { + phase = .error(error) + } + } + } +} + +// MARK: - Convenience Initializers + +extension StreamAsyncImage { + /// Creates an async image view with a thumbnail size for avatar-style loading. + public init( + url: URL?, + thumbnailSize: CGSize, + @ViewBuilder content: @escaping (StreamAsyncImagePhase) -> Content + ) { + self.init(url: url, resize: ImageResize(thumbnailSize), content: content) + } +} + +// MARK: - Phase & Result + /// The current loading state for ``StreamAsyncImage``. -public enum StreamAsyncImagePhase: Sendable, Equatable { - /// A successfully loaded image. - /// - /// The associated `Image` value represents the loaded image ready for display. - case success(Image) - +public enum StreamAsyncImagePhase { + /// The image loaded successfully. + case success(StreamAsyncImageResult) /// The image is currently loading. - /// - /// This is the initial phase while the image loader is fetching the image. - /// Use this state to display a loading placeholder or progress indicator. case loading - - /// No image is available. - /// - /// This phase occurs when the URL is `nil` or the image fails to load. - /// Use this state to display a placeholder or fallback content. + /// No image is available (nil URL). case empty + /// The load failed with an error. + case error(Error) + + /// The loaded image, if available. + public var image: Image? { + guard case .success(let result) = self else { return nil } + return Image(uiImage: result.image) + } +} + +/// The result of a successfully loaded image. +public struct StreamAsyncImageResult { + /// The loaded image. + public let image: UIImage + /// Whether the image is an animated format (e.g. GIF). + public let isAnimated: Bool + /// The raw image data for animated rendering. `nil` for static images. + public let animatedImageData: Data? } diff --git a/Sources/StreamChatSwiftUI/CommonViews/StreamButton.swift b/Sources/StreamChatSwiftUI/CommonViews/StreamButton.swift index 7c578b84a..d1a0bd024 100644 --- a/Sources/StreamChatSwiftUI/CommonViews/StreamButton.swift +++ b/Sources/StreamChatSwiftUI/CommonViews/StreamButton.swift @@ -2,7 +2,6 @@ // Copyright © 2026 Stream.io Inc. All rights reserved. // -import StreamChatCommonUI import SwiftUI struct StreamButton: View { @@ -222,7 +221,7 @@ struct StreamButtonStyle: ButtonStyle { private var backgroundColor: UIColor { if !isEnabled { - return style == .solid || style == .liquidGlass ? colors.backgroundCoreDisabled : .clear + return style == .solid || style == .liquidGlass ? colors.backgroundUtilityDisabled : .clear } switch style { @@ -254,8 +253,8 @@ struct StreamButtonStyle: ButtonStyle { private func interactionOverlayColor(isPressed: Bool) -> UIColor? { guard isEnabled else { return nil } - if isPressed { return colors.backgroundCorePressed } - if isSelected { return colors.backgroundCoreSelected } + if isPressed { return colors.backgroundUtilityPressed } + if isSelected { return colors.backgroundUtilitySelected } return nil } @@ -270,7 +269,7 @@ struct StreamButtonStyle: ButtonStyle { } } - private struct SizeMetrics { + @MainActor private struct SizeMetrics { let horizontalPaddingWithLabel: CGFloat let horizontalPaddingIconOnly: CGFloat let verticalPadding: CGFloat @@ -301,7 +300,7 @@ struct StreamButtonStyle: ButtonStyle { } } -private extension StreamButtonRole { +@MainActor private extension StreamButtonRole { func backgroundColor(colors: Appearance.ColorPalette) -> UIColor { switch self { case .primary: diff --git a/Sources/StreamChatSwiftUI/CommonViews/TypingIndicatorView.swift b/Sources/StreamChatSwiftUI/CommonViews/TypingIndicatorView.swift index dcf2711e6..b5789bfa7 100644 --- a/Sources/StreamChatSwiftUI/CommonViews/TypingIndicatorView.swift +++ b/Sources/StreamChatSwiftUI/CommonViews/TypingIndicatorView.swift @@ -3,7 +3,6 @@ // import StreamChat -import StreamChatCommonUI import SwiftUI /// View shown in the message list when other users are typing. diff --git a/Sources/StreamChatSwiftUI/CommonViews/VideoPlayIndicatorView.swift b/Sources/StreamChatSwiftUI/CommonViews/VideoPlayIndicatorView.swift index 7c3199fe1..f221ac000 100644 --- a/Sources/StreamChatSwiftUI/CommonViews/VideoPlayIndicatorView.swift +++ b/Sources/StreamChatSwiftUI/CommonViews/VideoPlayIndicatorView.swift @@ -31,7 +31,7 @@ public struct VideoPlayIndicatorView: View { public var body: some View { Circle() - .fill(Color(colors.controlPlayControlBackground)) + .fill(Color(colors.controlPlayButtonBackground)) .frame(width: size, height: size) .overlay( Image(uiImage: playing ? images.pauseFill : images.playFill) @@ -39,7 +39,7 @@ public struct VideoPlayIndicatorView: View { .resizable() .scaledToFit() .frame(width: iconSize, height: iconSize) - .foregroundColor(Color(colors.controlPlayControlIcon)) + .foregroundColor(Color(colors.controlPlayButtonIcon)) .offset(x: offsetX) ) .accessibilityIdentifier("VideoPlayIndicatorView") diff --git a/Sources/StreamChatSwiftUI/Generated/L10n.swift b/Sources/StreamChatSwiftUI/Generated/L10n.swift index d2cb57b13..c7822f67b 100644 --- a/Sources/StreamChatSwiftUI/Generated/L10n.swift +++ b/Sources/StreamChatSwiftUI/Generated/L10n.swift @@ -1,7 +1,6 @@ // Generated using SwiftGen — https://github.com/SwiftGen/SwiftGen import Foundation -import StreamChatCommonUI // MARK: - Strings @@ -115,8 +114,10 @@ internal enum L10n { internal enum Item { /// Audio internal static var audio: String { L10n.tr("Localizable", "channel.item.audio") } - /// No messages + /// No messages yet internal static var emptyMessages: String { L10n.tr("Localizable", "channel.item.empty-messages") } + /// Giphy + internal static var giphy: String { L10n.tr("Localizable", "channel.item.giphy") } /// Message failed to send internal static var messageFailedToSend: String { L10n.tr("Localizable", "channel.item.message-failed-to-send") } /// Mute @@ -459,8 +460,10 @@ internal enum L10n { internal static var recordingStopped: String { L10n.tr("Localizable", "composer.recording.recordingStopped") } /// Slide to cancel internal static var slideToCancel: String { L10n.tr("Localizable", "composer.recording.slide-to-cancel") } - /// Hold to record. Release to send + /// Hold to record. Release to send. internal static var tip: String { L10n.tr("Localizable", "composer.recording.tip") } + /// Hold to record. Release to save. + internal static var tipSave: String { L10n.tr("Localizable", "composer.recording.tipSave") } /// Voice message deleted internal static var voiceMessageDeleted: String { L10n.tr("Localizable", "composer.recording.voiceMessageDeleted") } } @@ -609,6 +612,8 @@ internal enum L10n { internal static var edited: String { L10n.tr("Localizable", "message.cell.edited") } /// Pinned by internal static var pinnedBy: String { L10n.tr("Localizable", "message.cell.pinnedBy") } + /// Pinned by you + internal static var pinnedByYou: String { L10n.tr("Localizable", "message.cell.pinnedByYou") } /// Sent at %@ internal static func sentAt(_ p1: Any) -> String { return L10n.tr("Localizable", "message.cell.sent-at", String(describing: p1)) @@ -621,6 +626,10 @@ internal enum L10n { internal static var errorPreview: String { L10n.tr("Localizable", "message.file-attachment.error-preview") } } internal enum Gallery { + /// %d of %d + internal static func pageCount(_ p1: Int, _ p2: Int) -> String { + return L10n.tr("Localizable", "message.gallery.pageCount", p1, p2) + } /// Photos internal static var photos: String { L10n.tr("Localizable", "message.gallery.photos") } } @@ -753,6 +762,10 @@ internal enum L10n { internal static var title: String { L10n.tr("Localizable", "message.search.title") } } internal enum Sending { + /// Retry upload + internal static var attachmentRetryUpload: String { L10n.tr("Localizable", "message.sending.attachment-retry-upload") } + /// Upload failed + internal static var attachmentUploadFailed: String { L10n.tr("Localizable", "message.sending.attachment-upload-failed") } /// UPLOADING FAILED internal static var attachmentUploadingFailed: String { L10n.tr("Localizable", "message.sending.attachment-uploading-failed") } } diff --git a/Sources/StreamChatSwiftUI/Generated/L10n_template.stencil b/Sources/StreamChatSwiftUI/Generated/L10n_template.stencil index 9e903805f..3c03c143b 100644 --- a/Sources/StreamChatSwiftUI/Generated/L10n_template.stencil +++ b/Sources/StreamChatSwiftUI/Generated/L10n_template.stencil @@ -3,7 +3,6 @@ {% if tables.count > 0 %} {% set accessModifier %}{% if param.publicAccess %}public{% else %}internal{% endif %}{% endset %} import Foundation -import StreamChatCommonUI // MARK: - Strings diff --git a/Sources/StreamChatSwiftUI/Generated/SystemEnvironment+Version.swift b/Sources/StreamChatSwiftUI/Generated/SystemEnvironment+Version.swift index a7e2406d2..f8dbc0d26 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 = "5.0.0-beta" + public static let version: String = "5.0.0" } diff --git a/Sources/StreamChatSwiftUI/Info.plist b/Sources/StreamChatSwiftUI/Info.plist index b6dfb7e49..c8d921104 100644 --- a/Sources/StreamChatSwiftUI/Info.plist +++ b/Sources/StreamChatSwiftUI/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString - 5.0.0-beta + 5.0.0 CFBundleVersion $(CURRENT_PROJECT_VERSION) NSPhotoLibraryUsageDescription diff --git a/Sources/StreamChatSwiftUI/InjectedValuesExtensions.swift b/Sources/StreamChatSwiftUI/InjectedValuesExtensions.swift index caf79c5c2..153065466 100644 --- a/Sources/StreamChatSwiftUI/InjectedValuesExtensions.swift +++ b/Sources/StreamChatSwiftUI/InjectedValuesExtensions.swift @@ -4,7 +4,6 @@ import Foundation import StreamChat -import StreamChatCommonUI extension InjectedValues { /// Provides access to the `ChatClient` instance. diff --git a/Sources/StreamChatSwiftUI/Resources/en.lproj/Localizable.strings b/Sources/StreamChatSwiftUI/Resources/en.lproj/Localizable.strings index 32316dbd2..f0cab11d8 100644 --- a/Sources/StreamChatSwiftUI/Resources/en.lproj/Localizable.strings +++ b/Sources/StreamChatSwiftUI/Resources/en.lproj/Localizable.strings @@ -5,7 +5,7 @@ "channel.name.and" = "and"; "channel.name.andXMore" = "and %@ more"; "channel.name.missing" = "NoChannel"; -"channel.item.empty-messages" = "No messages"; +"channel.item.empty-messages" = "No messages yet"; "channel.item.message-failed-to-send" = "Message failed to send"; "channel.item.poll-someone-voted" = "%@ voted:"; "channel.item.poll-you-voted" = "You voted:"; @@ -69,7 +69,9 @@ "message.threads.subtitle" = "with messages"; "message.gallery.photos" = "Photos"; +"message.gallery.pageCount" = "%d of %d"; "message.cell.pinnedBy" = "Pinned by"; +"message.cell.pinnedByYou" = "Pinned by you"; "message.cell.unknownPin" = "unknown"; "message.cell.edited" = "Edited"; "message.cell.sent-at" = "Sent at %@"; @@ -212,8 +214,11 @@ "composer.suggestions.commands.header" = "Instant Commands"; "message.sending.attachment-uploading-failed" = "UPLOADING FAILED"; +"message.sending.attachment-upload-failed" = "Upload failed"; +"message.sending.attachment-retry-upload" = "Retry upload"; -"composer.recording.tip" = "Hold to record. Release to send"; +"composer.recording.tip" = "Hold to record. Release to send."; +"composer.recording.tipSave" = "Hold to record. Release to save."; "composer.recording.slide-to-cancel" = "Slide to cancel"; "composer.recording.recordingStopped" = "Recording stopped"; "composer.recording.voiceMessageDeleted" = "Voice message deleted"; @@ -288,6 +293,7 @@ "chat-info.members.title" = "Members"; "channel.item.audio" = "Audio"; +"channel.item.giphy" = "Giphy"; "channel.item.photo" = "Photo"; "channel.item.video" = "Video"; "channel.item.poll" = "Poll"; diff --git a/Sources/StreamChatSwiftUI/Resources/en.lproj/Localizable.stringsdict b/Sources/StreamChatSwiftUI/Resources/en.lproj/Localizable.stringsdict index c85115496..7d2f4aa83 100644 --- a/Sources/StreamChatSwiftUI/Resources/en.lproj/Localizable.stringsdict +++ b/Sources/StreamChatSwiftUI/Resources/en.lproj/Localizable.stringsdict @@ -117,11 +117,11 @@ NSStringFormatValueTypeKey d zero - New messages + Unread messages one - New messages + Unread messages other - New messages + Unread messages messageList.typingIndicator.users @@ -153,11 +153,11 @@ NSStringFormatValueTypeKey d zero - No Thread Replies + 0 replies one - %d Thread Reply + %d reply other - %d Thread Replies + %d replies diff --git a/Sources/StreamChatSwiftUI/StreamChat.swift b/Sources/StreamChatSwiftUI/StreamChat.swift index 87f5c26bb..40cfff5cb 100644 --- a/Sources/StreamChatSwiftUI/StreamChat.swift +++ b/Sources/StreamChatSwiftUI/StreamChat.swift @@ -3,7 +3,6 @@ // import StreamChat -import StreamChatCommonUI /// Main interface to the SwiftUI SDK. /// diff --git a/Sources/StreamChatSwiftUI/Styles.swift b/Sources/StreamChatSwiftUI/Styles.swift index 19dfb4cf5..642e17ad4 100644 --- a/Sources/StreamChatSwiftUI/Styles.swift +++ b/Sources/StreamChatSwiftUI/Styles.swift @@ -2,7 +2,6 @@ // Copyright © 2026 Stream.io Inc. All rights reserved. // -import StreamChatCommonUI import SwiftUI @MainActor @@ -176,7 +175,7 @@ public struct RegularInputViewModifier: ViewModifier { public func body(content: Content) -> some View { content - .background(Color(colors.composerBackground)) + .background(Color(colors.backgroundCoreElevation1)) .modifier(BorderModifier(shape: .roundedRect(cornerRadius))) } @@ -192,7 +191,7 @@ public struct RegularButtonViewModifier: ViewModifier { public func body(content: Content) -> some View { content - .background(Color(colors.composerBackground)) + .background(Color(colors.backgroundCoreElevation1)) .modifier(BorderModifier(shape: .circle)) } } @@ -224,7 +223,7 @@ public struct ComposerBackgroundRegularViewModifier: ViewModifier { public func body(content: Content) -> some View { content - .background(Color(colors.composerBackground)) + .background(Color(colors.backgroundCoreElevation1)) } } @@ -242,7 +241,7 @@ public struct SuggestionsRegularContainerModifier: ViewModifier { Divider() content } - .background(Color(colors.backgroundElevationElevation1)) + .background(Color(colors.backgroundCoreElevation1)) } } @@ -271,7 +270,7 @@ public struct RegularScrollToBottomButtonModifier: ViewModifier { content .background( Circle() - .fill(Color(colors.backgroundElevationElevation1)) + .fill(Color(colors.backgroundCoreElevation1)) .shadow( color: Color(tokens.lightElevation3.color), radius: tokens.lightElevation3.blur / 2, diff --git a/Sources/StreamChatSwiftUI/Utils.swift b/Sources/StreamChatSwiftUI/Utils.swift index 68e9bd1ac..f10bbf89d 100644 --- a/Sources/StreamChatSwiftUI/Utils.swift +++ b/Sources/StreamChatSwiftUI/Utils.swift @@ -18,11 +18,8 @@ import StreamChatCommonUI public var messageTimestampFormatter: MessageTimestampFormatter public var galleryHeaderViewDateFormatter: GalleryHeaderViewDateFormatter public var messageDateSeparatorFormatter: MessageDateSeparatorFormatter - public var videoPreviewLoader: VideoPreviewLoader - public var imageLoader: ImageLoading - public var imageCDN: ImageCDN - public var imageProcessor: ImageProcessor - public var fileCDN: FileCDN + public var cdnRequester: CDNRequester + public var mediaLoader: MediaLoader public var channelNameFormatter: ChannelNameFormatter public var avPlayerProvider: AVPlayerProvider public var chatUserNamer: ChatUserNamer @@ -76,6 +73,7 @@ import StreamChatCommonUI var _audioPlayer: AudioPlaying? var _audioRecorder: AudioRecording? + var linkDetector = TextLinkDetector() var pollsDateFormatter: PollTimestampFormatter = DefaultPollTimestampFormatter() public init( @@ -84,11 +82,8 @@ import StreamChatCommonUI messageTimestampFormatter: MessageTimestampFormatter = ChannelListMessageTimestampFormatter(), galleryHeaderViewDateFormatter: GalleryHeaderViewDateFormatter = DefaultGalleryHeaderViewDateFormatter(), messageDateSeparatorFormatter: MessageDateSeparatorFormatter = DefaultMessageDateSeparatorFormatter(), - videoPreviewLoader: VideoPreviewLoader = DefaultVideoPreviewLoader(), - imageLoader: ImageLoading = NukeImageLoader(), - imageCDN: ImageCDN = StreamImageCDN(), - imageProcessor: ImageProcessor = NukeImageProcessor(), - fileCDN: FileCDN = DefaultFileCDN(), + cdnRequester: CDNRequester = StreamCDNRequester(), + mediaLoader: MediaLoader? = nil, avPlayerProvider: AVPlayerProvider = DefaultAVPlayerProvider(), messageTypeResolver: MessageTypeResolving = MessageTypeResolver(), messageActionResolver: MessageActionsResolving = MessageActionsResolver(), @@ -115,11 +110,8 @@ import StreamChatCommonUI self.messageTimestampFormatter = messageTimestampFormatter self.galleryHeaderViewDateFormatter = galleryHeaderViewDateFormatter self.messageDateSeparatorFormatter = messageDateSeparatorFormatter - self.videoPreviewLoader = videoPreviewLoader - self.imageLoader = imageLoader - self.imageCDN = imageCDN - self.imageProcessor = imageProcessor - self.fileCDN = fileCDN + self.cdnRequester = cdnRequester + self.mediaLoader = mediaLoader ?? StreamMediaLoader(downloader: StreamImageDownloader()) self.channelNameFormatter = channelNameFormatter self.avPlayerProvider = avPlayerProvider self.chatUserNamer = chatUserNamer @@ -148,32 +140,31 @@ import StreamChatCommonUI } } -/// Provides a custom `AVPlayer` for a given video URL. +/// Provides a custom `AVPlayer` from a `MediaLoaderVideoAsset`. /// -/// Conform to this protocol to provide a custom player configuration, -/// such as injecting authentication headers via a custom `AVURLAsset`. -/// -/// The URL passed to ``player(for:completion:)`` has already been resolved -/// through ``FileCDN/adjustedURL(for:completion:)``. +/// Conform to this protocol to provide a custom player configuration. +/// The video asset already contains CDN headers baked into its `AVURLAsset`, +/// resolved through ``MediaLoader/videoAsset(at:options:completion:)``. public protocol AVPlayerProvider { - /// Creates and returns an `AVPlayer` for the given video URL. + /// Creates and returns an `AVPlayer` from the given video asset. /// - Parameters: - /// - url: A video URL already resolved through `FileCDN`. + /// - videoAsset: A video asset already resolved through the `MediaLoader`. /// - completion: A completion that is called when the player is ready or an error occurred. func player( - for url: URL, - completion: @escaping ((Result) -> Void) + from videoAsset: MediaLoaderVideoAsset, + completion: @escaping (Result) -> Void ) } -/// The default implementation that creates an `AVPlayer` directly from the provided URL. +/// The default implementation that creates an `AVPlayer` from a `MediaLoaderVideoAsset`. public final class DefaultAVPlayerProvider: AVPlayerProvider { public init() {} public func player( - for url: URL, - completion: @escaping ((Result) -> Void) + from videoAsset: MediaLoaderVideoAsset, + completion: @escaping (Result) -> Void ) { - completion(.success(AVPlayer(url: url))) + let playerItem = AVPlayerItem(asset: videoAsset.asset) + completion(.success(AVPlayer(playerItem: playerItem))) } } diff --git a/Sources/StreamChatSwiftUI/Utils/Common/CGSize+Extensions.swift b/Sources/StreamChatSwiftUI/Utils/Common/CGSize+Extensions.swift new file mode 100644 index 000000000..9c30328d8 --- /dev/null +++ b/Sources/StreamChatSwiftUI/Utils/Common/CGSize+Extensions.swift @@ -0,0 +1,13 @@ +// +// Copyright © 2026 Stream.io Inc. All rights reserved. +// + +import CoreGraphics +import Foundation + +public extension CGSize { + /// Maximum size of avatar used in the UI. + /// + /// It's better to use single size of avatar thumbnail to utilise the cache. + static var avatarThumbnailSize: CGSize { CGSize(width: 40, height: 40) } +} diff --git a/Sources/StreamChatSwiftUI/Utils/Common/ChatClient+Extensions.swift b/Sources/StreamChatSwiftUI/Utils/Common/ChatClient+Extensions.swift index 4e176fdf0..30f81d8d9 100644 --- a/Sources/StreamChatSwiftUI/Utils/Common/ChatClient+Extensions.swift +++ b/Sources/StreamChatSwiftUI/Utils/Common/ChatClient+Extensions.swift @@ -9,10 +9,13 @@ extension ChatClient { /// The maximum attachment size for the file URL. /// /// The max attachment size can be set from the Stream's Dashboard App Settings. + /// Falls back to the value configured in ``ComposerConfig/maxAttachmentSize``. /// - /// - Parameter fileURL: The file URL of the attachment. + /// - Parameters: + /// - fileURL: The file URL of the attachment. + /// - fallbackSize: The fallback size when the server doesn't provide one. /// - Returns: The maximum allowed size for the attachment in bytes. - func maxAttachmentSize(for fileURL: URL) -> Int64 { + func maxAttachmentSize(for fileURL: URL, fallbackSize: Int64) -> Int64 { let attachmentType = AttachmentType(fileExtension: fileURL.pathExtension) let maxAttachmentSize: Int64? = switch attachmentType { case .image: @@ -23,11 +26,7 @@ extension ChatClient { if let maxAttachmentSize, maxAttachmentSize > 0 { return maxAttachmentSize } else { - if let customCDNClient = config.customCDNClient { - return type(of: customCDNClient).maxAttachmentSize - } else { - return 100 * 1024 * 1024 - } + return fallbackSize } } } diff --git a/Sources/StreamChatSwiftUI/Utils/Common/ChatMessage+Extensions.swift b/Sources/StreamChatSwiftUI/Utils/Common/ChatMessage+Extensions.swift index a3cd47e02..e5bfb04f7 100644 --- a/Sources/StreamChatSwiftUI/Utils/Common/ChatMessage+Extensions.swift +++ b/Sources/StreamChatSwiftUI/Utils/Common/ChatMessage+Extensions.swift @@ -4,6 +4,7 @@ import Foundation import StreamChat +import SwiftUI public extension ChatMessage { /// A boolean value that checks if actions are available on the message (e.g. `edit`, `delete`, `resend`, etc.). @@ -108,6 +109,84 @@ public extension ChatMessage { } } +@available(iOS 15, *) +extension ChatMessage { + /// Returns the message text as a styled `AttributedString` with markdown, mentions, and links applied. + /// + /// Behavior is controlled by `MessageListConfig.markdownSupportEnabled`, `MessageListConfig.localLinkDetectionEnabled`, + /// and `MessageDisplayOptions.messageLinkDisplayResolver`. + @MainActor public func attributedTextContent( + layoutDirection: LayoutDirection, + translationLanguage: TranslationLanguage? + ) -> AttributedString { + @Injected(\.utils) var utils + @Injected(\.colors) var colors + @Injected(\.fonts) var fonts + + let text: String + if let translationLanguage, let translatedText = textContent(for: translationLanguage) { + text = translatedText + } else { + text = textContent ?? "" + } + + let foregroundColor: Color = isSentByCurrentUser + ? Color(colors.chatTextOutgoing) + : Color(colors.chatTextIncoming) + + // Markdown + let attributes = AttributeContainer() + .foregroundColor(foregroundColor) + .font(fonts.body) + var attributedString: AttributedString + if utils.messageListConfig.markdownSupportEnabled { + attributedString = utils.markdownFormatter.format( + text, + attributes: attributes, + layoutDirection: layoutDirection + ) + } else { + attributedString = AttributedString(text, attributes: attributes) + } + + // Links and mentions + if utils.messageListConfig.localLinkDetectionEnabled { + for user in mentionedUsers { + let mention = "@\(user.name ?? user.id)" + let ranges = attributedString.ranges(of: mention, options: [.caseInsensitive]) + for range in ranges { + if let messageId = messageId.addingPercentEncoding(withAllowedCharacters: .urlPathAllowed), + let url = URL(string: "getstream://mention/\(messageId)/\(user.id)") { + attributedString[range].link = url + } + } + } + for link in utils.linkDetector.links(in: String(attributedString.characters)) { + if let attributedStringRange = Range(link.range, in: attributedString) { + attributedString[attributedStringRange].link = link.url + } + } + } + + // Link styling + var linkAttributes = utils.messageListConfig.messageDisplayOptions.messageLinkDisplayResolver(self) + if !linkAttributes.isEmpty { + var linkAttributeContainer = AttributeContainer() + if let uiColor = linkAttributes[.foregroundColor] as? UIColor { + linkAttributeContainer = linkAttributeContainer.foregroundColor(Color(uiColor: uiColor)) + linkAttributes.removeValue(forKey: .foregroundColor) + } + linkAttributeContainer.merge(AttributeContainer(linkAttributes)) + for (value, range) in attributedString.runs[\.link] { + guard value != nil else { continue } + attributedString[range].mergeAttributes(linkAttributeContainer) + } + } + + return attributedString + } +} + extension TranslationLanguage { var localizedName: String? { Locale.current.localizedString(forLanguageCode: languageCode) diff --git a/Sources/StreamChatSwiftUI/Utils/Common/FileCDN.swift b/Sources/StreamChatSwiftUI/Utils/Common/FileCDN.swift deleted file mode 100644 index 33881d7c6..000000000 --- a/Sources/StreamChatSwiftUI/Utils/Common/FileCDN.swift +++ /dev/null @@ -1,31 +0,0 @@ -// -// Copyright © 2026 Stream.io Inc. All rights reserved. -// - -import Foundation -import StreamChat - -/// FileCDN provides a set of functions to improve handling of files & videos from CDN. -public protocol FileCDN: AnyObject { - /// Prepare and return an adjusted or signed `URL` for the given file `URL` - /// This function can be used to intercept an unsigned URL and return a valid signed URL - /// - Parameters: - /// - url: A file URL. - /// - completion: A completion that is called when an adjusted URL is ready to be provided. - func adjustedURL( - for url: URL, - completion: @escaping ((Result) -> Void) - ) -} - -/// The `DefaultFileCDN` implemenation used by default. -public final class DefaultFileCDN: FileCDN { - // Initializer required for subclasses - public init() { - // Public init. - } - - public func adjustedURL(for url: URL, completion: @escaping ((Result) -> Void)) { - completion(.success(url)) - } -} diff --git a/Sources/StreamChatSwiftUI/Utils/Common/ImageCDN.swift b/Sources/StreamChatSwiftUI/Utils/Common/ImageCDN.swift deleted file mode 100644 index 59af83162..000000000 --- a/Sources/StreamChatSwiftUI/Utils/Common/ImageCDN.swift +++ /dev/null @@ -1,89 +0,0 @@ -// -// Copyright © 2026 Stream.io Inc. All rights reserved. -// - -import UIKit - -/// ImageCDN is providing set of functions to improve handling of images from CDN. -public protocol ImageCDN { - /// Customised (filtered) key for image cache. - /// - Parameter imageURL: URL of the image that should be customised (filtered). - /// - Returns: String to be used as an image cache key. - func cachingKey(forImage url: URL) -> String - - /// Prepare and return a `URLRequest` for the given image `URL` - /// This function can be used to inject custom headers for image loading request. - func urlRequest(forImage url: URL) -> URLRequest - - /// Enhance image URL with size parameters to get thumbnail - /// - Parameters: - /// - originalURL: URL of the image to get the thumbnail for. - /// - preferredSize: The requested thumbnail size. - /// - /// Use view size in points for `preferredSize`, point to pixel ratio (scale) of the device is applied inside of this function. - func thumbnailURL(originalURL: URL, preferredSize: CGSize) -> URL -} - -extension ImageCDN { - public func urlRequest(forImage url: URL) -> URLRequest { - URLRequest(url: url) - } -} - -open class StreamImageCDN: ImageCDN { - public static let streamCDNURL = "stream-io-cdn.com" - - // Initializer required for subclasses - public init() { - // Public init. - } - - open func cachingKey(forImage url: URL) -> String { - let key = url.absoluteString - - guard - var components = URLComponents(url: url, resolvingAgainstBaseURL: true), - let host = components.host, - host.contains(StreamImageCDN.streamCDNURL) - else { return key } - - // Keep these parameters in the cache key as they determine the image size. - let persistedParameters = ["w", "h"] - - let newParameters = components.queryItems?.filter { persistedParameters.contains($0.name) } ?? [] - components.queryItems = newParameters.isEmpty ? nil : newParameters - return components.string ?? key - } - - // Although this is the same as the default impl, we still need it - // so subclasses can safely override it - open func urlRequest(forImage url: URL) -> URLRequest { - URLRequest(url: url) - } - - open func thumbnailURL(originalURL: URL, preferredSize: CGSize) -> URL { - guard - var components = URLComponents(url: originalURL, resolvingAgainstBaseURL: true), - let host = components.host, - host.contains(StreamImageCDN.streamCDNURL) - else { return originalURL } - - let scale = Screen.scale - components.queryItems = components.queryItems ?? [] - components.queryItems?.append(contentsOf: [ - URLQueryItem(name: "w", value: String(format: "%.0f", preferredSize.width * scale)), - URLQueryItem(name: "h", value: String(format: "%.0f", preferredSize.height * scale)), - URLQueryItem(name: "crop", value: "center"), - URLQueryItem(name: "resize", value: "fill"), - URLQueryItem(name: "ro", value: "0") // Required parameter. - ]) - return components.url ?? originalURL - } -} - -public extension CGSize { - /// Maximum size of avatar used in the UI. - /// - /// It's better to use single size of avatar thumbnail to utilise the cache. - static var avatarThumbnailSize: CGSize { CGSize(width: 40, height: 40) } -} diff --git a/Sources/StreamChatSwiftUI/Utils/Common/InputTextView.swift b/Sources/StreamChatSwiftUI/Utils/Common/InputTextView.swift index a03fb4bce..1b83d80da 100644 --- a/Sources/StreamChatSwiftUI/Utils/Common/InputTextView.swift +++ b/Sources/StreamChatSwiftUI/Utils/Common/InputTextView.swift @@ -91,10 +91,10 @@ class InputTextView: UITextView, AccessibilityView { backgroundColor = .clear textContainer.lineFragmentPadding = 8 font = InjectedValues[\.utils].composerConfig.inputFont - textColor = InjectedValues[\.colors].text + textColor = InjectedValues[\.colors].textPrimary placeholderLabel.font = font - placeholderLabel.textColor = InjectedValues[\.colors].composerPlaceholderColor + placeholderLabel.textColor = InjectedValues[\.colors].inputTextPlaceholder applyTextAlignmentForCurrentDirection() } diff --git a/Sources/StreamChatSwiftUI/Utils/Common/NukeImageProcessor.swift b/Sources/StreamChatSwiftUI/Utils/Common/NukeImageProcessor.swift deleted file mode 100644 index 2c84d235a..000000000 --- a/Sources/StreamChatSwiftUI/Utils/Common/NukeImageProcessor.swift +++ /dev/null @@ -1,96 +0,0 @@ -// -// Copyright © 2026 Stream.io Inc. All rights reserved. -// - -import UIKit - -public protocol ImageProcessor: Sendable { - /// Crop the image to a given size. The image is center-cropped - /// - Parameters: - /// - image: The image to crop - /// - size: The size to which the image needs to be cropped - /// - Returns: The cropped image - func crop(image: UIImage, to size: CGSize) -> UIImage? - - /// Scale an image to a given size maintaing the aspect ratio. - /// - Parameters: - /// - image: The image to scale - /// - size: The size to which the image needs to be scaled - /// - Returns: The scaled image - func scale(image: UIImage, to size: CGSize) -> UIImage -} - -/// This class provides resizing operations for `UIImage`. It internally uses `Nuke` porcessors to implement operations on images. -open class NukeImageProcessor: ImageProcessor, @unchecked Sendable { - public init() { - // Public init. - } - - open func crop(image: UIImage, to size: CGSize) -> UIImage? { - let imageProccessor = ImageProcessors.Resize(size: size, crop: true) - return imageProccessor.process(image) - } - - open func scale(image: UIImage, to size: CGSize) -> UIImage { - // Determine the scale factor that preserves aspect ratio - let widthRatio = size.width / image.size.width - let heightRatio = size.height / image.size.height - - let scaleFactor = min(widthRatio, heightRatio) - - // Compute the new image size that preserves aspect ratio - let scaledImageSize = CGSize( - width: image.size.width * scaleFactor, - height: image.size.height * scaleFactor - ) - - // Draw and return the resized UIImage - let format = UIGraphicsImageRendererFormat() - format.preferredRange = .standard - let renderer = UIGraphicsImageRenderer(size: scaledImageSize, format: format) - - let scaledImage = renderer.image { _ in - image.draw(in: CGRect(origin: .zero, size: scaledImageSize)) - } - - return scaledImage - } -} - -/// Extension of `Nuke`'s `ImageProcessors` -extension ImageProcessors { - /// Scales an image to a specified size. - /// The getting of the size is offloaded via closure after the image is loaded. - /// The View has time to layout and provide non-zero size. - public final class LateResize: ImageProcessing { - private var size: CGSize { - var size: CGSize = .zero - DispatchQueue.main.sync { size = sizeProvider() } - return size - } - - private let sizeProvider: @Sendable () -> CGSize - - /// Initializes the processor with size providing closure. - /// - Parameter sizeProvider: Closure to obtain size after the image is loaded. - public init(sizeProvider: @escaping @Sendable () -> CGSize) { - self.sizeProvider = sizeProvider - } - - public func process(_ image: PlatformImage) -> PlatformImage? { - let size = size - guard size != .zero else { return image } - - return ImageProcessors.Resize( - size: size, - unit: .points, - contentMode: .aspectFill, - upscale: false - ).process(image) - } - - public var identifier: String { - "com.github.kean/nuke/lateResize" - } - } -} diff --git a/Sources/StreamChatSwiftUI/Utils/Common/VideoPreviewLoader.swift b/Sources/StreamChatSwiftUI/Utils/Common/VideoPreviewLoader.swift deleted file mode 100644 index 8814c67af..000000000 --- a/Sources/StreamChatSwiftUI/Utils/Common/VideoPreviewLoader.swift +++ /dev/null @@ -1,149 +0,0 @@ -// -// Copyright © 2026 Stream.io Inc. All rights reserved. -// - -import AVKit -import StreamChat -import UIKit - -/// A protocol the video preview uploader implementation must conform to. -@MainActor public protocol VideoPreviewLoader: AnyObject { - /// Loads a preview for a local video attachment at a given URL. - /// - Parameters: - /// - url: The video URL. - /// - completion: A completion that is called when a preview is loaded. Must be invoked on main queue. - func loadPreviewForVideo(at url: URL, completion: @escaping @MainActor (Result) -> Void) - - /// Loads a preview for the given remote video attachment. - /// - /// The default implementation calls ``loadPreviewForVideo(at:completion:)`` with the video URL. - /// Override this method to use the attachment's thumbnail URL or other metadata for preview generation. - /// - Parameters: - /// - attachment: A video attachment containing the video URL and optional thumbnail URL. - /// - completion: A completion that is called when a preview is loaded. Must be invoked on main queue. - func loadPreviewForVideo( - with attachment: ChatMessageVideoAttachment, - completion: @Sendable @escaping @MainActor (Result) -> Void - ) -} - -extension VideoPreviewLoader { - public func loadPreviewForVideo( - with attachment: ChatMessageVideoAttachment, - completion: @Sendable @escaping @MainActor (Result) -> Void - ) { - loadPreviewForVideo(at: attachment.videoURL, completion: completion) - } -} - -/// The `VideoPreviewLoader` implemenation used by default. -public final class DefaultVideoPreviewLoader: VideoPreviewLoader { - @Injected(\.utils) var utils - - private let cache: Cache - - public init(countLimit: Int = 50) { - cache = .init(countLimit: countLimit) - - NotificationCenter.default.addObserver( - self, - selector: #selector(handleMemoryWarning(_:)), - name: UIApplication.didReceiveMemoryWarningNotification, - object: nil - ) - } - - deinit { - NotificationCenter.default.removeObserver(self) - } - - public func loadPreviewForVideo(at url: URL, completion: @escaping @MainActor (Result) -> Void) { - if let cached = cache[url] { - Task { @MainActor in - completion(.success(cached)) - } - return - } - - generateVideoPreview(for: url, completion: completion) - } - - public func loadPreviewForVideo( - with attachment: ChatMessageVideoAttachment, - completion: @Sendable @escaping @MainActor (Result) -> Void - ) { - let videoURL = attachment.videoURL - if let cached = cache[videoURL] { - Task { @MainActor in - completion(.success(cached)) - } - return - } - - if let thumbnailURL = attachment.payload.thumbnailURL { - utils.imageLoader.loadImage( - url: thumbnailURL, - imageCDN: utils.imageCDN, - resize: false, - preferredSize: nil - ) { [weak self] result in - guard let self else { return } - switch result { - case let .success(image): - self.cache[videoURL] = image - Task { @MainActor in - completion(.success(image)) - } - case .failure: - self.generateVideoPreview(for: videoURL, completion: completion) - } - } - } else { - generateVideoPreview(for: videoURL, completion: completion) - } - } - - private func generateVideoPreview( - for url: URL, - completion: @escaping @MainActor (Result) -> Void - ) { - utils.fileCDN.adjustedURL(for: url) { result in - let adjustedUrl: URL - switch result { - case let .success(url): - adjustedUrl = url - case let .failure(error): - Task { @MainActor in - completion(.failure(error)) - } - return - } - - let asset = AVURLAsset(url: adjustedUrl) - let imageGenerator = AVAssetImageGenerator(asset: asset) - let frameTime = CMTime(seconds: 0.1, preferredTimescale: 600) - - imageGenerator.appliesPreferredTrackTransform = true - imageGenerator.generateCGImagesAsynchronously(forTimes: [.init(time: frameTime)]) { [cache = self.cache] _, image, _, _, error in - let result: Result - if let thumbnail = image { - result = .success(.init(cgImage: thumbnail)) - } else if let error { - result = .failure(error) - } else { - log.error("Both error and image are `nil`.") - return - } - - cache[url] = try? result.get() - Task { @MainActor in - completion(result) - } - } - } - } - - @objc private func handleMemoryWarning(_ notification: NSNotification) { - cache.removeAllObjects() - } -} diff --git a/Sources/StreamChatSwiftUI/Utils/StreamCore+Extensions.swift b/Sources/StreamChatSwiftUI/Utils/ExportedModules.swift similarity index 71% rename from Sources/StreamChatSwiftUI/Utils/StreamCore+Extensions.swift rename to Sources/StreamChatSwiftUI/Utils/ExportedModules.swift index 8b0dbe84e..36eca94f9 100644 --- a/Sources/StreamChatSwiftUI/Utils/StreamCore+Extensions.swift +++ b/Sources/StreamChatSwiftUI/Utils/ExportedModules.swift @@ -2,5 +2,5 @@ // Copyright © 2026 Stream.io Inc. All rights reserved. // -import Foundation +@_exported import StreamChatCommonUI @_exported import StreamCore diff --git a/Sources/StreamChatSwiftUI/Utils/ImageLoading.swift b/Sources/StreamChatSwiftUI/Utils/ImageLoading.swift deleted file mode 100644 index a4269a575..000000000 --- a/Sources/StreamChatSwiftUI/Utils/ImageLoading.swift +++ /dev/null @@ -1,56 +0,0 @@ -// -// Copyright © 2026 Stream.io Inc. All rights reserved. -// - -import UIKit - -/// ImageLoading is providing set of functions for downloading of images from URLs. -public protocol ImageLoading: AnyObject { - /// Load images from a given URLs - /// - Parameters: - /// - urls: The URLs to load the images from - /// - placeholders: The placeholder images. Placeholders are used when an image fails to load from a URL. The placeholders are used rotationally - /// - loadThumbnails: Should load the images as thumbnails. If this is set to `true`, the thumbnail URL is derived from the `imageCDN` object - /// - thumbnailSize: The size of the thumbnail. This parameter is used only if the `loadThumbnails` parameter is true - /// - imageCDN: The imageCDN to be used - /// - completion: Completion that gets called when all the images finish downloading - func loadImages( - from urls: [URL], - placeholders: [UIImage], - loadThumbnails: Bool, - thumbnailSize: CGSize, - imageCDN: ImageCDN, - completion: @escaping @MainActor ([UIImage]) -> Void - ) - - /// Loads an image from the provided url. - /// - Parameters: - /// - url: The URL to load the images from. - /// - imageCDN: The imageCDN to be used - /// - resize: whether the image should be resized. - /// - preferredSize: if resized, what should be the preferred size. - /// - completion: Completion that gets called when all the images finish downloading - func loadImage( - url: URL?, - imageCDN: ImageCDN, - resize: Bool, - preferredSize: CGSize?, - completion: @escaping @MainActor (Result) -> Void - ) -} - -public extension ImageLoading { - func loadImages( - from urls: [URL], - placeholders: [UIImage], - loadThumbnails: Bool = true, - thumbnailSize: CGSize = .avatarThumbnailSize, - imageCDN: ImageCDN - ) async -> [UIImage] { - await withCheckedContinuation { continuation in - loadImages(from: urls, placeholders: placeholders, loadThumbnails: loadThumbnails, thumbnailSize: thumbnailSize, imageCDN: imageCDN) { images in - continuation.resume(with: .success(images)) - } - } - } -} diff --git a/Sources/StreamChatSwiftUI/Utils/LazyImageExtensions.swift b/Sources/StreamChatSwiftUI/Utils/LazyImageExtensions.swift deleted file mode 100644 index 0c09cff77..000000000 --- a/Sources/StreamChatSwiftUI/Utils/LazyImageExtensions.swift +++ /dev/null @@ -1,41 +0,0 @@ -// -// Copyright © 2026 Stream.io Inc. All rights reserved. -// - -import SwiftUI - -enum LazyImageContentState { - case loaded(UIImage) - case placeholder - case loading - case error(Error) -} - -extension LazyImage { - init( - imageURL: URL?, - @ViewBuilder content: @escaping (LazyImageContentState) -> Content - ) { - let placeholderContent: (LazyImageState) -> Content = { state in - if let image = state.imageContainer?.image { - content(.loaded(image)) - } else if let error = state.error { - content(.error(error)) - } else { - content(.loading) - } - } - self.init(imageURL: imageURL, content: placeholderContent) - } - - init(imageURL: URL?, @ViewBuilder content: @escaping (LazyImageState) -> Content) { - let imageCDN = InjectedValues[\.utils].imageCDN - guard let imageURL else { - self.init(url: imageURL, content: content) - return - } - let urlRequest = imageCDN.urlRequest(forImage: imageURL) - let imageRequest = ImageRequest(urlRequest: urlRequest) - self.init(request: imageRequest, content: content) - } -} diff --git a/Sources/StreamChatSwiftUI/Utils/LiquidGlassModifiers.swift b/Sources/StreamChatSwiftUI/Utils/LiquidGlassModifiers.swift index 42fb9dc48..974a7907d 100644 --- a/Sources/StreamChatSwiftUI/Utils/LiquidGlassModifiers.swift +++ b/Sources/StreamChatSwiftUI/Utils/LiquidGlassModifiers.swift @@ -2,7 +2,6 @@ // Copyright © 2026 Stream.io Inc. All rights reserved. // -import StreamChatCommonUI import SwiftUI public struct LiquidGlassModifier: ViewModifier { @@ -33,6 +32,34 @@ public struct LiquidGlassModifier: ViewModifier { } } +public struct LiquidGlassBorderlessModifier: ViewModifier { + var shape: BackgroundShape + var isInteractive: Bool + + public init( + shape: BackgroundShape, + isInteractive: Bool = false + ) { + self.shape = shape + self.isInteractive = isInteractive + } + + public func body(content: Content) -> some View { + #if swift(>=6.2) + if #available(iOS 26.0, *) { + content + .contentShape(shape) + .clipShape(shape) + .glassEffect(.regular.interactive(isInteractive), in: shape) + } else { + content + } + #else + content + #endif + } +} + public extension Shape where Self == RoundedRectangle { static func roundedRect(_ radius: CGFloat) -> Self { RoundedRectangle(cornerRadius: radius) diff --git a/Sources/StreamChatSwiftUI/Utils/MarkdownFormatter.swift b/Sources/StreamChatSwiftUI/Utils/MarkdownFormatter.swift index 4803c4054..9fc8386fe 100644 --- a/Sources/StreamChatSwiftUI/Utils/MarkdownFormatter.swift +++ b/Sources/StreamChatSwiftUI/Utils/MarkdownFormatter.swift @@ -69,7 +69,7 @@ open class DefaultMarkdownFormatter: MarkdownFormatter { switch presentationKind { case .blockQuote: return AttributeContainer() - .foregroundColor(Color(colors.subtitleText)) + .foregroundColor(Color(colors.textSecondary)) case .codeBlock: return AttributeContainer() .font(fonts.body.monospaced()) @@ -88,7 +88,7 @@ open class DefaultMarkdownFormatter: MarkdownFormatter { default: fonts.footnote } - let foregroundColor: Color? = level >= 6 ? Color(colors.subtitleText) : nil + let foregroundColor: Color? = level >= 6 ? Color(colors.textSecondary) : nil if let foregroundColor { return AttributeContainer() .font(font) diff --git a/Sources/StreamChatSwiftUI/Utils/MessagePreviewFormatter.swift b/Sources/StreamChatSwiftUI/Utils/MessagePreviewFormatter.swift index 5249d1723..7fbf824c8 100644 --- a/Sources/StreamChatSwiftUI/Utils/MessagePreviewFormatter.swift +++ b/Sources/StreamChatSwiftUI/Utils/MessagePreviewFormatter.swift @@ -14,6 +14,9 @@ import SwiftUI /// Formats the message including the author's name. open func format(_ previewMessage: ChatMessage, in channel: ChatChannel) -> String { + if previewMessage.isDeleted { + return L10n.Message.deletedMessagePlaceholder + } if let poll = previewMessage.poll { return formatPoll(poll) } @@ -32,6 +35,9 @@ import SwiftUI /// Formats only the content of the message without the author's name. open func formatContent(for previewMessage: ChatMessage, in channel: ChatChannel) -> String { + if previewMessage.isDeleted { + return L10n.Message.deletedMessagePlaceholder + } if let attachmentPreviewText = formatAttachmentContent(for: previewMessage, in: channel) { return attachmentPreviewText } @@ -67,7 +73,7 @@ import SwiftUI let defaultVideoText = L10n.Channel.Item.video return text.isEmpty ? defaultVideoText : text case .giphy: - return "/giphy" + return L10n.Channel.Item.giphy case .voiceRecording: let defaultVoiceMessageText = L10n.Channel.Item.voiceMessage return text.isEmpty ? defaultVoiceMessageText : text diff --git a/Sources/StreamChatSwiftUI/Utils/Modifiers.swift b/Sources/StreamChatSwiftUI/Utils/Modifiers.swift index 60717d7a6..0020c97b5 100644 --- a/Sources/StreamChatSwiftUI/Utils/Modifiers.swift +++ b/Sources/StreamChatSwiftUI/Utils/Modifiers.swift @@ -40,7 +40,7 @@ struct RoundedBorderModifier: ViewModifier { func body(content: Content) -> some View { content.overlay( RoundedRectangle(cornerRadius: cornerRadius) - .stroke(Color(colors.innerBorder), lineWidth: 1) + .stroke(Color(colors.borderCoreDefault), lineWidth: 1) ) .clipShape(RoundedRectangle(cornerRadius: cornerRadius)) } @@ -51,7 +51,7 @@ struct IconOverImageModifier: ViewModifier { func body(content: Content) -> some View { content - .foregroundColor(Color(colors.staticColorText)) + .foregroundColor(Color(colors.backgroundCoreElevation0)) .padding(.all, 4) } } diff --git a/Sources/StreamChatSwiftUI/Utils/NukeImageLoader.swift b/Sources/StreamChatSwiftUI/Utils/NukeImageLoader.swift deleted file mode 100644 index 479e4122f..000000000 --- a/Sources/StreamChatSwiftUI/Utils/NukeImageLoader.swift +++ /dev/null @@ -1,147 +0,0 @@ -// -// Copyright © 2026 Stream.io Inc. All rights reserved. -// - -import StreamChat -import UIKit - -/// The class which is resposible for loading images from URLs. -/// Internally uses `Nuke`'s shared object of `ImagePipeline` to load the image. -open class NukeImageLoader: ImageLoading { - public init() { - // Public init. - } - - open func loadImage( - using urlRequest: URLRequest, - cachingKey: String?, - completion: @escaping @MainActor (Result) -> Void - ) { - var userInfo: [ImageRequest.UserInfoKey: Any]? - if let cachingKey { - userInfo = [.imageIdKey: cachingKey] - } - - let request = ImageRequest( - urlRequest: urlRequest, - userInfo: userInfo - ) - - ImagePipeline.shared.loadImage(with: request) { result in - Task { @MainActor in - switch result { - case let .success(imageResponse): - completion(.success(imageResponse.image)) - case let .failure(error): - completion(.failure(error)) - } - } - } - } - - open func loadImages( - from urls: [URL], - placeholders: [UIImage], - loadThumbnails: Bool, - thumbnailSize: CGSize, - imageCDN: ImageCDN, - completion: @escaping @MainActor ([UIImage]) -> Void - ) { - let group = DispatchGroup() - final class BatchLoadingResult: @unchecked Sendable { - var images: [UIImage] = [] - } - let batchLoadingResult = BatchLoadingResult() - - for avatarUrl in urls { - var placeholderIndex = 0 - - let thumbnailUrl = imageCDN.thumbnailURL(originalURL: avatarUrl, preferredSize: .avatarThumbnailSize) - var imageRequest = imageCDN.urlRequest(forImage: thumbnailUrl) - imageRequest.timeoutInterval = 8 - let cachingKey = imageCDN.cachingKey(forImage: avatarUrl) - - group.enter() - - loadImage(using: imageRequest, cachingKey: cachingKey) { result in - switch result { - case let .success(image): - batchLoadingResult.images.append(image) - case .failure: - if !placeholders.isEmpty { - // Rotationally use the placeholders - batchLoadingResult.images.append(placeholders[placeholderIndex]) - placeholderIndex += 1 - if placeholderIndex == placeholders.count { - placeholderIndex = 0 - } - } - } - group.leave() - } - } - - group.notify(queue: .main) { - Task { @MainActor in - completion(batchLoadingResult.images) - } - } - } - - open func loadImage( - url: URL?, - imageCDN: ImageCDN, - resize: Bool = true, - preferredSize: CGSize? = nil, - completion: @escaping @MainActor (Result) -> Void - ) { - guard var url else { - Task { @MainActor in - completion(.failure(ClientError.Unknown())) - } - return - } - - let urlRequest = imageCDN.urlRequest(forImage: url) - - var processors = [ImageProcessing]() - if let preferredSize, resize == true { - processors = [ImageProcessors.LateResize(sizeProvider: { - preferredSize - })] - } - - let size = preferredSize ?? .zero - if resize && size != .zero { - url = imageCDN.thumbnailURL(originalURL: url, preferredSize: size) - } - - let cachingKey = imageCDN.cachingKey(forImage: url) - - let request = ImageRequest( - urlRequest: urlRequest, - processors: processors, - userInfo: [.imageIdKey: cachingKey] - ) - - ImagePipeline.shared.loadImage(with: request) { result in - Task { @MainActor in - switch result { - case let .success(imageResponse): - completion(.success(imageResponse.image)) - case let .failure(error): - completion(.failure(error)) - } - } - } - } -} - -private extension UIImageView { - static var nukeLoadingTaskKey: UInt8 = 0 - - var currentImageLoadingTask: ImageTask? { - get { objc_getAssociatedObject(self, &Self.nukeLoadingTaskKey) as? ImageTask } - set { objc_setAssociatedObject(self, &Self.nukeLoadingTaskKey, newValue, .OBJC_ASSOCIATION_RETAIN) } - } -} diff --git a/Sources/StreamChatSwiftUI/Utils/StreamImageDownloader.swift b/Sources/StreamChatSwiftUI/Utils/StreamImageDownloader.swift new file mode 100644 index 000000000..120263752 --- /dev/null +++ b/Sources/StreamChatSwiftUI/Utils/StreamImageDownloader.swift @@ -0,0 +1,46 @@ +// +// Copyright © 2026 Stream.io Inc. All rights reserved. +// + +import StreamChatCommonUI +import UIKit + +/// Nuke-backed implementation of ``ImageDownloading`` for the SwiftUI SDK. +public final class StreamImageDownloader: ImageDownloading, Sendable { + public init() {} + + public func downloadImage( + url: URL, + options: ImageDownloadingOptions, + completion: @escaping @MainActor (Result) -> Void + ) { + var urlRequest = URLRequest(url: url) + if let headers = options.headers { + for (key, value) in headers { + urlRequest.setValue(value, forHTTPHeaderField: key) + } + } + + var processors = [ImageProcessing]() + if let resize = options.resize, resize != .zero { + processors.append(ImageProcessors.Resize(size: resize)) + } + + let request = ImageRequest( + urlRequest: urlRequest, + processors: processors, + userInfo: options.cachingKey.map { [.imageIdKey: $0] } + ) + + ImagePipeline.shared.loadImage(with: request) { result in + Task { @MainActor in + switch result { + case let .success(imageResponse): + completion(.success(DownloadedImage(image: imageResponse.image))) + case let .failure(error): + completion(.failure(error)) + } + } + } + } +} diff --git a/Sources/StreamChatSwiftUI/ViewFactory/DefaultViewFactory.swift b/Sources/StreamChatSwiftUI/ViewFactory/DefaultViewFactory.swift index c4ac49442..7f20463b6 100644 --- a/Sources/StreamChatSwiftUI/ViewFactory/DefaultViewFactory.swift +++ b/Sources/StreamChatSwiftUI/ViewFactory/DefaultViewFactory.swift @@ -10,8 +10,8 @@ import SwiftUI extension ViewFactory { // MARK: channels - public func makeNoChannelsView(options: NoChannelsViewOptions) -> some View { - NoChannelsView() + public func makeEmptyChannelsView(options: EmptyChannelsViewOptions) -> some View { + EmptyChannelsView() } public func makeLoadingView(options: LoadingViewOptions) -> some View { @@ -31,19 +31,23 @@ extension ViewFactory { public func makeMoreChannelActionsView( options: MoreChannelActionsViewOptions ) -> some View { - MoreChannelActionsView( + let actions = InjectedValues[\.utils].channelListConfig.supportedMoreChannelActions( + SupportedMoreChannelActionsOptions( + channel: options.channel, + onDismiss: options.onDismiss, + onError: options.onError + ) + ) + return MoreChannelActionsView( factory: self, channel: options.channel, - channelActions: InjectedValues[\.utils].channelListConfig.supportedMoreChannelActions( - SupportedMoreChannelActionsOptions( - channel: options.channel, - onDismiss: options.onDismiss, - onError: options.onError - ) - ), + channelActions: actions, swipedChannelId: options.swipedChannelId, onDismiss: options.onDismiss ) + .modifier(PresentationDetentsModifier( + sheetSizes: [.custom(actions.count > 3 ? 250 : 200), .medium]) + ) } public func makeChannelListItem( @@ -65,7 +69,7 @@ extension ViewFactory { channelListItem: listItem, swipedChannelId: options.swipedChannelId, channel: options.channel, - numberOfTrailingItems: options.channel.ownCapabilities.contains(.deleteChannel) ? 2 : 1, + numberOfTrailingItems: 2, trailingRightButtonTapped: options.trailingSwipeRightButtonTapped, trailingLeftButtonTapped: options.trailingSwipeLeftButtonTapped, leadingSwipeButtonTapped: options.leadingSwipeButtonTapped @@ -77,12 +81,14 @@ extension ViewFactory { ) -> some View { ChannelAvatar( channel: options.channel, - size: options.size + size: options.size, + indicator: options.showsIndicator ? options.channel.defaultAvatarIndicator : .none, + showsBorder: options.showsBorder ) } public func makeChannelListBackground(options: ChannelListBackgroundOptions) -> some View { - Color(InjectedValues[\.colors].background) + Color(InjectedValues[\.colors].backgroundCoreApp) .edgesIgnoringSafeArea(.bottom) } @@ -90,7 +96,7 @@ extension ViewFactory { options: ChannelListItemBackgroundOptions ) -> some View { let colors = InjectedValues[\.colors] - return Color(colors.backgroundElevationElevation0) + return Color(colors.backgroundCoreElevation0) } public func makeChannelListDividerItem(options: ChannelListDividerItemOptions) -> some View { @@ -191,7 +197,7 @@ extension ViewFactory { public func makeEmptyMessagesView( options: EmptyMessagesViewOptions ) -> some View { - Color(InjectedValues[\.colors].background) + Color(InjectedValues[\.colors].backgroundCoreApp) .frame(maxWidth: .infinity, maxHeight: .infinity) .accessibilityIdentifier("EmptyMessagesView") } @@ -200,7 +206,8 @@ extension ViewFactory { UserAvatar( user: options.user, size: options.size, - showsIndicator: options.showsIndicator + indicator: options.showsIndicator ? (options.user.isOnline ? .online : .offline) : .none, + showsBorder: options.showsBorder ) } @@ -258,7 +265,8 @@ extension ViewFactory { factory: self, message: options.message, isFirst: options.isFirst, - scrolledId: options.scrolledId + scrolledId: options.scrolledId, + translationLanguage: options.translationLanguage ) } @@ -288,12 +296,14 @@ extension ViewFactory { public func makeMessageAttachmentsView( options: MessageAttachmentsViewOptions ) -> some View { - MessageAttachmentsView( + @Injected(\.utils) var utils + return MessageAttachmentsView( factory: self, message: options.message, - width: options.availableWidth, + width: min(options.availableWidth, utils.messageListConfig.attachmentPreviewWidth), isFirst: options.isFirst, - scrolledId: options.scrolledId + scrolledId: options.scrolledId, + translationLanguage: options.translationLanguage ) } @@ -303,17 +313,19 @@ extension ViewFactory { MessageMediaAttachmentsContainerView( factory: self, message: options.message, - width: options.availableWidth + width: options.availableWidth, + isFirst: options.isFirst ) } public func makeGiphyAttachmentView( options: GiphyAttachmentViewOptions ) -> some View { - GiphyAttachmentView( + @Injected(\.utils) var utils + return GiphyAttachmentView( factory: self, message: options.message, - width: options.availableWidth, + width: min(options.availableWidth, utils.messageListConfig.attachmentPreviewWidth), isFirst: options.isFirst, scrolledId: options.scrolledId ) @@ -322,10 +334,11 @@ extension ViewFactory { public func makeLinkAttachmentView( options: LinkAttachmentViewOptions ) -> some View { - LinkAttachmentContainer( + @Injected(\.utils) var utils + return LinkAttachmentContainer( factory: self, message: options.message, - width: options.availableWidth, + width: min(options.availableWidth, utils.messageListConfig.attachmentPreviewWidth), isFirst: options.isFirst, scrolledId: options.scrolledId ) @@ -349,7 +362,8 @@ extension ViewFactory { MessageMediaAttachmentsContainerView( factory: self, message: options.message, - width: options.availableWidth + width: options.availableWidth, + isFirst: options.isFirst ) } @@ -366,12 +380,28 @@ extension ViewFactory { ) } - public func makeMediaViewerHeader( - options: MediaViewerHeaderOptions + public func makeMediaViewerToolbarModifier( + options: MediaViewerToolbarModifierOptions + ) -> some ViewModifier { + MediaViewerToolbarModifier( + title: options.title, + subtitle: options.subtitle, + isShown: options.isShown + ) + } + + public func makeMediaViewerFooterView( + options: MediaViewerFooterViewOptions ) -> some View { - MediaViewerHeader(title: options.title, subtitle: options.subtitle, isShown: options.shown) + MediaViewerFooterView( + shareContent: options.shareContent, + shareFallbackURL: options.shareFallbackURL, + selected: options.selected, + totalCount: options.totalCount, + gridShown: options.gridShown + ) } - + public func makeVideoPlayerHeaderView( options: VideoPlayerHeaderViewOptions ) -> some View { @@ -478,7 +508,7 @@ extension ViewFactory { messageController: options.messageController, quotedMessage: options.quotedMessage, editedMessage: options.editedMessage, - onMessageSent: options.onMessageSent + willSendMessage: options.willSendMessage ) } @@ -553,6 +583,7 @@ extension ViewFactory { factory: self, text: options.$text, recordingState: options.$recordingState, + composerCommand: options.$composerCommand, composerInputState: options.composerInputState, startRecording: options.startRecording, stopRecording: options.stopRecording, @@ -643,10 +674,11 @@ extension ViewFactory { public func makeVoiceRecordingView( options: VoiceRecordingViewOptions ) -> some View { - VoiceRecordingContainerView( + @Injected(\.utils) var utils + return VoiceRecordingContainerView( factory: self, message: options.message, - width: options.availableWidth, + width: min(options.availableWidth, utils.messageListConfig.attachmentPreviewWidth), isFirst: options.isFirst, scrolledId: options.scrolledId ) @@ -784,7 +816,7 @@ extension ViewFactory { } public func makeReactionsDetailView(options: ReactionsDetailViewOptions) -> some View { - ReactionsDetailView(message: options.message) + ReactionsDetailView(factory: self, message: options.message) } public func makeComposerQuotedMessageView( @@ -873,32 +905,43 @@ extension ViewFactory { ) } - public func makeNewMessagesIndicatorView( - options: NewMessagesIndicatorViewOptions + public func makeNewMessagesDividerView( + options: NewMessagesDividerViewOptions ) -> some View { - NewMessagesIndicator( + NewMessagesDivider( newMessagesStartId: options.newMessagesStartId, count: options.count ) } + + public func makeThreadRepliesDividerView( + options: ThreadRepliesDividerViewOptions + ) -> some View { + ThreadRepliesDivider( + replyCount: options.replyCount + ) + } - public func makeJumpToUnreadButton( + public func makeJumpToUnreadButtonOverlay( options: JumpToUnreadButtonOptions - ) -> some View { - VStack { - JumpToUnreadButton( - unreadCount: options.channel.unreadCount.messages, - onTap: options.onJumpToMessage, - onClose: options.onClose - ) - .padding(.all, 8) - - Spacer() - } + ) -> some ViewModifier { + JumpToUnreadButtonOverlayModifier( + isShown: options.isShown, + unreadCount: options.channel.unreadCount.messages, + onJumpToMessage: options.onJumpToMessage, + onClose: options.onClose + ) } public func makePollView(options: PollViewOptions) -> some View { - PollAttachmentView(factory: self, message: options.message, poll: options.poll, isFirst: options.isFirst) + @Injected(\.utils) var utils + return PollAttachmentView( + factory: self, + message: options.message, + poll: options.poll, + isFirst: options.isFirst, + width: min(options.availableWidth, utils.messageListConfig.attachmentPreviewWidth) + ) } // MARK: Threads @@ -924,8 +967,8 @@ extension ViewFactory { ) } - public func makeNoThreadsView(options: NoThreadsViewOptions) -> some View { - NoThreadsView() + public func makeEmptyThreadsView(options: EmptyThreadsViewOptions) -> some View { + EmptyThreadsView() } public func makeThreadListLoadingView(options: ThreadListLoadingViewOptions) -> some View { @@ -949,7 +992,7 @@ extension ViewFactory { } public func makeThreadListBackground(options: ThreadListBackgroundOptions) -> some View { - Color(options.colors.backgroundElevationElevation1) + Color(options.colors.backgroundCoreElevation1) .edgesIgnoringSafeArea(.bottom) } @@ -957,29 +1000,37 @@ extension ViewFactory { options: ThreadListItemBackgroundOptions ) -> some View { let colors = InjectedValues[\.colors] - return Color(colors.backgroundElevationElevation1) + return Color(colors.backgroundCoreElevation1) } public func makeThreadListDividerItem(options: ThreadListDividerItemOptions) -> some View { Divider() } - public func makeAddUsersView( - options: AddUsersViewOptions + public func makeMemberAddView( + options: MemberAddViewOptions ) -> some View { - AddUsersView(loadedUserIds: options.options.loadedUserIds, onConfirm: options.onConfirm) + MemberAddView(loadedUserIds: options.options.loadedUserIds, onConfirm: options.onConfirm) } public func makeAttachmentTextView( options: AttachmentTextViewOptions ) -> some View { - AttachmentTextView(factory: self, message: options.message) + AttachmentTextView( + factory: self, + message: options.message, + availableWidth: options.availableWidth, + translationLanguage: options.translationLanguage + ) } public func makeStreamTextView( options: StreamTextViewOptions ) -> some View { - StreamTextView(message: options.message) + StreamTextView( + message: options.message, + translationLanguage: options.translationLanguage + ) } } diff --git a/Sources/StreamChatSwiftUI/ViewFactory/Options/AttachmentViewFactoryOptions.swift b/Sources/StreamChatSwiftUI/ViewFactory/Options/AttachmentViewFactoryOptions.swift index f04f6bd98..9bd93d226 100644 --- a/Sources/StreamChatSwiftUI/ViewFactory/Options/AttachmentViewFactoryOptions.swift +++ b/Sources/StreamChatSwiftUI/ViewFactory/Options/AttachmentViewFactoryOptions.swift @@ -188,17 +188,21 @@ public final class MessageAttachmentsViewOptions: Sendable { public let availableWidth: CGFloat /// Binding to the currently scrolled message ID. public let scrolledId: Binding + /// The translation language to apply, or `nil` to show the original text. + public let translationLanguage: TranslationLanguage? public init( message: ChatMessage, isFirst: Bool, availableWidth: CGFloat, - scrolledId: Binding + scrolledId: Binding, + translationLanguage: TranslationLanguage? ) { self.message = message self.isFirst = isFirst self.availableWidth = availableWidth self.scrolledId = scrolledId + self.translationLanguage = translationLanguage } } @@ -286,19 +290,47 @@ public final class MediaViewerOptions: Sendable { } } -/// Options for creating the gallery header view. -public final class MediaViewerHeaderOptions: Sendable { - /// The title to display in the header. +/// Options for creating the media viewer toolbar modifier. +public final class MediaViewerToolbarModifierOptions: Sendable { + /// The title to display in the toolbar (e.g. author name). public let title: String - /// The subtitle to display in the header. + /// The subtitle to display in the toolbar (e.g. date). public let subtitle: String - /// Binding to whether the header is shown. - public let shown: Binding - - public init(title: String, subtitle: String, shown: Binding) { + /// Binding that controls whether the media viewer is shown. + public let isShown: Binding + + public init(title: String, subtitle: String, isShown: Binding) { self.title = title self.subtitle = subtitle - self.shown = shown + self.isShown = isShown + } +} + +/// Options for creating the media viewer footer view. +public final class MediaViewerFooterViewOptions: Sendable { + /// The content available for sharing (e.g. loaded images). + public let shareContent: [UIImage] + /// URL to share when ``shareContent`` is empty (e.g. video attachments, or an image still loading). + public let shareFallbackURL: URL? + /// The currently selected media index (zero-based). + public let selected: Int + /// The total number of media attachments. + public let totalCount: Int + /// Binding that controls whether the grid sheet is shown. + public let gridShown: Binding + + public init( + shareContent: [UIImage], + shareFallbackURL: URL? = nil, + selected: Int, + totalCount: Int, + gridShown: Binding + ) { + self.shareContent = shareContent + self.shareFallbackURL = shareFallbackURL + self.selected = selected + self.totalCount = totalCount + self.gridShown = gridShown } } diff --git a/Sources/StreamChatSwiftUI/ViewFactory/Options/ChannelViewFactoryOptions.swift b/Sources/StreamChatSwiftUI/ViewFactory/Options/ChannelViewFactoryOptions.swift index 79aae5feb..74ad4b486 100644 --- a/Sources/StreamChatSwiftUI/ViewFactory/Options/ChannelViewFactoryOptions.swift +++ b/Sources/StreamChatSwiftUI/ViewFactory/Options/ChannelViewFactoryOptions.swift @@ -30,8 +30,8 @@ public final class ChannelListItemOptions { public let selectedChannel: Binding /// Binding to the currently swiped channel ID. public let swipedChannelId: Binding - /// The destination view for channel navigation. - public let channelDestination: @MainActor (ChannelSelectionInfo) -> ChannelDestination + /// The destination view for channel navigation. If nil, channel navigation is disabled. + public let channelDestination: (@MainActor (ChannelSelectionInfo) -> ChannelDestination)? /// Callback when the item is tapped. public let onItemTap: @MainActor (ChatChannel) -> Void /// Callback when the trailing right swipe button is tapped. @@ -47,7 +47,7 @@ public final class ChannelListItemOptions { disabled: Bool, selectedChannel: Binding, swipedChannelId: Binding, - channelDestination: @escaping @MainActor (ChannelSelectionInfo) -> ChannelDestination, + channelDestination: (@MainActor (ChannelSelectionInfo) -> ChannelDestination)? = nil, onItemTap: @escaping @MainActor (ChatChannel) -> Void, trailingSwipeRightButtonTapped: @escaping @MainActor (ChatChannel) -> Void, trailingSwipeLeftButtonTapped: @escaping @MainActor (ChatChannel) -> Void, @@ -73,9 +73,16 @@ public final class ChannelAvatarViewOptions: Sendable { /// The size of the avatar. public let size: CGFloat - public init(channel: ChatChannel, size: CGFloat) { + /// Whether to show the online presence indicator. + public let showsIndicator: Bool + /// Whether to show a circular border around the avatar. + public let showsBorder: Bool + + public init(channel: ChatChannel, size: CGFloat, showsIndicator: Bool = true, showsBorder: Bool = true) { self.channel = channel self.size = size + self.showsIndicator = showsIndicator + self.showsBorder = showsBorder } } @@ -285,16 +292,16 @@ public final class ChannelBarsVisibilityViewModifierOptions: Sendable { } } -// MARK: - Add Users Options +// MARK: - Member Add Options -/// Options for creating the add users view. -public final class AddUsersViewOptions: Sendable { - /// Additional options for the add users view. - public let options: AddUsersOptions +/// Options for creating the member add view. +public final class MemberAddViewOptions: Sendable { + /// Additional options for the member add view. + public let options: MemberAddOptions /// Callback invoked when the user confirms the selection of members to add. public let onConfirm: @MainActor ([ChatUser]) -> Void - public init(options: AddUsersOptions, onConfirm: @escaping @MainActor ([ChatUser]) -> Void) { + public init(options: MemberAddOptions, onConfirm: @escaping @MainActor ([ChatUser]) -> Void) { self.options = options self.onConfirm = onConfirm } diff --git a/Sources/StreamChatSwiftUI/ViewFactory/Options/ComposerViewFactoryOptions.swift b/Sources/StreamChatSwiftUI/ViewFactory/Options/ComposerViewFactoryOptions.swift index 09921f7bb..cda4e6efb 100644 --- a/Sources/StreamChatSwiftUI/ViewFactory/Options/ComposerViewFactoryOptions.swift +++ b/Sources/StreamChatSwiftUI/ViewFactory/Options/ComposerViewFactoryOptions.swift @@ -18,21 +18,21 @@ public final class MessageComposerViewTypeOptions: Sendable { public let quotedMessage: Binding /// Binding to the edited message. public let editedMessage: Binding - /// Callback when a message is sent. - public let onMessageSent: @MainActor () -> Void + /// Callback invoked before a message is sent. + public let willSendMessage: @MainActor () -> Void public init( channelController: ChatChannelController, messageController: ChatMessageController?, quotedMessage: Binding, editedMessage: Binding, - onMessageSent: @escaping @MainActor () -> Void + willSendMessage: @escaping @MainActor () -> Void ) { self.channelController = channelController self.messageController = messageController self.quotedMessage = quotedMessage self.editedMessage = editedMessage - self.onMessageSent = onMessageSent + self.willSendMessage = willSendMessage } } @@ -228,6 +228,8 @@ public final class ComposerInputTrailingViewOptions: @unchecked Sendable { @Binding public var text: String /// Binding to the recording state. @Binding public var recordingState: VoiceRecordingState + /// Binding for the composer command. + @Binding public var composerCommand: ComposerCommand? /// The current composer's input view state. public let composerInputState: MessageComposerInputState /// The closure for starting a recording. @@ -242,6 +244,7 @@ public final class ComposerInputTrailingViewOptions: @unchecked Sendable { public init( text: Binding, recordingState: Binding, + composerCommand: Binding, composerInputState: MessageComposerInputState, startRecording: @escaping @MainActor () -> Void, stopRecording: @escaping @MainActor () -> Void, @@ -250,6 +253,7 @@ public final class ComposerInputTrailingViewOptions: @unchecked Sendable { ) { _text = text _recordingState = recordingState + _composerCommand = composerCommand self.composerInputState = composerInputState self.startRecording = startRecording self.stopRecording = stopRecording @@ -488,10 +492,13 @@ public final class PollViewOptions: Sendable { public let poll: Poll /// Whether this is the first message in a group. public let isFirst: Bool - - public init(message: ChatMessage, poll: Poll, isFirst: Bool) { + /// The available width for the poll view. + public let availableWidth: CGFloat + + public init(message: ChatMessage, poll: Poll, isFirst: Bool, availableWidth: CGFloat) { self.message = message self.poll = poll self.isFirst = isFirst + self.availableWidth = availableWidth } } diff --git a/Sources/StreamChatSwiftUI/ViewFactory/Options/EmptyViewFactoryOptions.swift b/Sources/StreamChatSwiftUI/ViewFactory/Options/EmptyViewFactoryOptions.swift index db860828a..81c642373 100644 --- a/Sources/StreamChatSwiftUI/ViewFactory/Options/EmptyViewFactoryOptions.swift +++ b/Sources/StreamChatSwiftUI/ViewFactory/Options/EmptyViewFactoryOptions.swift @@ -7,8 +7,8 @@ import SwiftUI // MARK: - Empty Options -/// Options for creating the no channels view. -public final class NoChannelsViewOptions: Sendable { +/// Options for creating the empty channels view. +public final class EmptyChannelsViewOptions: Sendable { public init() {} } @@ -77,8 +77,8 @@ public final class ThreadDestinationOptions: Sendable { public init() {} } -/// Options for creating the no threads view. -public final class NoThreadsViewOptions: Sendable { +/// Options for creating the empty threads view. +public final class EmptyThreadsViewOptions: Sendable { public init() {} } diff --git a/Sources/StreamChatSwiftUI/ViewFactory/Options/MessageViewFactoryOptions.swift b/Sources/StreamChatSwiftUI/ViewFactory/Options/MessageViewFactoryOptions.swift index 3843eba26..983151c47 100644 --- a/Sources/StreamChatSwiftUI/ViewFactory/Options/MessageViewFactoryOptions.swift +++ b/Sources/StreamChatSwiftUI/ViewFactory/Options/MessageViewFactoryOptions.swift @@ -36,15 +36,19 @@ public final class UserAvatarViewOptions: Sendable { public let user: ChatUser /// The size of the avatar. public let size: CGFloat - /// True, if the presence indicator should be shown with online and offline states. + /// Whether to show the online presence indicator. public let showsIndicator: Bool - + /// Whether to show a circular border around the avatar. + public let showsBorder: Bool + public init( user: ChatUser, size: CGFloat, - showsIndicator: Bool + showsIndicator: Bool, + showsBorder: Bool = true ) { self.size = size + self.showsBorder = showsBorder self.showsIndicator = showsIndicator self.user = user } @@ -127,17 +131,21 @@ public final class MessageTextViewOptions: Sendable { public let availableWidth: CGFloat /// Binding to the currently scrolled message ID. public let scrolledId: Binding - + /// The translation language to apply, or `nil` to show the original text. + public let translationLanguage: TranslationLanguage? + public init( message: ChatMessage, isFirst: Bool, availableWidth: CGFloat, - scrolledId: Binding + scrolledId: Binding, + translationLanguage: TranslationLanguage? ) { self.message = message self.isFirst = isFirst self.availableWidth = availableWidth self.scrolledId = scrolledId + self.translationLanguage = translationLanguage } } @@ -148,9 +156,12 @@ public final class MessageTextViewOptions: Sendable { public class StreamTextViewOptions { /// The message whose text should be displayed. public let message: ChatMessage + /// The translation language to apply, or `nil` to show the original text. + public let translationLanguage: TranslationLanguage? - public init(message: ChatMessage) { + public init(message: ChatMessage, translationLanguage: TranslationLanguage?) { self.message = message + self.translationLanguage = translationLanguage } } @@ -158,9 +169,15 @@ public class StreamTextViewOptions { public class AttachmentTextViewOptions { /// The message whose text caption should be displayed. public let message: ChatMessage + /// The maximum width available for the text caption. + public let availableWidth: CGFloat + /// The translation language to apply, or `nil` to show the original text. + public let translationLanguage: TranslationLanguage? - public init(message: ChatMessage) { + public init(message: ChatMessage, availableWidth: CGFloat, translationLanguage: TranslationLanguage?) { self.message = message + self.availableWidth = availableWidth + self.translationLanguage = translationLanguage } } @@ -407,8 +424,8 @@ public final class MessageReadIndicatorViewOptions: Sendable { } } -/// Options for creating the new messages indicator view. -public final class NewMessagesIndicatorViewOptions: Sendable { +/// Options for creating the new messages divider view. +public final class NewMessagesDividerViewOptions: Sendable { /// Binding to the new messages start ID. public let newMessagesStartId: Binding /// The number of new messages. @@ -420,8 +437,20 @@ public final class NewMessagesIndicatorViewOptions: Sendable { } } -/// Options for creating the jump to unread button. +/// Options for creating the thread replies divider view. +public final class ThreadRepliesDividerViewOptions: Sendable { + /// The number of replies in the thread. + public let replyCount: Int + + public init(replyCount: Int) { + self.replyCount = replyCount + } +} + +/// Options for creating the jump to unread button overlay. public final class JumpToUnreadButtonOptions: Sendable { + /// Whether the button should be shown. + public let isShown: Bool /// The channel to jump to unread messages in. public let channel: ChatChannel /// Callback when the jump to message button is tapped. @@ -430,10 +459,12 @@ public final class JumpToUnreadButtonOptions: Sendable { public let onClose: @MainActor () -> Void public init( + isShown: Bool = true, channel: ChatChannel, onJumpToMessage: @escaping @MainActor () -> Void, onClose: @escaping @MainActor () -> Void ) { + self.isShown = isShown self.channel = channel self.onJumpToMessage = onJumpToMessage self.onClose = onClose diff --git a/Sources/StreamChatSwiftUI/ViewFactory/Options/ThreadViewFactoryOptions.swift b/Sources/StreamChatSwiftUI/ViewFactory/Options/ThreadViewFactoryOptions.swift index 7b7d9a99f..1f1c5ddc7 100644 --- a/Sources/StreamChatSwiftUI/ViewFactory/Options/ThreadViewFactoryOptions.swift +++ b/Sources/StreamChatSwiftUI/ViewFactory/Options/ThreadViewFactoryOptions.swift @@ -4,7 +4,6 @@ import Foundation import StreamChat -import StreamChatCommonUI import SwiftUI // MARK: - Thread List Options diff --git a/Sources/StreamChatSwiftUI/ViewFactory/ViewFactory.swift b/Sources/StreamChatSwiftUI/ViewFactory/ViewFactory.swift index 64020adf7..14e935f90 100644 --- a/Sources/StreamChatSwiftUI/ViewFactory/ViewFactory.swift +++ b/Sources/StreamChatSwiftUI/ViewFactory/ViewFactory.swift @@ -21,9 +21,9 @@ import SwiftUI /// - Parameter options: the options for creating the header view modifier. func makeChannelListHeaderViewModifier(options: ChannelListHeaderViewModifierOptions) -> HeaderViewModifier - associatedtype NoChannels: View + associatedtype EmptyChannels: View /// Creates the view that is displayed when there are no channels available. - func makeNoChannelsView(options: NoChannelsViewOptions) -> NoChannels + func makeEmptyChannelsView(options: EmptyChannelsViewOptions) -> EmptyChannels associatedtype LoadingContent: View /// Creates the loading view. @@ -227,12 +227,18 @@ import SwiftUI /// - Returns: view displayed in the gallery slot. func makeMediaViewer(options: MediaViewerOptions) -> MediaViewerType - associatedtype MediaViewerHeaderType: View - /// Creates the gallery header view presented with a sheet. - /// - Parameter options: the options for creating the gallery header view. - /// - Returns: View displayed in the gallery header slot. - func makeMediaViewerHeader(options: MediaViewerHeaderOptions) -> MediaViewerHeaderType - + associatedtype MediaViewerToolbarModifierType: ViewModifier + /// Creates the toolbar modifier applied to the media viewer navigation content. + /// - Parameter options: the options for creating the media viewer toolbar. + /// - Returns: ViewModifier applied to the media viewer's navigation content. + func makeMediaViewerToolbarModifier(options: MediaViewerToolbarModifierOptions) -> MediaViewerToolbarModifierType + + associatedtype MediaViewerFooterViewType: View + /// Creates the footer view for the media viewer (share, page counter, grid button). + /// - Parameter options: the options for creating the media viewer footer. + /// - Returns: View displayed in the media viewer footer slot. + func makeMediaViewerFooterView(options: MediaViewerFooterViewOptions) -> MediaViewerFooterViewType + associatedtype VideoPlayerHeaderViewType: View /// Creates the video player header view presented with a sheet. /// - Parameter options: the options for creating the video player header view. @@ -519,17 +525,23 @@ import SwiftUI /// - Returns: view shown in the message read indicator slot. func makeMessageReadIndicatorView(options: MessageReadIndicatorViewOptions) -> MessageReadIndicatorViewType - associatedtype NewMessagesIndicatorViewType: View - /// Creates a separator view showing the number of new messages in the message list. - /// - Parameter options: the options for creating the new messages indicator view. - /// - Returns: view shown in the new messages indicator slot. - func makeNewMessagesIndicatorView(options: NewMessagesIndicatorViewOptions) -> NewMessagesIndicatorViewType + associatedtype NewMessagesDividerType: View + /// Creates the divider shown between read and unread messages. + /// - Parameter options: the options for creating the new messages divider. + /// - Returns: view shown in the new messages divider slot. + func makeNewMessagesDividerView(options: NewMessagesDividerViewOptions) -> NewMessagesDividerType + + associatedtype ThreadRepliesDividerType: View + /// Creates the divider shown between the parent message and replies in a thread. + /// - Parameter options: the options for creating the thread replies divider. + /// - Returns: view shown in the thread replies divider slot. + func makeThreadRepliesDividerView(options: ThreadRepliesDividerViewOptions) -> ThreadRepliesDividerType - associatedtype JumpToUnreadButtonType: View - /// Creates a jump to unread button. - /// - Parameter options: the options for creating the jump to unread button. - /// - Returns: view shown in the jump to unread slot. - func makeJumpToUnreadButton(options: JumpToUnreadButtonOptions) -> JumpToUnreadButtonType + associatedtype JumpToUnreadButtonOverlayType: ViewModifier + /// Creates the jump to unread button overlay modifier. + /// - Parameter options: the options for creating the jump to unread button overlay. + /// - Returns: a view modifier that overlays the jump to unread button on the message list. + func makeJumpToUnreadButtonOverlay(options: JumpToUnreadButtonOptions) -> JumpToUnreadButtonOverlayType associatedtype PollViewType: View /// Creates a poll view. @@ -548,9 +560,9 @@ import SwiftUI /// - Parameter options: the options for creating the thread list item. func makeThreadListItem(options: ThreadListItemOptions) -> ThreadListItemType - associatedtype NoThreads: View + associatedtype EmptyThreads: View /// Creates the view that is displayed when there are no threads available. - func makeNoThreadsView(options: NoThreadsViewOptions) -> NoThreads + func makeEmptyThreadsView(options: EmptyThreadsViewOptions) -> EmptyThreads associatedtype ThreadListLoadingView: View /// Creates a loading view for the thread list. @@ -597,11 +609,11 @@ import SwiftUI /// Creates the thread list divider item. func makeThreadListDividerItem(options: ThreadListDividerItemOptions) -> ThreadListDividerItem - associatedtype AddUsersViewType: View - /// Creates a view for adding users to a chat or channel. - /// - Parameter options: the options for creating the add users view. - /// - Returns: The view shown in the add users slot. - func makeAddUsersView(options: AddUsersViewOptions) -> AddUsersViewType + associatedtype MemberAddViewType: View + /// Creates a view for adding members to a channel. + /// - Parameter options: the options for creating the member add view. + /// - Returns: The view shown in the member add slot. + func makeMemberAddView(options: MemberAddViewOptions) -> MemberAddViewType associatedtype AttachmentTextViewType: View /// Creates a text caption view displayed below attachments inside ``MessageAttachmentsView``. diff --git a/Sources/StreamChatSwiftUI/ViewFactory/ViewModelsFactory.swift b/Sources/StreamChatSwiftUI/ViewFactory/ViewModelsFactory.swift index b6bd9adee..835b7d07e 100644 --- a/Sources/StreamChatSwiftUI/ViewFactory/ViewModelsFactory.swift +++ b/Sources/StreamChatSwiftUI/ViewFactory/ViewModelsFactory.swift @@ -68,16 +68,22 @@ import SwiftUI /// - channelController: the channel controller. /// - messageController: optional message controller (used in threads). /// - quotedMessage: the quoted message. + /// - editedMessage: the edited message. + /// - willSendMessage: callback called before a message is sent. /// - Returns: `MessageComposerViewModel`. public static func makeMessageComposerViewModel( with channelController: ChatChannelController, messageController: ChatMessageController?, - quotedMessage: Binding? = nil + quotedMessage: Binding?, + editedMessage: Binding?, + willSendMessage: (() -> Void)? ) -> MessageComposerViewModel { MessageComposerViewModel( channelController: channelController, messageController: messageController, - quotedMessage: quotedMessage + quotedMessage: quotedMessage, + editedMessage: editedMessage, + willSendMessage: willSendMessage ) } diff --git a/StreamChatSwiftUI.xcodeproj/project.pbxproj b/StreamChatSwiftUI.xcodeproj/project.pbxproj index 61bf2b66e..a1de6b45d 100644 --- a/StreamChatSwiftUI.xcodeproj/project.pbxproj +++ b/StreamChatSwiftUI.xcodeproj/project.pbxproj @@ -9,9 +9,6 @@ /* Begin PBXBuildFile section */ 402C54482B6AAC0100672BFB /* StreamChatSwiftUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8465FBB52746873A00AF091E /* StreamChatSwiftUI.framework */; }; 402C54492B6AAC0100672BFB /* StreamChatSwiftUI.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 8465FBB52746873A00AF091E /* StreamChatSwiftUI.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 4FB52B472EBB63F700491977 /* StreamCore in Frameworks */ = {isa = PBXBuildFile; productRef = 4FB52B462EBB63F700491977 /* StreamCore */; }; - 4FB52B492EBB643700491977 /* StreamCore in Frameworks */ = {isa = PBXBuildFile; productRef = 4FB52B482EBB643700491977 /* StreamCore */; }; - 4FD307F62EC353BE0062127C /* StreamCore in Frameworks */ = {isa = PBXBuildFile; productRef = 4FD307F52EC353BE0062127C /* StreamCore */; }; 8205B4142AD41CC700265B84 /* StreamSwiftTestHelpers in Frameworks */ = {isa = PBXBuildFile; productRef = 8205B4132AD41CC700265B84 /* StreamSwiftTestHelpers */; }; 8205B4182AD4267200265B84 /* StreamSwiftTestHelpers in Frameworks */ = {isa = PBXBuildFile; productRef = 8205B4172AD4267200265B84 /* StreamSwiftTestHelpers */; }; 829EF8772A9362C00045D166 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 829EF8762A9362C00045D166 /* PrivacyInfo.xcprivacy */; }; @@ -119,19 +116,19 @@ Infrastructure/Mocks/AnyEndpoint.swift, Infrastructure/Mocks/APIClient_Mock.swift, Infrastructure/Mocks/CDNClient_Mock.swift, + Infrastructure/Mocks/CDNRequester_Mock.swift, Infrastructure/Mocks/ChatMessageControllerSUI_Mock.swift, Infrastructure/Mocks/ChatReactionListControllerSUI_Mock.swift, Infrastructure/Mocks/EventBatcherMock.swift, Infrastructure/Mocks/EventNotificationCenterMock.swift, - Infrastructure/Mocks/ImageLoader_Mock.swift, Infrastructure/Mocks/InternetConnectionMock.swift, + Infrastructure/Mocks/MediaLoader_Mock.swift, Infrastructure/Mocks/mock.html, Infrastructure/Mocks/MockBackgroundTaskScheduler.swift, Infrastructure/Mocks/MockNetworkURLProtocol.swift, Infrastructure/Mocks/Poll_Mock.swift, Infrastructure/Mocks/RequestRecorderURLProtocol.swift, Infrastructure/Mocks/TestRequest.swift, - Infrastructure/Mocks/VideoPreviewLoader_Mock.swift, Infrastructure/Mocks/VirtualTimer.swift, Infrastructure/Mocks/WebSocketEngineMock.swift, Infrastructure/Mocks/WebSocketPingControllerMock.swift, @@ -161,8 +158,6 @@ Tests/ChatChannel/AttachmentCommandsPickerView_Tests.swift, Tests/ChatChannel/AttachmentFilePickerView_Tests.swift, Tests/ChatChannel/ChannelControllerFactory_Tests.swift, - Tests/ChatChannel/ChannelInfo/AddUsersView_Tests.swift, - Tests/ChatChannel/ChannelInfo/AddUsersViewModel_Tests.swift, Tests/ChatChannel/ChannelInfo/ChannelInfoMockUtils.swift, Tests/ChatChannel/ChannelInfo/ChatChannelInfoView_Tests.swift, Tests/ChatChannel/ChannelInfo/ChatChannelInfoViewModel_Tests.swift, @@ -171,6 +166,8 @@ Tests/ChatChannel/ChannelInfo/FileAttachmentsViewModel_Tests.swift, Tests/ChatChannel/ChannelInfo/MediaAttachmentsView_Tests.swift, Tests/ChatChannel/ChannelInfo/MediaAttachmentsViewModel_Tests.swift, + Tests/ChatChannel/ChannelInfo/MemberAddView_Tests.swift, + Tests/ChatChannel/ChannelInfo/MemberAddViewModel_Tests.swift, Tests/ChatChannel/ChannelInfo/MemberListView_Tests.swift, Tests/ChatChannel/ChannelInfo/ParticipantInfoView_Tests.swift, Tests/ChatChannel/ChannelInfo/PinnedMessagesView_Tests.swift, @@ -192,7 +189,7 @@ Tests/ChatChannel/CreatePollViewModel_Tests.swift, Tests/ChatChannel/EditedMessageView_Tests.swift, Tests/ChatChannel/FileAttachmentView_Tests.swift, - Tests/ChatChannel/LazyImageExtensions_Tests.swift, + Tests/ChatChannel/LazyLoadingImage_Tests.swift, Tests/ChatChannel/MediaAttachmentGalleryOrdering_Tests.swift, Tests/ChatChannel/MediaViewer_Tests.swift, Tests/ChatChannel/MessageActions_Tests.swift, @@ -202,6 +199,7 @@ Tests/ChatChannel/MessageCachingUtils_Tests.swift, Tests/ChatChannel/MessageComposerView_Tests.swift, Tests/ChatChannel/MessageComposerViewModel_Tests.swift, + Tests/ChatChannel/MessageImagePreviewView_Tests.swift, Tests/ChatChannel/MessageItemView_Tests.swift, Tests/ChatChannel/MessageListDateUtils_Tests.swift, Tests/ChatChannel/MessageListView_Tests.swift, @@ -235,16 +233,17 @@ Tests/ChatChannel/Suggestions/UserSuggestionsView_Tests.swift, Tests/ChatChannel/SystemMessageView_Tests.swift, Tests/ChatChannel/TypingIndicatorView_Tests.swift, + Tests/ChatChannel/VoiceRecordingHandler_Tests.swift, Tests/ChatChannel/WebView_Tests.swift, Tests/ChatChannelList/ChatChannelListItemView_Tests.swift, Tests/ChatChannelList/ChatChannelListTestHelpers.swift, Tests/ChatChannelList/ChatChannelListView_Tests.swift, Tests/ChatChannelList/ChatChannelListViewModel_Tests.swift, + Tests/ChatChannelList/EmptyChannelsView_Tests.swift, Tests/ChatChannelList/LoadingView_Tests.swift, Tests/ChatChannelList/MoreChannelActionsFullScreenWrappingView_Tests.swift, Tests/ChatChannelList/MoreChannelActionsView_Tests.swift, Tests/ChatChannelList/MoreChannelActionsViewModel_Tests.swift, - Tests/ChatChannelList/NoChannelsView_Tests.swift, Tests/ChatChannelList/SearchResultsView_Tests.swift, Tests/ChatThreadList/ChatThreadListItemView_Tests.swift, Tests/ChatThreadList/ChatThreadListView_Tests.swift, @@ -256,6 +255,7 @@ Tests/CommonViews/BadgeCountView_Tests.swift, Tests/CommonViews/BadgeNotificationView_Tests.swift, Tests/CommonViews/GalleryHeaderView_Tests.swift, + Tests/CommonViews/NukeImageLoader_Tests.swift, Tests/CommonViews/RadioCheckView_Tests.swift, Tests/CommonViews/SearchBar_Tests.swift, Tests/CommonViews/SnackBarView_Tests.swift, @@ -265,14 +265,13 @@ Tests/Utils/ChatClientExtensions_Tests.swift, Tests/Utils/ChatMessageExtensions_Tests.swift, Tests/Utils/ChatUserNamer_Tests.swift, - Tests/Utils/ImageCDN_Tests.swift, + Tests/Utils/MediaLoader_Tests.swift, Tests/Utils/MessagePreviewFormatter_Tests.swift, Tests/Utils/ReactionsIconProvider_Tests.swift, Tests/Utils/SortReactions_Tests.swift, Tests/Utils/StreamChat_Utils_Tests.swift, Tests/Utils/StringExtensions_Tests.swift, Tests/Utils/URLUtils_Tests.swift, - Tests/Utils/VideoPreviewLoader_Tests.swift, Tests/Utils/ViewFactory_Tests.swift, ); target = 8465FBBC2746873A00AF091E /* StreamChatSwiftUITests */; @@ -390,7 +389,6 @@ ADCE879F2F0D5D0300F6A7C3 /* StreamChatCommonUI in Frameworks */, ADCE87A52F0D5ED900F6A7C3 /* StreamChat in Frameworks */, 8400A34C282C081E0067D3A0 /* OHHTTPStubs in Frameworks */, - 4FD307F62EC353BE0062127C /* StreamCore in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -399,7 +397,6 @@ buildActionMask = 2147483647; files = ( 84E7F9E22EFAF9BF00BA56A3 /* StreamChat in Frameworks */, - 4FB52B492EBB643700491977 /* StreamCore in Frameworks */, 84E7F9E42EFAF9BF00BA56A3 /* StreamChatCommonUI in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -424,7 +421,6 @@ 8465FCE6274695B400AF091E /* StreamChatSwiftUI.framework in Frameworks */, E3A1C01C282BAC66002D1E26 /* Sentry in Frameworks */, ADCE871A2F0C290B00F6A7C3 /* StreamChat in Frameworks */, - 4FB52B472EBB63F700491977 /* StreamCore in Frameworks */, ADCE871C2F0C291600F6A7C3 /* StreamChatCommonUI in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -527,7 +523,6 @@ name = StreamChatSwiftUITestsApp; packageProductDependencies = ( 8400A34B282C081E0067D3A0 /* OHHTTPStubs */, - 4FD307F52EC353BE0062127C /* StreamCore */, ADCE879E2F0D5D0300F6A7C3 /* StreamChatCommonUI */, ADCE87A42F0D5ED900F6A7C3 /* StreamChat */, ); @@ -555,7 +550,6 @@ ); name = StreamChatSwiftUI; packageProductDependencies = ( - 4FB52B482EBB643700491977 /* StreamCore */, 84E7F9E12EFAF9BF00BA56A3 /* StreamChat */, 84E7F9E32EFAF9BF00BA56A3 /* StreamChatCommonUI */, ); @@ -610,7 +604,6 @@ name = DemoAppSwiftUI; packageProductDependencies = ( E3A1C01B282BAC66002D1E26 /* Sentry */, - 4FB52B462EBB63F700491977 /* StreamCore */, ADCE87192F0C290B00F6A7C3 /* StreamChat */, ADCE871B2F0C291600F6A7C3 /* StreamChatCommonUI */, ); @@ -660,7 +653,6 @@ E3A1C01A282BAC66002D1E26 /* XCRemoteSwiftPackageReference "sentry-cocoa" */, 8400A346282C06F90067D3A0 /* XCRemoteSwiftPackageReference "OHHTTPStubs" */, 82543C7B2AD41B0400D5F6CD /* XCRemoteSwiftPackageReference "stream-chat-swift-test-helpers" */, - 4FB52B452EBB63F700491977 /* XCRemoteSwiftPackageReference "stream-core-swift" */, 84E7F9E02EFAF9BF00BA56A3 /* XCRemoteSwiftPackageReference "stream-chat-swift" */, ); preferredProjectObjectVersion = 77; @@ -1510,14 +1502,6 @@ /* End XCConfigurationList section */ /* Begin XCRemoteSwiftPackageReference section */ - 4FB52B452EBB63F700491977 /* XCRemoteSwiftPackageReference "stream-core-swift" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/GetStream/stream-core-swift"; - requirement = { - kind = exactVersion; - version = 0.6.2; - }; - }; 82543C7B2AD41B0400D5F6CD /* XCRemoteSwiftPackageReference "stream-chat-swift-test-helpers" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/GetStream/stream-chat-swift-test-helpers.git"; @@ -1539,7 +1523,7 @@ repositoryURL = "https://github.com/GetStream/stream-chat-swift.git"; requirement = { kind = upToNextMajorVersion; - minimumVersion = 5.0.0-beta; + minimumVersion = 5.0.0; }; }; E3A1C01A282BAC66002D1E26 /* XCRemoteSwiftPackageReference "sentry-cocoa" */ = { @@ -1553,21 +1537,6 @@ /* End XCRemoteSwiftPackageReference section */ /* Begin XCSwiftPackageProductDependency section */ - 4FB52B462EBB63F700491977 /* StreamCore */ = { - isa = XCSwiftPackageProductDependency; - package = 4FB52B452EBB63F700491977 /* XCRemoteSwiftPackageReference "stream-core-swift" */; - productName = StreamCore; - }; - 4FB52B482EBB643700491977 /* StreamCore */ = { - isa = XCSwiftPackageProductDependency; - package = 4FB52B452EBB63F700491977 /* XCRemoteSwiftPackageReference "stream-core-swift" */; - productName = StreamCore; - }; - 4FD307F52EC353BE0062127C /* StreamCore */ = { - isa = XCSwiftPackageProductDependency; - package = 4FB52B452EBB63F700491977 /* XCRemoteSwiftPackageReference "stream-core-swift" */; - productName = StreamCore; - }; 8205B4132AD41CC700265B84 /* StreamSwiftTestHelpers */ = { isa = XCSwiftPackageProductDependency; package = 82543C7B2AD41B0400D5F6CD /* XCRemoteSwiftPackageReference "stream-chat-swift-test-helpers" */; diff --git a/StreamChatSwiftUITests/Infrastructure/Mocks/APIClient_Mock.swift b/StreamChatSwiftUITests/Infrastructure/Mocks/APIClient_Mock.swift index b231562e7..58b00c037 100644 --- a/StreamChatSwiftUITests/Infrastructure/Mocks/APIClient_Mock.swift +++ b/StreamChatSwiftUITests/Infrastructure/Mocks/APIClient_Mock.swift @@ -23,13 +23,13 @@ class APIClientMock: APIClient, StreamChatTestTools.Spy, @unchecked Sendable { /// The last endpoint `uploadFile` function was called with. @Atomic var uploadFile_attachment: AnyChatMessageAttachment? - @Atomic var uploadFile_progress: ((Double) -> Void)? - @Atomic var uploadFile_completion: ((Result) -> Void)? + @Atomic var uploadFile_progress: (@Sendable (Double) -> Void)? + @Atomic var uploadFile_completion: ((Result) -> Void)? @Atomic var init_sessionConfiguration: URLSessionConfiguration @Atomic var init_requestEncoder: RequestEncoder @Atomic var init_requestDecoder: RequestDecoder - @Atomic var init_CDNClient: CDNClient + @Atomic var init_cdnStorage: CDNStorage @Atomic var request_expectation: XCTestExpectation // Cleans up all recorded values @@ -48,42 +48,43 @@ class APIClientMock: APIClient, StreamChatTestTools.Spy, @unchecked Sendable { sessionConfiguration: URLSessionConfiguration, requestEncoder: RequestEncoder, requestDecoder: RequestDecoder, - CDNClient: CDNClient, - tokenRefresher: ((@escaping () -> Void) -> Void)!, + attachmentDownloader: AttachmentDownloader, + cdnStorage: CDNStorage, + tokenRefresher: ((@escaping @Sendable () -> Void) -> Void)!, queueOfflineRequest: @escaping QueueOfflineRequestBlock ) { init_sessionConfiguration = sessionConfiguration init_requestEncoder = requestEncoder init_requestDecoder = requestDecoder - init_CDNClient = CDNClient - let attachmentUploader = StreamAttachmentUploader(cdnClient: CDNClient) + init_cdnStorage = cdnStorage request_expectation = .init() super.init( sessionConfiguration: sessionConfiguration, requestEncoder: requestEncoder, requestDecoder: requestDecoder, - attachmentDownloader: StreamAttachmentDownloader(sessionConfiguration: sessionConfiguration), - attachmentUploader: attachmentUploader, - cdnClient: CDNClient + attachmentDownloader: attachmentDownloader, + cdnStorage: cdnStorage ) + self.tokenRefresher = tokenRefresher + self.queueOfflineRequest = queueOfflineRequest } /// Simulates the response of the last `request` method call - func test_simulateResponse(_ response: Result) { - let completion = request_completion as? ((Result) -> Void) + func test_simulateResponse(_ response: Result) { + let completion = request_completion as? (@Sendable (Result) -> Void) completion?(response) } - func test_simulateRecoveryResponse(_ response: Result) { - let completion = recoveryRequest_completion as? ((Result) -> Void) + func test_simulateRecoveryResponse(_ response: Result) { + let completion = recoveryRequest_completion as? (@Sendable (Result) -> Void) completion?(response) } override func request( endpoint: Endpoint, - completion: @escaping (Result) -> Void - ) where Response: Decodable { + completion: @escaping @Sendable (Result) -> Void + ) where Response: Decodable & Sendable { request_endpoint = AnyEndpoint(endpoint) request_completion = completion _request_allRecordedCalls.mutate { $0.append((request_endpoint!, request_completion!)) } @@ -92,17 +93,17 @@ class APIClientMock: APIClient, StreamChatTestTools.Spy, @unchecked Sendable { override func recoveryRequest( endpoint: Endpoint, - completion: @escaping (Result) -> Void - ) where Response: Decodable { + completion: @escaping @Sendable (Result) -> Void + ) where Response: Decodable & Sendable { recoveryRequest_endpoint = AnyEndpoint(endpoint) recoveryRequest_completion = completion _recoveryRequest_allRecordedCalls.mutate { $0.append((recoveryRequest_endpoint!, recoveryRequest_completion!)) } } - func uploadAttachment( + override func uploadAttachment( _ attachment: AnyChatMessageAttachment, - progress: ((Double) -> Void)?, - completion: @escaping (Result) -> Void + progress: (@Sendable (Double) -> Void)?, + completion: @escaping @Sendable (Result) -> Void ) { uploadFile_attachment = attachment uploadFile_progress = progress @@ -136,7 +137,8 @@ extension APIClientMock { sessionConfiguration: .ephemeral, requestEncoder: DefaultRequestEncoder(baseURL: .unique(), apiKey: .init(.unique)), requestDecoder: DefaultRequestDecoder(), - CDNClient: CDNClient_Mock(), + attachmentDownloader: StreamAttachmentDownloader(sessionConfiguration: .ephemeral), + cdnStorage: CDNStorage_Mock(), tokenRefresher: { _ in }, queueOfflineRequest: { _ in } ) diff --git a/StreamChatSwiftUITests/Infrastructure/Mocks/CDNClient_Mock.swift b/StreamChatSwiftUITests/Infrastructure/Mocks/CDNClient_Mock.swift index f14a37e42..2c738b274 100644 --- a/StreamChatSwiftUITests/Infrastructure/Mocks/CDNClient_Mock.swift +++ b/StreamChatSwiftUITests/Infrastructure/Mocks/CDNClient_Mock.swift @@ -5,37 +5,49 @@ import Foundation @testable import StreamChat -final class CDNClient_Mock: CDNClient, @unchecked Sendable { +final class CDNStorage_Mock: CDNStorage, @unchecked Sendable { lazy var deleteAttachmentMockFunc = MockFunc.mock(for: deleteAttachment) - func deleteAttachment(remoteUrl: URL, completion: @escaping ((any Error)?) -> Void) { + func deleteAttachment(remoteUrl: URL, options: AttachmentDeleteOptions, completion: @escaping @Sendable (Error?) -> Void) { deleteAttachmentMockFunc.callAndReturn( ( remoteUrl, + options, completion ) ) } - static var maxAttachmentSize: Int64 = .max + lazy var uploadAttachmentMockFunc = MockFunc< + ( + AnyChatMessageAttachment, + AttachmentUploadOptions, + @Sendable (Result) -> Void + ), + Void + >() - lazy var uploadAttachmentMockFunc = MockFunc.mock(for: uploadAttachment) func uploadAttachment( _ attachment: AnyChatMessageAttachment, - progress: ((Double) -> Void)?, - completion: @escaping (Result) -> Void + options: AttachmentUploadOptions, + completion: @escaping @Sendable (Result) -> Void ) { - uploadAttachmentMockFunc.callAndReturn( - ( - attachment, - progress, - completion - ) - ) + uploadAttachmentMockFunc.callAndReturn((attachment, options, completion)) + } + + lazy var uploadAttachmentLocalUrlMockFunc = MockFunc< + ( + URL, + AttachmentUploadOptions, + @Sendable (Result) -> Void + ), + Void + >() + + func uploadAttachment( + localUrl: URL, + options: AttachmentUploadOptions, + completion: @escaping @Sendable (Result) -> Void + ) { + uploadAttachmentLocalUrlMockFunc.callAndReturn((localUrl, options, completion)) } - - func uploadStandaloneAttachment( - _ attachment: StreamAttachment, - progress: ((Double) -> Void)?, - completion: @escaping (Result) -> Void - ) {} } diff --git a/StreamChatSwiftUITests/Infrastructure/Mocks/CDNRequester_Mock.swift b/StreamChatSwiftUITests/Infrastructure/Mocks/CDNRequester_Mock.swift new file mode 100644 index 000000000..839cdcc5c --- /dev/null +++ b/StreamChatSwiftUITests/Infrastructure/Mocks/CDNRequester_Mock.swift @@ -0,0 +1,40 @@ +// +// Copyright © 2026 Stream.io Inc. All rights reserved. +// + +import Foundation +@testable import StreamChat + +final class CDNRequester_Mock: CDNRequester, @unchecked Sendable { + var fileRequestCallCount = 0 + var fileRequestCalledWithURLs: [URL] = [] + var fileRequestResult: Result = .success( + CDNRequest(url: URL(string: "https://cdn.example.com/signed-file")!) + ) + + var imageRequestCallCount = 0 + var imageRequestCalledWithURLs: [URL] = [] + var imageRequestResult: Result = .success( + CDNRequest(url: URL(string: "https://cdn.example.com/signed-image")!) + ) + + func fileRequest( + for url: URL, + options: FileRequestOptions, + completion: @escaping (Result) -> Void + ) { + fileRequestCallCount += 1 + fileRequestCalledWithURLs.append(url) + completion(fileRequestResult) + } + + func imageRequest( + for url: URL, + options: ImageRequestOptions, + completion: @escaping (Result) -> Void + ) { + imageRequestCallCount += 1 + imageRequestCalledWithURLs.append(url) + completion(imageRequestResult) + } +} diff --git a/StreamChatSwiftUITests/Infrastructure/Mocks/ImageLoader_Mock.swift b/StreamChatSwiftUITests/Infrastructure/Mocks/ImageLoader_Mock.swift deleted file mode 100644 index 2b6b204fc..000000000 --- a/StreamChatSwiftUITests/Infrastructure/Mocks/ImageLoader_Mock.swift +++ /dev/null @@ -1,102 +0,0 @@ -// -// Copyright © 2026 Stream.io Inc. All rights reserved. -// - -import Foundation -@testable import StreamChat -import StreamChatSwiftUI -import UIKit -import XCTest - -/// Mock implementation of `ImageLoading`. -class ImageLoader_Mock: ImageLoading { - static let defaultLoadedImage = XCTestCase.TestImages.yoda.image - var loadImageCalled = false - - func loadImage( - url: URL?, - imageCDN: ImageCDN, - resize: Bool, - preferredSize: CGSize?, - completion: @escaping @MainActor (Result) -> Void - ) { - loadImageCalled = true - StreamConcurrency.onMain { - completion(.success(Self.defaultLoadedImage)) - } - } - - func loadImages( - from urls: [URL], - placeholders: [UIImage], - loadThumbnails: Bool, - thumbnailSize: CGSize, - imageCDN: ImageCDN, - completion: @escaping @MainActor ([UIImage]) -> Void - ) { - loadImageCalled = true - - StreamConcurrency.onMain { - completion([Self.defaultLoadedImage]) - } - } -} - -/// Mock implementation of `ImageLoading` that returns different TestImages based on URL. -class TestImagesLoader_Mock: ImageLoading { - var loadImageCalled = false - var loadImagesCalled = false - - func loadImage( - url: URL?, - imageCDN: ImageCDN, - resize: Bool, - preferredSize: CGSize?, - completion: @escaping @MainActor (Result) -> Void - ) { - loadImageCalled = true - - let image = imageForURL(url) - StreamConcurrency.onMain { - completion(.success(image)) - } - } - - func loadImages( - from urls: [URL], - placeholders: [UIImage], - loadThumbnails: Bool, - thumbnailSize: CGSize, - imageCDN: ImageCDN, - completion: @escaping @MainActor ([UIImage]) -> Void - ) { - loadImagesCalled = true - - let images = urls.map { imageForURL($0) } - StreamConcurrency.onMain { - completion(images) - } - } - - private func imageForURL(_ url: URL?) -> UIImage { - guard let url else { - return XCTestCase.TestImages.yoda.image - } - - let urlString = url.absoluteString - - // Return different TestImages based on URL content - if urlString.contains("yoda") { - return XCTestCase.TestImages.yoda.image - } else if urlString.contains("chewbacca") { - return XCTestCase.TestImages.chewbacca.image - } else if urlString.contains("r2") || urlString.contains("r2-d2") { - return XCTestCase.TestImages.r2.image - } else if urlString.contains("vader") { - return XCTestCase.TestImages.vader.image - } else { - // Default fallback - return XCTestCase.TestImages.yoda.image - } - } -} diff --git a/StreamChatSwiftUITests/Infrastructure/Mocks/MediaLoader_Mock.swift b/StreamChatSwiftUITests/Infrastructure/Mocks/MediaLoader_Mock.swift new file mode 100644 index 000000000..7ae564169 --- /dev/null +++ b/StreamChatSwiftUITests/Infrastructure/Mocks/MediaLoader_Mock.swift @@ -0,0 +1,91 @@ +// +// Copyright © 2026 Stream.io Inc. All rights reserved. +// + +import AVKit +import Foundation +@testable import StreamChat +import StreamChatCommonUI +@testable import StreamChatSwiftUI +import UIKit +import XCTest + +/// Mock implementation of `MediaLoader`. +/// +/// Returns images based on URL content when known test image names are present +/// (yoda, chewbacca, r2, vader), otherwise falls back to `defaultLoadedImage`. +class MediaLoader_Mock: MediaLoader, @unchecked Sendable { + static let defaultLoadedImage = XCTestCase.TestImages.yoda.image + var loadImageCalled = false + var loadImageCallCount = 0 + var loadedURLs: [URL?] = [] + var loadImageOptions: [ImageLoadOptions] = [] + var loadVideoPreviewWithAttachmentCalled = false + var loadVideoPreviewAtURLCalled = false + var loadVideoPreviewOptions: [VideoLoadOptions] = [] + var loadVideoAssetOptions: [VideoLoadOptions] = [] + + func loadImage( + url: URL?, + options: ImageLoadOptions, + completion: @escaping @MainActor (Result) -> Void + ) { + loadImageCalled = true + loadImageCallCount += 1 + loadedURLs.append(url) + loadImageOptions.append(options) + let image = imageForURL(url) + StreamConcurrency.onMain { + completion(.success(MediaLoaderImage(image: image))) + } + } + + func loadVideoAsset( + at url: URL, + options: VideoLoadOptions, + completion: @escaping @MainActor (Result) -> Void + ) { + loadVideoAssetOptions.append(options) + StreamConcurrency.onMain { + completion(.success(MediaLoaderVideoAsset(asset: AVURLAsset(url: url)))) + } + } + + func loadVideoPreview( + with attachment: ChatMessageVideoAttachment, + options: VideoLoadOptions, + completion: @escaping @MainActor (Result) -> Void + ) { + loadVideoPreviewWithAttachmentCalled = true + loadVideoPreviewOptions.append(options) + StreamConcurrency.onMain { + completion(.success(MediaLoaderVideoPreview(image: Self.defaultLoadedImage))) + } + } + + func loadVideoPreview( + at url: URL, + options: VideoLoadOptions, + completion: @escaping @MainActor (Result) -> Void + ) { + loadVideoPreviewAtURLCalled = true + loadVideoPreviewOptions.append(options) + StreamConcurrency.onMain { + completion(.success(MediaLoaderVideoPreview(image: Self.defaultLoadedImage))) + } + } + + private func imageForURL(_ url: URL?) -> UIImage { + guard let url else { return Self.defaultLoadedImage } + let urlString = url.absoluteString + if urlString.contains("chewbacca") { + return XCTestCase.TestImages.chewbacca.image + } else if urlString.contains("r2") || urlString.contains("r2-d2") { + return XCTestCase.TestImages.r2.image + } else if urlString.contains("vader") { + return XCTestCase.TestImages.vader.image + } else { + return Self.defaultLoadedImage + } + } +} diff --git a/StreamChatSwiftUITests/Infrastructure/Mocks/VideoPreviewLoader_Mock.swift b/StreamChatSwiftUITests/Infrastructure/Mocks/VideoPreviewLoader_Mock.swift deleted file mode 100644 index af7a4eac4..000000000 --- a/StreamChatSwiftUITests/Infrastructure/Mocks/VideoPreviewLoader_Mock.swift +++ /dev/null @@ -1,31 +0,0 @@ -// -// Copyright © 2026 Stream.io Inc. All rights reserved. -// - -@testable import StreamChat -@testable import StreamChatSwiftUI -import UIKit -import XCTest - -/// Mock implementation of `VideoPreviewLoader`. -class VideoPreviewLoader_Mock: VideoPreviewLoader { - var loadPreviewVideoCalled = false - var loadPreviewVideoWithAttachmentCalled = false - - func loadPreviewForVideo(at url: URL, completion: @escaping @MainActor (Result) -> Void) { - loadPreviewVideoCalled = true - - StreamConcurrency.onMain { - completion(.success(ImageLoader_Mock.defaultLoadedImage)) - } - } - - func loadPreviewForVideo( - with attachment: ChatMessageVideoAttachment, - completion: @escaping @MainActor (Result) -> Void - ) { - loadPreviewVideoWithAttachmentCalled = true - - completion(.success(ImageLoader_Mock.defaultLoadedImage)) - } -} diff --git a/StreamChatSwiftUITests/Infrastructure/Shared/StreamChatModel.xcdatamodeld/StreamChatModel.xcdatamodel/contents b/StreamChatSwiftUITests/Infrastructure/Shared/StreamChatModel.xcdatamodeld/StreamChatModel.xcdatamodel/contents index 17b350000..f2c19b41a 100644 --- a/StreamChatSwiftUITests/Infrastructure/Shared/StreamChatModel.xcdatamodeld/StreamChatModel.xcdatamodel/contents +++ b/StreamChatSwiftUITests/Infrastructure/Shared/StreamChatModel.xcdatamodeld/StreamChatModel.xcdatamodel/contents @@ -76,7 +76,7 @@ - + @@ -263,7 +263,7 @@ - + diff --git a/StreamChatSwiftUITests/Infrastructure/TestTools/ChatClient_Mock.swift b/StreamChatSwiftUITests/Infrastructure/TestTools/ChatClient_Mock.swift index 7d1077696..67c993016 100644 --- a/StreamChatSwiftUITests/Infrastructure/TestTools/ChatClient_Mock.swift +++ b/StreamChatSwiftUITests/Infrastructure/TestTools/ChatClient_Mock.swift @@ -10,10 +10,10 @@ public extension ChatClient { /// Create a new instance of mock `ChatClient` static func mock( isLocalStorageEnabled: Bool = false, - customCDNClient: CDNClient? = nil + customCDNStorage: CDNStorage? = nil ) -> ChatClient_Mock { var config = ChatClientConfig(apiKey: .init("--== Mock ChatClient ==--")) - config.customCDNClient = customCDNClient + config.cdnStorage = customCDNStorage config.isLocalStorageEnabled = isLocalStorageEnabled config.isClientInActiveMode = false config.maxAttachmentCountPerMessage = 10 @@ -28,8 +28,7 @@ public extension ChatClient { requestEncoder: $1, requestDecoder: $2, attachmentDownloader: $3, - attachmentUploader: $4, - cdnClient: $5 + cdnStorage: $4 ) }, webSocketClientBuilder: { diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/AttachmentCommandsPickerView_Tests.swift b/StreamChatSwiftUITests/Tests/ChatChannel/AttachmentCommandsPickerView_Tests.swift index fae1b8dcd..007ca04cd 100644 --- a/StreamChatSwiftUITests/Tests/ChatChannel/AttachmentCommandsPickerView_Tests.swift +++ b/StreamChatSwiftUITests/Tests/ChatChannel/AttachmentCommandsPickerView_Tests.swift @@ -15,9 +15,8 @@ import XCTest override func setUp() { super.setUp() - let imageLoader = TestImagesLoader_Mock() let utils = Utils( - imageLoader: imageLoader, + mediaLoader: MediaLoader_Mock(), messageListConfig: MessageListConfig( becomesFirstResponderOnOpen: true, draftMessagesEnabled: true diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/ChatChannelInfoViewModel_Tests.swift b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/ChatChannelInfoViewModel_Tests.swift index cf5ac3adb..421ed047a 100644 --- a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/ChatChannelInfoViewModel_Tests.swift +++ b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/ChatChannelInfoViewModel_Tests.swift @@ -263,7 +263,7 @@ import XCTest let viewModel = ChatChannelInfoViewModel(channel: channel) // When - let leaveButton = viewModel.shouldShowAddUserButton + let leaveButton = viewModel.shouldShowAddMemberButton // Then XCTAssert(leaveButton == true) @@ -275,7 +275,7 @@ import XCTest let viewModel = ChatChannelInfoViewModel(channel: channel) // When - let leaveButton = viewModel.shouldShowAddUserButton + let leaveButton = viewModel.shouldShowAddMemberButton // Then XCTAssert(leaveButton == false) @@ -287,7 +287,7 @@ import XCTest let viewModel = ChatChannelInfoViewModel(channel: channel) // When - let leaveButton = viewModel.shouldShowAddUserButton + let leaveButton = viewModel.shouldShowAddMemberButton // Then XCTAssert(leaveButton == false) @@ -891,7 +891,7 @@ import XCTest // Then XCTAssertEqual(blockAction.title, L10n.Alert.Actions.blockUser) - XCTAssertEqual(blockAction.iconName, "icn_block_user") + XCTAssertEqual(blockAction.iconName, "nosign") XCTAssertFalse(blockAction.isDestructive) XCTAssertNotNil(blockAction.confirmationPopup) XCTAssertEqual(blockAction.confirmationPopup?.title, L10n.Alert.Actions.blockUser) diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/FileAttachmentsView_Tests.swift b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/FileAttachmentsView_Tests.swift index 84018d340..9aa2b0398 100644 --- a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/FileAttachmentsView_Tests.swift +++ b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/FileAttachmentsView_Tests.swift @@ -87,27 +87,4 @@ import XCTest // Then assertSnapshot(matching: view, as: .image(perceptualPrecision: precision)) } - - func test_fileAttachmentsView_withDownloadEnabled() { - // Given - let utils = Utils( - messageListConfig: MessageListConfig(downloadFileAttachmentsEnabled: true) - ) - streamChat = StreamChat(chatClient: chatClient, utils: utils) - - let messages = ChannelInfoMockUtils.generateMessagesWithPdfAttachments(count: 5) - let messageSearchController = ChatMessageSearchController_Mock.mock(client: chatClient) - messageSearchController.messages_mock = messages - let viewModel = FileAttachmentsViewModel( - channel: .mockDMChannel(), - messageSearchController: messageSearchController - ) - - // When - let view = FileAttachmentsView(viewModel: viewModel) - .applyDefaultSize() - - // Then - assertSnapshot(matching: view, as: .image(perceptualPrecision: precision)) - } } diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/AddUsersViewModel_Tests.swift b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/MemberAddViewModel_Tests.swift similarity index 77% rename from StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/AddUsersViewModel_Tests.swift rename to StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/MemberAddViewModel_Tests.swift index afde63329..8b346a531 100644 --- a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/AddUsersViewModel_Tests.swift +++ b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/MemberAddViewModel_Tests.swift @@ -8,14 +8,14 @@ import Combine @testable import StreamChatTestTools import XCTest -@MainActor class AddUsersViewModel_Tests: StreamChatTestCase { +@MainActor class MemberAddViewModel_Tests: StreamChatTestCase { private var cancellables = Set() - func test_addUsersViewModel_loadedUsers() { + func test_memberAddViewModel_loadedUsers() { // Given let searchController = ChatUserSearchController_Mock.mock(client: chatClient) searchController.users_mock = ChannelInfoMockUtils.generateMockUsers(count: 10) - let viewModel = AddUsersViewModel( + let viewModel = MemberAddViewModel( loadedUserIds: [], searchController: searchController ) @@ -27,17 +27,16 @@ import XCTest XCTAssert(users.count == 10) } - func test_addUsersViewModel_search() { + func test_memberAddViewModel_search() { // Given let searchController = ChatUserSearchController_Mock.mock(client: chatClient) searchController.users_mock = ChannelInfoMockUtils.generateMockUsers(count: 12) - let viewModel = AddUsersViewModel( + let viewModel = MemberAddViewModel( loadedUserIds: [], searchController: searchController ) let expectation = expectation(description: "search") - // Observe first, but ignore the initial value viewModel.$users .dropFirst() .first() @@ -53,12 +52,12 @@ import XCTest waitForExpectations(timeout: defaultTimeout) } - func test_addUsersViewModel_onUserAppear() { + func test_memberAddViewModel_onUserAppear() { // Given let searchController = ChatUserSearchController_Mock.mock(client: chatClient) var users = ChannelInfoMockUtils.generateMockUsers(count: 20) searchController.users_mock = users - let viewModel = AddUsersViewModel( + let viewModel = MemberAddViewModel( loadedUserIds: [], searchController: searchController ) @@ -76,12 +75,12 @@ import XCTest XCTAssert(afterLoad.count == 40) } - func test_addUsersViewModel_toggleUser_selectsUser() { + func test_memberAddViewModel_toggleUser_selectsUser() { // Given let searchController = ChatUserSearchController_Mock.mock(client: chatClient) let users = ChannelInfoMockUtils.generateMockUsers(count: 5) searchController.users_mock = users - let viewModel = AddUsersViewModel(loadedUserIds: [], searchController: searchController) + let viewModel = MemberAddViewModel(loadedUserIds: [], searchController: searchController) let user = viewModel.users[0] // When @@ -91,12 +90,12 @@ import XCTest XCTAssertTrue(viewModel.isSelected(user)) } - func test_addUsersViewModel_toggleUser_deselectsUser() { + func test_memberAddViewModel_toggleUser_deselectsUser() { // Given let searchController = ChatUserSearchController_Mock.mock(client: chatClient) let users = ChannelInfoMockUtils.generateMockUsers(count: 5) searchController.users_mock = users - let viewModel = AddUsersViewModel(loadedUserIds: [], searchController: searchController) + let viewModel = MemberAddViewModel(loadedUserIds: [], searchController: searchController) let user = viewModel.users[0] // When @@ -107,36 +106,36 @@ import XCTest XCTAssertFalse(viewModel.isSelected(user)) } - func test_addUsersViewModel_isAlreadyMember_trueForLoadedUser() { + func test_memberAddViewModel_isAlreadyMember_trueForLoadedUser() { // Given let users = ChannelInfoMockUtils.generateMockUsers(count: 5) let loadedUserIds = users.map(\.id) let searchController = ChatUserSearchController_Mock.mock(client: chatClient) searchController.users_mock = users - let viewModel = AddUsersViewModel(loadedUserIds: loadedUserIds, searchController: searchController) + let viewModel = MemberAddViewModel(loadedUserIds: loadedUserIds, searchController: searchController) // Then XCTAssertTrue(viewModel.isAlreadyMember(users[0])) XCTAssertTrue(viewModel.isAlreadyMember(users[4])) } - func test_addUsersViewModel_isAlreadyMember_falseForNewUser() { + func test_memberAddViewModel_isAlreadyMember_falseForNewUser() { // Given let users = ChannelInfoMockUtils.generateMockUsers(count: 5) let searchController = ChatUserSearchController_Mock.mock(client: chatClient) searchController.users_mock = users - let viewModel = AddUsersViewModel(loadedUserIds: [], searchController: searchController) + let viewModel = MemberAddViewModel(loadedUserIds: [], searchController: searchController) // Then XCTAssertFalse(viewModel.isAlreadyMember(users[0])) } - func test_addUsersViewModel_selectedUsers_returnsSelectedSubset() { + func test_memberAddViewModel_selectedUsers_returnsSelectedSubset() { // Given let searchController = ChatUserSearchController_Mock.mock(client: chatClient) let users = ChannelInfoMockUtils.generateMockUsers(count: 5) searchController.users_mock = users - let viewModel = AddUsersViewModel(loadedUserIds: [], searchController: searchController) + let viewModel = MemberAddViewModel(loadedUserIds: [], searchController: searchController) // When viewModel.toggleUser(viewModel.users[0]) diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/AddUsersView_Tests.swift b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/MemberAddView_Tests.swift similarity index 65% rename from StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/AddUsersView_Tests.swift rename to StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/MemberAddView_Tests.swift index b825ee1c5..6af939a07 100644 --- a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/AddUsersView_Tests.swift +++ b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/MemberAddView_Tests.swift @@ -10,31 +10,31 @@ import StreamSwiftTestHelpers import SwiftUI import XCTest -@MainActor class AddUsersView_Tests: StreamChatTestCase { - func test_addUsersView_snapshot() { +@MainActor class MemberAddView_Tests: StreamChatTestCase { + func test_memberAddView_snapshot() { // Given let searchController = ChatUserSearchController_Mock.mock(client: chatClient) let users = ChannelInfoMockUtils.generateMockUsers(count: 20) searchController.users_mock = users - let viewModel = AddUsersViewModel( + let viewModel = MemberAddViewModel( loadedUserIds: [], searchController: searchController ) // When - let view = AddUsersView(viewModel: viewModel, onConfirm: { _ in }) + let view = MemberAddView(factory: DefaultTestViewFactory.shared, viewModel: viewModel, onConfirm: { _ in }) .applyDefaultSize() // Then - assertSnapshot(matching: view, as: .image(perceptualPrecision: precision)) + AssertSnapshot(view) } - func test_addUsersView_selectedUsersSnapshot() { + func test_memberAddView_selectedUsersSnapshot() { // Given let searchController = ChatUserSearchController_Mock.mock(client: chatClient) let users = ChannelInfoMockUtils.generateMockUsers(count: 10) searchController.users_mock = users - let viewModel = AddUsersViewModel( + let viewModel = MemberAddViewModel( loadedUserIds: [], searchController: searchController ) @@ -42,29 +42,29 @@ import XCTest viewModel.toggleUser(users[3]) // When - let view = AddUsersView(viewModel: viewModel, onConfirm: { _ in }) + let view = MemberAddView(factory: DefaultTestViewFactory.shared, viewModel: viewModel, onConfirm: { _ in }) .applyDefaultSize() // Then - assertSnapshot(matching: view, as: .image(perceptualPrecision: precision)) + AssertSnapshot(view) } - func test_addUsersView_alreadyMemberSnapshot() { + func test_memberAddView_alreadyMemberSnapshot() { // Given let searchController = ChatUserSearchController_Mock.mock(client: chatClient) let users = ChannelInfoMockUtils.generateMockUsers(count: 10) searchController.users_mock = users let alreadyMemberIds = Array(users.prefix(3)).map(\.id) - let viewModel = AddUsersViewModel( + let viewModel = MemberAddViewModel( loadedUserIds: alreadyMemberIds, searchController: searchController ) // When - let view = AddUsersView(viewModel: viewModel, onConfirm: { _ in }) + let view = MemberAddView(factory: DefaultTestViewFactory.shared, viewModel: viewModel, onConfirm: { _ in }) .applyDefaultSize() // Then - assertSnapshot(matching: view, as: .image(perceptualPrecision: precision)) + AssertSnapshot(view) } } diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/MemberListView_Tests.swift b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/MemberListView_Tests.swift index 66a45698e..96ee00d17 100644 --- a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/MemberListView_Tests.swift +++ b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/MemberListView_Tests.swift @@ -28,7 +28,7 @@ import XCTest let viewModel = ChatChannelInfoViewModel(channel: group) // When - let view = MemberListView(viewModel: viewModel) + let view = MemberListView(factory: DefaultTestViewFactory.shared, viewModel: viewModel) .applyDefaultSize() // Then @@ -52,7 +52,7 @@ import XCTest let viewModel = ChatChannelInfoViewModel(channel: group) // When - let view = MemberListView(viewModel: viewModel) + let view = MemberListView(factory: DefaultTestViewFactory.shared, viewModel: viewModel) .applyDefaultSize() // Then diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/ParticipantInfoView_Tests.swift b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/ParticipantInfoView_Tests.swift index 4658759e9..dbfc2ceec 100644 --- a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/ParticipantInfoView_Tests.swift +++ b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/ParticipantInfoView_Tests.swift @@ -29,7 +29,7 @@ import XCTest ), ParticipantAction( title: L10n.Alert.Actions.blockUser, - iconName: "icn_block_user", + iconName: "nosign", action: {}, confirmationPopup: nil, isDestructive: false @@ -58,7 +58,7 @@ import XCTest let actions: [ParticipantAction] = [ ParticipantAction( title: L10n.Alert.Actions.blockUser, - iconName: "icn_block_user", + iconName: "nosign", action: {}, confirmationPopup: nil, isDestructive: false diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/AddUsersView_Tests/test_addUsersView_alreadyMemberSnapshot.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/AddUsersView_Tests/test_addUsersView_alreadyMemberSnapshot.1.png deleted file mode 100644 index e30f57cd7..000000000 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/AddUsersView_Tests/test_addUsersView_alreadyMemberSnapshot.1.png and /dev/null differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/AddUsersView_Tests/test_addUsersView_selectedUsersSnapshot.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/AddUsersView_Tests/test_addUsersView_selectedUsersSnapshot.1.png deleted file mode 100644 index c71ab3a36..000000000 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/AddUsersView_Tests/test_addUsersView_selectedUsersSnapshot.1.png and /dev/null differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/AddUsersView_Tests/test_addUsersView_snapshot.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/AddUsersView_Tests/test_addUsersView_snapshot.1.png deleted file mode 100644 index 8a43f7717..000000000 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/AddUsersView_Tests/test_addUsersView_snapshot.1.png and /dev/null differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_addUsersShownSnapshot.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_addUsersShownSnapshot.default-light.png index 4dff50cb7..9d7b8458f 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_addUsersShownSnapshot.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_addUsersShownSnapshot.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_addUsersShownSnapshot.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_addUsersShownSnapshot.extraExtraExtraLarge-light.png index 637e9de0a..bcd5704c6 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_addUsersShownSnapshot.extraExtraExtraLarge-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_addUsersShownSnapshot.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_addUsersShownSnapshot.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_addUsersShownSnapshot.rightToLeftLayout-default.png index 75204b0e2..3916ab9a7 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_addUsersShownSnapshot.rightToLeftLayout-default.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_addUsersShownSnapshot.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_addUsersShownSnapshot.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_addUsersShownSnapshot.small-dark.png index 9a682eb7f..48ff04373 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_addUsersShownSnapshot.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_addUsersShownSnapshot.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_currentUserRowTappableSnapshot.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_currentUserRowTappableSnapshot.default-light.png index 9f7c5124e..b95d339d9 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_currentUserRowTappableSnapshot.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_currentUserRowTappableSnapshot.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_currentUserRowTappableSnapshot.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_currentUserRowTappableSnapshot.extraExtraExtraLarge-light.png index f6246ece2..cf1939e92 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_currentUserRowTappableSnapshot.extraExtraExtraLarge-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_currentUserRowTappableSnapshot.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_currentUserRowTappableSnapshot.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_currentUserRowTappableSnapshot.rightToLeftLayout-default.png index e702b99d2..027b760c0 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_currentUserRowTappableSnapshot.rightToLeftLayout-default.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_currentUserRowTappableSnapshot.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_currentUserRowTappableSnapshot.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_currentUserRowTappableSnapshot.small-dark.png index f28642af0..f5ed65239 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_currentUserRowTappableSnapshot.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_currentUserRowTappableSnapshot.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_directChannelMoreMembersSnapshot.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_directChannelMoreMembersSnapshot.default-light.png index 2b00eae19..4a88f994b 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_directChannelMoreMembersSnapshot.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_directChannelMoreMembersSnapshot.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_directChannelMoreMembersSnapshot.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_directChannelMoreMembersSnapshot.extraExtraExtraLarge-light.png index 2c833058b..ba399c41d 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_directChannelMoreMembersSnapshot.extraExtraExtraLarge-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_directChannelMoreMembersSnapshot.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_directChannelMoreMembersSnapshot.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_directChannelMoreMembersSnapshot.rightToLeftLayout-default.png index cd5efffcf..6264c9484 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_directChannelMoreMembersSnapshot.rightToLeftLayout-default.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_directChannelMoreMembersSnapshot.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_directChannelMoreMembersSnapshot.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_directChannelMoreMembersSnapshot.small-dark.png index 7a53ed1fb..ed177047d 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_directChannelMoreMembersSnapshot.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_directChannelMoreMembersSnapshot.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_directChannelMutedSnapshot.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_directChannelMutedSnapshot.default-light.png index 6b0c4614d..319d593ae 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_directChannelMutedSnapshot.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_directChannelMutedSnapshot.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_directChannelMutedSnapshot.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_directChannelMutedSnapshot.extraExtraExtraLarge-light.png index df4f3a39a..7546cca66 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_directChannelMutedSnapshot.extraExtraExtraLarge-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_directChannelMutedSnapshot.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_directChannelMutedSnapshot.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_directChannelMutedSnapshot.rightToLeftLayout-default.png index a03db0f68..d782b0dc2 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_directChannelMutedSnapshot.rightToLeftLayout-default.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_directChannelMutedSnapshot.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_directChannelMutedSnapshot.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_directChannelMutedSnapshot.small-dark.png index 54fb253e2..08baf8fbd 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_directChannelMutedSnapshot.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_directChannelMutedSnapshot.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_directChannelOfflineSnapshot.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_directChannelOfflineSnapshot.default-light.png index 462fbe7d7..0d363e784 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_directChannelOfflineSnapshot.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_directChannelOfflineSnapshot.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_directChannelOfflineSnapshot.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_directChannelOfflineSnapshot.extraExtraExtraLarge-light.png index 034b60596..308db1100 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_directChannelOfflineSnapshot.extraExtraExtraLarge-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_directChannelOfflineSnapshot.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_directChannelOfflineSnapshot.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_directChannelOfflineSnapshot.rightToLeftLayout-default.png index 18f343c6b..d8d61f25f 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_directChannelOfflineSnapshot.rightToLeftLayout-default.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_directChannelOfflineSnapshot.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_directChannelOfflineSnapshot.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_directChannelOfflineSnapshot.small-dark.png index 91840180d..e5ba7f149 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_directChannelOfflineSnapshot.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_directChannelOfflineSnapshot.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_directChannelOnlineSnapshot.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_directChannelOnlineSnapshot.default-light.png index 8cf9a1745..e47ba1e33 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_directChannelOnlineSnapshot.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_directChannelOnlineSnapshot.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_directChannelOnlineSnapshot.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_directChannelOnlineSnapshot.extraExtraExtraLarge-light.png index 35157c9d5..1a4c4c970 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_directChannelOnlineSnapshot.extraExtraExtraLarge-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_directChannelOnlineSnapshot.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_directChannelOnlineSnapshot.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_directChannelOnlineSnapshot.rightToLeftLayout-default.png index bd1bd4a3f..a8c2e8cbe 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_directChannelOnlineSnapshot.rightToLeftLayout-default.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_directChannelOnlineSnapshot.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_directChannelOnlineSnapshot.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_directChannelOnlineSnapshot.small-dark.png index 87e5ce29f..343cea990 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_directChannelOnlineSnapshot.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_directChannelOnlineSnapshot.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_groupCollapsedDeactivatedSnapshot.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_groupCollapsedDeactivatedSnapshot.default-light.png index cc2be68fb..308f7d084 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_groupCollapsedDeactivatedSnapshot.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_groupCollapsedDeactivatedSnapshot.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_groupCollapsedDeactivatedSnapshot.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_groupCollapsedDeactivatedSnapshot.extraExtraExtraLarge-light.png index bba6e90a4..57030e648 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_groupCollapsedDeactivatedSnapshot.extraExtraExtraLarge-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_groupCollapsedDeactivatedSnapshot.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_groupCollapsedDeactivatedSnapshot.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_groupCollapsedDeactivatedSnapshot.rightToLeftLayout-default.png index 5aba23ed6..f4369ea2f 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_groupCollapsedDeactivatedSnapshot.rightToLeftLayout-default.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_groupCollapsedDeactivatedSnapshot.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_groupCollapsedDeactivatedSnapshot.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_groupCollapsedDeactivatedSnapshot.small-dark.png index 30a08d424..021d69182 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_groupCollapsedDeactivatedSnapshot.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_groupCollapsedDeactivatedSnapshot.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_groupCollapsedLargeDeactivatedSnapshot.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_groupCollapsedLargeDeactivatedSnapshot.default-light.png index 4dff50cb7..9d7b8458f 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_groupCollapsedLargeDeactivatedSnapshot.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_groupCollapsedLargeDeactivatedSnapshot.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_groupCollapsedLargeDeactivatedSnapshot.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_groupCollapsedLargeDeactivatedSnapshot.extraExtraExtraLarge-light.png index 637e9de0a..bcd5704c6 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_groupCollapsedLargeDeactivatedSnapshot.extraExtraExtraLarge-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_groupCollapsedLargeDeactivatedSnapshot.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_groupCollapsedLargeDeactivatedSnapshot.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_groupCollapsedLargeDeactivatedSnapshot.rightToLeftLayout-default.png index 75204b0e2..3916ab9a7 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_groupCollapsedLargeDeactivatedSnapshot.rightToLeftLayout-default.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_groupCollapsedLargeDeactivatedSnapshot.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_groupCollapsedLargeDeactivatedSnapshot.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_groupCollapsedLargeDeactivatedSnapshot.small-dark.png index 9a682eb7f..48ff04373 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_groupCollapsedLargeDeactivatedSnapshot.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_groupCollapsedLargeDeactivatedSnapshot.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_groupCollapsedSnapshot.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_groupCollapsedSnapshot.default-light.png index 4dff50cb7..9d7b8458f 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_groupCollapsedSnapshot.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_groupCollapsedSnapshot.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_groupCollapsedSnapshot.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_groupCollapsedSnapshot.extraExtraExtraLarge-light.png index 637e9de0a..bcd5704c6 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_groupCollapsedSnapshot.extraExtraExtraLarge-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_groupCollapsedSnapshot.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_groupCollapsedSnapshot.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_groupCollapsedSnapshot.rightToLeftLayout-default.png index 75204b0e2..3916ab9a7 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_groupCollapsedSnapshot.rightToLeftLayout-default.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_groupCollapsedSnapshot.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_groupCollapsedSnapshot.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_groupCollapsedSnapshot.small-dark.png index 9a682eb7f..48ff04373 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_groupCollapsedSnapshot.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_groupCollapsedSnapshot.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_groupExpandedSnapshot.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_groupExpandedSnapshot.default-light.png index 4dff50cb7..9d7b8458f 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_groupExpandedSnapshot.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_groupExpandedSnapshot.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_groupExpandedSnapshot.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_groupExpandedSnapshot.extraExtraExtraLarge-light.png index 637e9de0a..bcd5704c6 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_groupExpandedSnapshot.extraExtraExtraLarge-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_groupExpandedSnapshot.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_groupExpandedSnapshot.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_groupExpandedSnapshot.rightToLeftLayout-default.png index 75204b0e2..3916ab9a7 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_groupExpandedSnapshot.rightToLeftLayout-default.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_groupExpandedSnapshot.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_groupExpandedSnapshot.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_groupExpandedSnapshot.small-dark.png index 9a682eb7f..48ff04373 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_groupExpandedSnapshot.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_groupExpandedSnapshot.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_multiPersonDMSnapshot.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_multiPersonDMSnapshot.default-light.png index 5b2cc0295..13bbd7bd4 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_multiPersonDMSnapshot.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_multiPersonDMSnapshot.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_multiPersonDMSnapshot.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_multiPersonDMSnapshot.extraExtraExtraLarge-light.png index 78bbaf441..87ef8b2f6 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_multiPersonDMSnapshot.extraExtraExtraLarge-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_multiPersonDMSnapshot.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_multiPersonDMSnapshot.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_multiPersonDMSnapshot.rightToLeftLayout-default.png index b73274180..03c375e49 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_multiPersonDMSnapshot.rightToLeftLayout-default.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_multiPersonDMSnapshot.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_multiPersonDMSnapshot.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_multiPersonDMSnapshot.small-dark.png index 17466cf50..ad1e12b2a 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_multiPersonDMSnapshot.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_multiPersonDMSnapshot.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_navBarSnapshot.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_navBarSnapshot.1.png index 70f6aa17d..13373c99b 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_navBarSnapshot.1.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_navBarSnapshot.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_navigationBarAppearance.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_navigationBarAppearance.default-light.png index a76421ce7..e0d8f8a6b 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_navigationBarAppearance.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_navigationBarAppearance.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_navigationBarAppearance.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_navigationBarAppearance.extraExtraExtraLarge-light.png index 934ec3c84..668709847 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_navigationBarAppearance.extraExtraExtraLarge-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_navigationBarAppearance.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_navigationBarAppearance.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_navigationBarAppearance.rightToLeftLayout-default.png index 4a9cb14e4..f2385f204 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_navigationBarAppearance.rightToLeftLayout-default.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_navigationBarAppearance.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_navigationBarAppearance.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_navigationBarAppearance.small-dark.png index 9d1fc9a3c..6c9f2a934 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_navigationBarAppearance.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_navigationBarAppearance.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_participantSelectedBasicActionsSnapshot.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_participantSelectedBasicActionsSnapshot.default-light.png index 2232354a9..0a5372859 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_participantSelectedBasicActionsSnapshot.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_participantSelectedBasicActionsSnapshot.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_participantSelectedBasicActionsSnapshot.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_participantSelectedBasicActionsSnapshot.extraExtraExtraLarge-light.png index f99882724..29c20b061 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_participantSelectedBasicActionsSnapshot.extraExtraExtraLarge-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_participantSelectedBasicActionsSnapshot.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_participantSelectedBasicActionsSnapshot.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_participantSelectedBasicActionsSnapshot.rightToLeftLayout-default.png index 40cf72367..7145cd1b6 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_participantSelectedBasicActionsSnapshot.rightToLeftLayout-default.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_participantSelectedBasicActionsSnapshot.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_participantSelectedBasicActionsSnapshot.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_participantSelectedBasicActionsSnapshot.small-dark.png index aa6ea076a..91d7eb9c1 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_participantSelectedBasicActionsSnapshot.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_participantSelectedBasicActionsSnapshot.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_participantSelectedOfflineUserSnapshot.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_participantSelectedOfflineUserSnapshot.default-light.png index 08f9fbe14..2e923779b 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_participantSelectedOfflineUserSnapshot.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_participantSelectedOfflineUserSnapshot.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_participantSelectedOfflineUserSnapshot.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_participantSelectedOfflineUserSnapshot.extraExtraExtraLarge-light.png index 3fd3fee3b..0a1fc19f3 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_participantSelectedOfflineUserSnapshot.extraExtraExtraLarge-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_participantSelectedOfflineUserSnapshot.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_participantSelectedOfflineUserSnapshot.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_participantSelectedOfflineUserSnapshot.rightToLeftLayout-default.png index 8bd8cffec..52cf3c44d 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_participantSelectedOfflineUserSnapshot.rightToLeftLayout-default.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_participantSelectedOfflineUserSnapshot.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_participantSelectedOfflineUserSnapshot.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_participantSelectedOfflineUserSnapshot.small-dark.png index 7190b3f2d..2bab6dede 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_participantSelectedOfflineUserSnapshot.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_participantSelectedOfflineUserSnapshot.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_participantSelectedWithMuteActionsSnapshot.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_participantSelectedWithMuteActionsSnapshot.default-light.png index 2232354a9..0a5372859 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_participantSelectedWithMuteActionsSnapshot.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_participantSelectedWithMuteActionsSnapshot.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_participantSelectedWithMuteActionsSnapshot.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_participantSelectedWithMuteActionsSnapshot.extraExtraExtraLarge-light.png index f99882724..29c20b061 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_participantSelectedWithMuteActionsSnapshot.extraExtraExtraLarge-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_participantSelectedWithMuteActionsSnapshot.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_participantSelectedWithMuteActionsSnapshot.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_participantSelectedWithMuteActionsSnapshot.rightToLeftLayout-default.png index 40cf72367..7145cd1b6 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_participantSelectedWithMuteActionsSnapshot.rightToLeftLayout-default.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_participantSelectedWithMuteActionsSnapshot.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_participantSelectedWithMuteActionsSnapshot.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_participantSelectedWithMuteActionsSnapshot.small-dark.png index aa6ea076a..91d7eb9c1 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_participantSelectedWithMuteActionsSnapshot.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_participantSelectedWithMuteActionsSnapshot.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_participantSelectedWithRemoveActionSnapshot.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_participantSelectedWithRemoveActionSnapshot.default-light.png index 2232354a9..0a5372859 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_participantSelectedWithRemoveActionSnapshot.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_participantSelectedWithRemoveActionSnapshot.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_participantSelectedWithRemoveActionSnapshot.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_participantSelectedWithRemoveActionSnapshot.extraExtraExtraLarge-light.png index f99882724..29c20b061 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_participantSelectedWithRemoveActionSnapshot.extraExtraExtraLarge-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_participantSelectedWithRemoveActionSnapshot.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_participantSelectedWithRemoveActionSnapshot.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_participantSelectedWithRemoveActionSnapshot.rightToLeftLayout-default.png index 40cf72367..7145cd1b6 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_participantSelectedWithRemoveActionSnapshot.rightToLeftLayout-default.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_participantSelectedWithRemoveActionSnapshot.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_participantSelectedWithRemoveActionSnapshot.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_participantSelectedWithRemoveActionSnapshot.small-dark.png index aa6ea076a..91d7eb9c1 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_participantSelectedWithRemoveActionSnapshot.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_participantSelectedWithRemoveActionSnapshot.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_rtlSnapshot.rtl.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_rtlSnapshot.rtl.png index e93b636a9..3f0c03c07 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_rtlSnapshot.rtl.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_rtlSnapshot.rtl.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_smallGroupDeactivatedSnapshot.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_smallGroupDeactivatedSnapshot.default-light.png index 5855a9508..de67edc2d 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_smallGroupDeactivatedSnapshot.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_smallGroupDeactivatedSnapshot.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_smallGroupDeactivatedSnapshot.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_smallGroupDeactivatedSnapshot.extraExtraExtraLarge-light.png index 6a2c8c486..f0a6666a8 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_smallGroupDeactivatedSnapshot.extraExtraExtraLarge-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_smallGroupDeactivatedSnapshot.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_smallGroupDeactivatedSnapshot.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_smallGroupDeactivatedSnapshot.rightToLeftLayout-default.png index 54de32be7..f7da02671 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_smallGroupDeactivatedSnapshot.rightToLeftLayout-default.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_smallGroupDeactivatedSnapshot.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_smallGroupDeactivatedSnapshot.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_smallGroupDeactivatedSnapshot.small-dark.png index d90415a79..5911cf230 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_smallGroupDeactivatedSnapshot.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_smallGroupDeactivatedSnapshot.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_smallGroupSnapshot.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_smallGroupSnapshot.default-light.png index a63bbfe5d..f664262bf 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_smallGroupSnapshot.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_smallGroupSnapshot.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_smallGroupSnapshot.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_smallGroupSnapshot.extraExtraExtraLarge-light.png index fca73c57a..eb9a5b2a2 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_smallGroupSnapshot.extraExtraExtraLarge-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_smallGroupSnapshot.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_smallGroupSnapshot.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_smallGroupSnapshot.rightToLeftLayout-default.png index 88b08f874..6f0fe87e2 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_smallGroupSnapshot.rightToLeftLayout-default.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_smallGroupSnapshot.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_smallGroupSnapshot.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_smallGroupSnapshot.small-dark.png index 8b0f3d2c6..8e493c918 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_smallGroupSnapshot.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_smallGroupSnapshot.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_smallGroupWithLeaveButtonSnapshot.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_smallGroupWithLeaveButtonSnapshot.default-light.png index a49f825d2..b59972402 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_smallGroupWithLeaveButtonSnapshot.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_smallGroupWithLeaveButtonSnapshot.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_smallGroupWithLeaveButtonSnapshot.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_smallGroupWithLeaveButtonSnapshot.extraExtraExtraLarge-light.png index 5098901a6..5763b4cd7 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_smallGroupWithLeaveButtonSnapshot.extraExtraExtraLarge-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_smallGroupWithLeaveButtonSnapshot.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_smallGroupWithLeaveButtonSnapshot.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_smallGroupWithLeaveButtonSnapshot.rightToLeftLayout-default.png index 22b0f7fd3..1049dafd2 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_smallGroupWithLeaveButtonSnapshot.rightToLeftLayout-default.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_smallGroupWithLeaveButtonSnapshot.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_smallGroupWithLeaveButtonSnapshot.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_smallGroupWithLeaveButtonSnapshot.small-dark.png index bc54c25e0..efc2f9edf 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_smallGroupWithLeaveButtonSnapshot.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ChatChannelInfoView_Tests/test_chatChannelInfoView_smallGroupWithLeaveButtonSnapshot.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/EditGroupView_Tests/test_editGroupView_snapshot.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/EditGroupView_Tests/test_editGroupView_snapshot.default-light.png index 14a2d26ed..ef0283f51 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/EditGroupView_Tests/test_editGroupView_snapshot.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/EditGroupView_Tests/test_editGroupView_snapshot.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/EditGroupView_Tests/test_editGroupView_snapshot.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/EditGroupView_Tests/test_editGroupView_snapshot.extraExtraExtraLarge-light.png index f4e1caa83..c813c5e3b 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/EditGroupView_Tests/test_editGroupView_snapshot.extraExtraExtraLarge-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/EditGroupView_Tests/test_editGroupView_snapshot.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/EditGroupView_Tests/test_editGroupView_snapshot.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/EditGroupView_Tests/test_editGroupView_snapshot.rightToLeftLayout-default.png index df7d47f9e..1ec4c046a 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/EditGroupView_Tests/test_editGroupView_snapshot.rightToLeftLayout-default.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/EditGroupView_Tests/test_editGroupView_snapshot.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/EditGroupView_Tests/test_editGroupView_snapshot.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/EditGroupView_Tests/test_editGroupView_snapshot.small-dark.png index 56db0e2ee..db7e4f7ba 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/EditGroupView_Tests/test_editGroupView_snapshot.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/EditGroupView_Tests/test_editGroupView_snapshot.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/EditGroupView_Tests/test_editGroupView_uploadingSnapshot.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/EditGroupView_Tests/test_editGroupView_uploadingSnapshot.small-dark.png index 5d6fed26c..be022dbb6 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/EditGroupView_Tests/test_editGroupView_uploadingSnapshot.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/EditGroupView_Tests/test_editGroupView_uploadingSnapshot.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/EditGroupView_Tests/test_groupAvatarPickerSheetView_snapshot.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/EditGroupView_Tests/test_groupAvatarPickerSheetView_snapshot.default-light.png index fe9812349..63243288a 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/EditGroupView_Tests/test_groupAvatarPickerSheetView_snapshot.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/EditGroupView_Tests/test_groupAvatarPickerSheetView_snapshot.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/EditGroupView_Tests/test_groupAvatarPickerSheetView_snapshot.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/EditGroupView_Tests/test_groupAvatarPickerSheetView_snapshot.extraExtraExtraLarge-light.png index 6157ab395..3928ea0fa 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/EditGroupView_Tests/test_groupAvatarPickerSheetView_snapshot.extraExtraExtraLarge-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/EditGroupView_Tests/test_groupAvatarPickerSheetView_snapshot.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/EditGroupView_Tests/test_groupAvatarPickerSheetView_snapshot.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/EditGroupView_Tests/test_groupAvatarPickerSheetView_snapshot.rightToLeftLayout-default.png index ff5e96e59..5f53e7ae4 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/EditGroupView_Tests/test_groupAvatarPickerSheetView_snapshot.rightToLeftLayout-default.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/EditGroupView_Tests/test_groupAvatarPickerSheetView_snapshot.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/EditGroupView_Tests/test_groupAvatarPickerSheetView_snapshot.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/EditGroupView_Tests/test_groupAvatarPickerSheetView_snapshot.small-dark.png index 5fcc37745..294ba0c97 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/EditGroupView_Tests/test_groupAvatarPickerSheetView_snapshot.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/EditGroupView_Tests/test_groupAvatarPickerSheetView_snapshot.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/FileAttachmentsView_Tests/test_fileAttachmentsView_emptySnapshot.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/FileAttachmentsView_Tests/test_fileAttachmentsView_emptySnapshot.small-dark.png index a05eb1835..96cb381a8 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/FileAttachmentsView_Tests/test_fileAttachmentsView_emptySnapshot.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/FileAttachmentsView_Tests/test_fileAttachmentsView_emptySnapshot.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/FileAttachmentsView_Tests/test_fileAttachmentsView_withDownloadEnabled.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/FileAttachmentsView_Tests/test_fileAttachmentsView_withDownloadEnabled.1.png deleted file mode 100644 index 5d90e3c24..000000000 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/FileAttachmentsView_Tests/test_fileAttachmentsView_withDownloadEnabled.1.png and /dev/null differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/MediaAttachmentsView_Tests/test_mediaAttachmentsView_emptySnapshot.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/MediaAttachmentsView_Tests/test_mediaAttachmentsView_emptySnapshot.small-dark.png index 0b8a10e69..816a53e38 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/MediaAttachmentsView_Tests/test_mediaAttachmentsView_emptySnapshot.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/MediaAttachmentsView_Tests/test_mediaAttachmentsView_emptySnapshot.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/MediaAttachmentsView_Tests/test_mediaAttachmentsView_iPadSnapshot.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/MediaAttachmentsView_Tests/test_mediaAttachmentsView_iPadSnapshot.default-light.png index 195bfa657..4f7e09e83 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/MediaAttachmentsView_Tests/test_mediaAttachmentsView_iPadSnapshot.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/MediaAttachmentsView_Tests/test_mediaAttachmentsView_iPadSnapshot.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/MediaAttachmentsView_Tests/test_mediaAttachmentsView_iPadSnapshot.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/MediaAttachmentsView_Tests/test_mediaAttachmentsView_iPadSnapshot.extraExtraExtraLarge-light.png index 195bfa657..4f7e09e83 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/MediaAttachmentsView_Tests/test_mediaAttachmentsView_iPadSnapshot.extraExtraExtraLarge-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/MediaAttachmentsView_Tests/test_mediaAttachmentsView_iPadSnapshot.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/MediaAttachmentsView_Tests/test_mediaAttachmentsView_iPadSnapshot.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/MediaAttachmentsView_Tests/test_mediaAttachmentsView_iPadSnapshot.rightToLeftLayout-default.png index a77e49949..b29ed5e82 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/MediaAttachmentsView_Tests/test_mediaAttachmentsView_iPadSnapshot.rightToLeftLayout-default.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/MediaAttachmentsView_Tests/test_mediaAttachmentsView_iPadSnapshot.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/MediaAttachmentsView_Tests/test_mediaAttachmentsView_iPadSnapshot.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/MediaAttachmentsView_Tests/test_mediaAttachmentsView_iPadSnapshot.small-dark.png index 2246efba7..ddebdf08b 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/MediaAttachmentsView_Tests/test_mediaAttachmentsView_iPadSnapshot.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/MediaAttachmentsView_Tests/test_mediaAttachmentsView_iPadSnapshot.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/MediaAttachmentsView_Tests/test_mediaAttachmentsView_notEmptySnapshot.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/MediaAttachmentsView_Tests/test_mediaAttachmentsView_notEmptySnapshot.default-light.png index 0ec2020cc..320304228 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/MediaAttachmentsView_Tests/test_mediaAttachmentsView_notEmptySnapshot.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/MediaAttachmentsView_Tests/test_mediaAttachmentsView_notEmptySnapshot.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/MediaAttachmentsView_Tests/test_mediaAttachmentsView_notEmptySnapshot.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/MediaAttachmentsView_Tests/test_mediaAttachmentsView_notEmptySnapshot.extraExtraExtraLarge-light.png index 0ec2020cc..320304228 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/MediaAttachmentsView_Tests/test_mediaAttachmentsView_notEmptySnapshot.extraExtraExtraLarge-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/MediaAttachmentsView_Tests/test_mediaAttachmentsView_notEmptySnapshot.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/MediaAttachmentsView_Tests/test_mediaAttachmentsView_notEmptySnapshot.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/MediaAttachmentsView_Tests/test_mediaAttachmentsView_notEmptySnapshot.rightToLeftLayout-default.png index f46c0513d..29a76cb0b 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/MediaAttachmentsView_Tests/test_mediaAttachmentsView_notEmptySnapshot.rightToLeftLayout-default.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/MediaAttachmentsView_Tests/test_mediaAttachmentsView_notEmptySnapshot.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/MediaAttachmentsView_Tests/test_mediaAttachmentsView_notEmptySnapshot.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/MediaAttachmentsView_Tests/test_mediaAttachmentsView_notEmptySnapshot.small-dark.png index 412ffe54a..4f25a0a04 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/MediaAttachmentsView_Tests/test_mediaAttachmentsView_notEmptySnapshot.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/MediaAttachmentsView_Tests/test_mediaAttachmentsView_notEmptySnapshot.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/MediaAttachmentsView_Tests/test_mediaAttachmentsView_themedSnapshot.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/MediaAttachmentsView_Tests/test_mediaAttachmentsView_themedSnapshot.default-light.png index 6af854fd1..3a16f746e 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/MediaAttachmentsView_Tests/test_mediaAttachmentsView_themedSnapshot.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/MediaAttachmentsView_Tests/test_mediaAttachmentsView_themedSnapshot.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/MediaAttachmentsView_Tests/test_mediaAttachmentsView_themedSnapshot.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/MediaAttachmentsView_Tests/test_mediaAttachmentsView_themedSnapshot.extraExtraExtraLarge-light.png index f8ad38d29..a518299e2 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/MediaAttachmentsView_Tests/test_mediaAttachmentsView_themedSnapshot.extraExtraExtraLarge-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/MediaAttachmentsView_Tests/test_mediaAttachmentsView_themedSnapshot.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/MediaAttachmentsView_Tests/test_mediaAttachmentsView_themedSnapshot.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/MediaAttachmentsView_Tests/test_mediaAttachmentsView_themedSnapshot.rightToLeftLayout-default.png index dda1582b5..e01a473dc 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/MediaAttachmentsView_Tests/test_mediaAttachmentsView_themedSnapshot.rightToLeftLayout-default.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/MediaAttachmentsView_Tests/test_mediaAttachmentsView_themedSnapshot.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/MediaAttachmentsView_Tests/test_mediaAttachmentsView_themedSnapshot.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/MediaAttachmentsView_Tests/test_mediaAttachmentsView_themedSnapshot.small-dark.png index 78be215f9..968c6b3c7 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/MediaAttachmentsView_Tests/test_mediaAttachmentsView_themedSnapshot.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/MediaAttachmentsView_Tests/test_mediaAttachmentsView_themedSnapshot.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/MemberAddView_Tests/test_memberAddView_alreadyMemberSnapshot.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/MemberAddView_Tests/test_memberAddView_alreadyMemberSnapshot.default-light.png new file mode 100644 index 000000000..f373fb802 Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/MemberAddView_Tests/test_memberAddView_alreadyMemberSnapshot.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/MemberAddView_Tests/test_memberAddView_alreadyMemberSnapshot.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/MemberAddView_Tests/test_memberAddView_alreadyMemberSnapshot.extraExtraExtraLarge-light.png new file mode 100644 index 000000000..31e436eb1 Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/MemberAddView_Tests/test_memberAddView_alreadyMemberSnapshot.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/MemberAddView_Tests/test_memberAddView_alreadyMemberSnapshot.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/MemberAddView_Tests/test_memberAddView_alreadyMemberSnapshot.rightToLeftLayout-default.png new file mode 100644 index 000000000..cb9e13e88 Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/MemberAddView_Tests/test_memberAddView_alreadyMemberSnapshot.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/MemberAddView_Tests/test_memberAddView_alreadyMemberSnapshot.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/MemberAddView_Tests/test_memberAddView_alreadyMemberSnapshot.small-dark.png new file mode 100644 index 000000000..1afa546dd Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/MemberAddView_Tests/test_memberAddView_alreadyMemberSnapshot.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/MemberAddView_Tests/test_memberAddView_selectedUsersSnapshot.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/MemberAddView_Tests/test_memberAddView_selectedUsersSnapshot.default-light.png new file mode 100644 index 000000000..051aecdca Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/MemberAddView_Tests/test_memberAddView_selectedUsersSnapshot.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/MemberAddView_Tests/test_memberAddView_selectedUsersSnapshot.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/MemberAddView_Tests/test_memberAddView_selectedUsersSnapshot.extraExtraExtraLarge-light.png new file mode 100644 index 000000000..5ffac081a Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/MemberAddView_Tests/test_memberAddView_selectedUsersSnapshot.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/MemberAddView_Tests/test_memberAddView_selectedUsersSnapshot.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/MemberAddView_Tests/test_memberAddView_selectedUsersSnapshot.rightToLeftLayout-default.png new file mode 100644 index 000000000..667233b94 Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/MemberAddView_Tests/test_memberAddView_selectedUsersSnapshot.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/MemberAddView_Tests/test_memberAddView_selectedUsersSnapshot.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/MemberAddView_Tests/test_memberAddView_selectedUsersSnapshot.small-dark.png new file mode 100644 index 000000000..9848fc5bf Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/MemberAddView_Tests/test_memberAddView_selectedUsersSnapshot.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/MemberAddView_Tests/test_memberAddView_snapshot.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/MemberAddView_Tests/test_memberAddView_snapshot.default-light.png new file mode 100644 index 000000000..ca8e1cd13 Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/MemberAddView_Tests/test_memberAddView_snapshot.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/MemberAddView_Tests/test_memberAddView_snapshot.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/MemberAddView_Tests/test_memberAddView_snapshot.extraExtraExtraLarge-light.png new file mode 100644 index 000000000..8e13f9754 Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/MemberAddView_Tests/test_memberAddView_snapshot.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/MemberAddView_Tests/test_memberAddView_snapshot.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/MemberAddView_Tests/test_memberAddView_snapshot.rightToLeftLayout-default.png new file mode 100644 index 000000000..86fdd6c52 Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/MemberAddView_Tests/test_memberAddView_snapshot.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/MemberAddView_Tests/test_memberAddView_snapshot.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/MemberAddView_Tests/test_memberAddView_snapshot.small-dark.png new file mode 100644 index 000000000..b2796eb45 Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/MemberAddView_Tests/test_memberAddView_snapshot.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/MemberListView_Tests/test_memberListView_withAddButtonSnapshot.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/MemberListView_Tests/test_memberListView_withAddButtonSnapshot.default-light.png index aee9f9495..6487562d0 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/MemberListView_Tests/test_memberListView_withAddButtonSnapshot.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/MemberListView_Tests/test_memberListView_withAddButtonSnapshot.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/MemberListView_Tests/test_memberListView_withAddButtonSnapshot.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/MemberListView_Tests/test_memberListView_withAddButtonSnapshot.extraExtraExtraLarge-light.png index 821f24649..01d9dfff6 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/MemberListView_Tests/test_memberListView_withAddButtonSnapshot.extraExtraExtraLarge-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/MemberListView_Tests/test_memberListView_withAddButtonSnapshot.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/MemberListView_Tests/test_memberListView_withAddButtonSnapshot.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/MemberListView_Tests/test_memberListView_withAddButtonSnapshot.rightToLeftLayout-default.png index dea212f54..5dc091f88 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/MemberListView_Tests/test_memberListView_withAddButtonSnapshot.rightToLeftLayout-default.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/MemberListView_Tests/test_memberListView_withAddButtonSnapshot.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/MemberListView_Tests/test_memberListView_withAddButtonSnapshot.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/MemberListView_Tests/test_memberListView_withAddButtonSnapshot.small-dark.png index 273392384..7de18e925 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/MemberListView_Tests/test_memberListView_withAddButtonSnapshot.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/MemberListView_Tests/test_memberListView_withAddButtonSnapshot.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/MemberListView_Tests/test_memberListView_withoutAddButtonSnapshot.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/MemberListView_Tests/test_memberListView_withoutAddButtonSnapshot.default-light.png index 0a8b1ce88..b70f304e9 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/MemberListView_Tests/test_memberListView_withoutAddButtonSnapshot.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/MemberListView_Tests/test_memberListView_withoutAddButtonSnapshot.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/MemberListView_Tests/test_memberListView_withoutAddButtonSnapshot.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/MemberListView_Tests/test_memberListView_withoutAddButtonSnapshot.extraExtraExtraLarge-light.png index 179fd1118..2d1322c69 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/MemberListView_Tests/test_memberListView_withoutAddButtonSnapshot.extraExtraExtraLarge-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/MemberListView_Tests/test_memberListView_withoutAddButtonSnapshot.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/MemberListView_Tests/test_memberListView_withoutAddButtonSnapshot.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/MemberListView_Tests/test_memberListView_withoutAddButtonSnapshot.rightToLeftLayout-default.png index a4a588844..acd2b2465 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/MemberListView_Tests/test_memberListView_withoutAddButtonSnapshot.rightToLeftLayout-default.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/MemberListView_Tests/test_memberListView_withoutAddButtonSnapshot.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/MemberListView_Tests/test_memberListView_withoutAddButtonSnapshot.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/MemberListView_Tests/test_memberListView_withoutAddButtonSnapshot.small-dark.png index b92496635..7a94b69c6 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/MemberListView_Tests/test_memberListView_withoutAddButtonSnapshot.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/MemberListView_Tests/test_memberListView_withoutAddButtonSnapshot.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ParticipantInfoView_Tests/test_participantInfoView_emptyActionsSnapshot.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ParticipantInfoView_Tests/test_participantInfoView_emptyActionsSnapshot.default-light.png index 7242bf833..6a9b92341 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ParticipantInfoView_Tests/test_participantInfoView_emptyActionsSnapshot.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ParticipantInfoView_Tests/test_participantInfoView_emptyActionsSnapshot.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ParticipantInfoView_Tests/test_participantInfoView_emptyActionsSnapshot.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ParticipantInfoView_Tests/test_participantInfoView_emptyActionsSnapshot.extraExtraExtraLarge-light.png index 37fcbdbf3..be934e199 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ParticipantInfoView_Tests/test_participantInfoView_emptyActionsSnapshot.extraExtraExtraLarge-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ParticipantInfoView_Tests/test_participantInfoView_emptyActionsSnapshot.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ParticipantInfoView_Tests/test_participantInfoView_emptyActionsSnapshot.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ParticipantInfoView_Tests/test_participantInfoView_emptyActionsSnapshot.rightToLeftLayout-default.png index 53094b825..9aa83b0e6 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ParticipantInfoView_Tests/test_participantInfoView_emptyActionsSnapshot.rightToLeftLayout-default.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ParticipantInfoView_Tests/test_participantInfoView_emptyActionsSnapshot.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ParticipantInfoView_Tests/test_participantInfoView_emptyActionsSnapshot.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ParticipantInfoView_Tests/test_participantInfoView_emptyActionsSnapshot.small-dark.png index e3c9eadf2..5fc576c89 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ParticipantInfoView_Tests/test_participantInfoView_emptyActionsSnapshot.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ParticipantInfoView_Tests/test_participantInfoView_emptyActionsSnapshot.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ParticipantInfoView_Tests/test_participantInfoView_withBasicActionsSnapshot.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ParticipantInfoView_Tests/test_participantInfoView_withBasicActionsSnapshot.default-light.png index e52cbb8a0..25c4f0d97 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ParticipantInfoView_Tests/test_participantInfoView_withBasicActionsSnapshot.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ParticipantInfoView_Tests/test_participantInfoView_withBasicActionsSnapshot.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ParticipantInfoView_Tests/test_participantInfoView_withBasicActionsSnapshot.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ParticipantInfoView_Tests/test_participantInfoView_withBasicActionsSnapshot.extraExtraExtraLarge-light.png index 516630938..854185588 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ParticipantInfoView_Tests/test_participantInfoView_withBasicActionsSnapshot.extraExtraExtraLarge-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ParticipantInfoView_Tests/test_participantInfoView_withBasicActionsSnapshot.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ParticipantInfoView_Tests/test_participantInfoView_withBasicActionsSnapshot.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ParticipantInfoView_Tests/test_participantInfoView_withBasicActionsSnapshot.rightToLeftLayout-default.png index 78ab8360c..3f718b984 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ParticipantInfoView_Tests/test_participantInfoView_withBasicActionsSnapshot.rightToLeftLayout-default.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ParticipantInfoView_Tests/test_participantInfoView_withBasicActionsSnapshot.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ParticipantInfoView_Tests/test_participantInfoView_withBasicActionsSnapshot.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ParticipantInfoView_Tests/test_participantInfoView_withBasicActionsSnapshot.small-dark.png index 6c1ddb9e3..1317a1ede 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ParticipantInfoView_Tests/test_participantInfoView_withBasicActionsSnapshot.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ParticipantInfoView_Tests/test_participantInfoView_withBasicActionsSnapshot.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ParticipantInfoView_Tests/test_participantInfoView_withDestructiveActionSnapshot.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ParticipantInfoView_Tests/test_participantInfoView_withDestructiveActionSnapshot.default-light.png index 5aa11c96a..ee046c2fa 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ParticipantInfoView_Tests/test_participantInfoView_withDestructiveActionSnapshot.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ParticipantInfoView_Tests/test_participantInfoView_withDestructiveActionSnapshot.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ParticipantInfoView_Tests/test_participantInfoView_withDestructiveActionSnapshot.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ParticipantInfoView_Tests/test_participantInfoView_withDestructiveActionSnapshot.extraExtraExtraLarge-light.png index 4b6adb99e..186bd6e85 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ParticipantInfoView_Tests/test_participantInfoView_withDestructiveActionSnapshot.extraExtraExtraLarge-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ParticipantInfoView_Tests/test_participantInfoView_withDestructiveActionSnapshot.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ParticipantInfoView_Tests/test_participantInfoView_withDestructiveActionSnapshot.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ParticipantInfoView_Tests/test_participantInfoView_withDestructiveActionSnapshot.rightToLeftLayout-default.png index cdf0bd2cc..1c915df8e 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ParticipantInfoView_Tests/test_participantInfoView_withDestructiveActionSnapshot.rightToLeftLayout-default.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ParticipantInfoView_Tests/test_participantInfoView_withDestructiveActionSnapshot.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ParticipantInfoView_Tests/test_participantInfoView_withDestructiveActionSnapshot.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ParticipantInfoView_Tests/test_participantInfoView_withDestructiveActionSnapshot.small-dark.png index d00fedbf8..00b9c01dc 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ParticipantInfoView_Tests/test_participantInfoView_withDestructiveActionSnapshot.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ParticipantInfoView_Tests/test_participantInfoView_withDestructiveActionSnapshot.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ParticipantInfoView_Tests/test_participantInfoView_withLeaveGroupActionSnapshot.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ParticipantInfoView_Tests/test_participantInfoView_withLeaveGroupActionSnapshot.default-light.png index 291283bdf..bfe9f30cc 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ParticipantInfoView_Tests/test_participantInfoView_withLeaveGroupActionSnapshot.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ParticipantInfoView_Tests/test_participantInfoView_withLeaveGroupActionSnapshot.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ParticipantInfoView_Tests/test_participantInfoView_withLeaveGroupActionSnapshot.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ParticipantInfoView_Tests/test_participantInfoView_withLeaveGroupActionSnapshot.extraExtraExtraLarge-light.png index f29ce0d4a..0e58ee998 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ParticipantInfoView_Tests/test_participantInfoView_withLeaveGroupActionSnapshot.extraExtraExtraLarge-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ParticipantInfoView_Tests/test_participantInfoView_withLeaveGroupActionSnapshot.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ParticipantInfoView_Tests/test_participantInfoView_withLeaveGroupActionSnapshot.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ParticipantInfoView_Tests/test_participantInfoView_withLeaveGroupActionSnapshot.rightToLeftLayout-default.png index eb4161998..0e1a1ea47 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ParticipantInfoView_Tests/test_participantInfoView_withLeaveGroupActionSnapshot.rightToLeftLayout-default.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ParticipantInfoView_Tests/test_participantInfoView_withLeaveGroupActionSnapshot.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ParticipantInfoView_Tests/test_participantInfoView_withLeaveGroupActionSnapshot.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ParticipantInfoView_Tests/test_participantInfoView_withLeaveGroupActionSnapshot.small-dark.png index 28ca390d2..083924c9c 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ParticipantInfoView_Tests/test_participantInfoView_withLeaveGroupActionSnapshot.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/ParticipantInfoView_Tests/test_participantInfoView_withLeaveGroupActionSnapshot.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/PinnedMessagesView_Tests/test_pinnedMessagesView_emptySnapshot.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/PinnedMessagesView_Tests/test_pinnedMessagesView_emptySnapshot.small-dark.png index 274c2c382..e1a7a5f67 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/PinnedMessagesView_Tests/test_pinnedMessagesView_emptySnapshot.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/PinnedMessagesView_Tests/test_pinnedMessagesView_emptySnapshot.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/PinnedMessagesView_Tests/test_pinnedMessagesView_imageSnapshot.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/PinnedMessagesView_Tests/test_pinnedMessagesView_imageSnapshot.1.png index 5a7470009..f41b373dc 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/PinnedMessagesView_Tests/test_pinnedMessagesView_imageSnapshot.1.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/PinnedMessagesView_Tests/test_pinnedMessagesView_imageSnapshot.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/PinnedMessagesView_Tests/test_pinnedMessagesView_notEmptySnapshot.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/PinnedMessagesView_Tests/test_pinnedMessagesView_notEmptySnapshot.1.png index 16f3d326a..8508aa09f 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/PinnedMessagesView_Tests/test_pinnedMessagesView_notEmptySnapshot.1.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/PinnedMessagesView_Tests/test_pinnedMessagesView_notEmptySnapshot.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/PinnedMessagesView_Tests/test_pinnedMessagesView_pollSnapshot.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/PinnedMessagesView_Tests/test_pinnedMessagesView_pollSnapshot.1.png index b4b59e252..87722aeac 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/PinnedMessagesView_Tests/test_pinnedMessagesView_pollSnapshot.1.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/PinnedMessagesView_Tests/test_pinnedMessagesView_pollSnapshot.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/PinnedMessagesView_Tests/test_pinnedMessagesView_themedSnapshot.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/PinnedMessagesView_Tests/test_pinnedMessagesView_themedSnapshot.1.png index 6122efdfc..4d79d4963 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/PinnedMessagesView_Tests/test_pinnedMessagesView_themedSnapshot.1.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/PinnedMessagesView_Tests/test_pinnedMessagesView_themedSnapshot.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/PinnedMessagesView_Tests/test_pinnedMessagesView_videoSnapshot.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/PinnedMessagesView_Tests/test_pinnedMessagesView_videoSnapshot.1.png index 784edb6b6..f8d6ac03f 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/PinnedMessagesView_Tests/test_pinnedMessagesView_videoSnapshot.1.png and b/StreamChatSwiftUITests/Tests/ChatChannel/ChannelInfo/__Snapshots__/PinnedMessagesView_Tests/test_pinnedMessagesView_videoSnapshot.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChatChannelHeader_Tests.swift b/StreamChatSwiftUITests/Tests/ChatChannel/ChatChannelHeader_Tests.swift index 88f0f16d0..2f6070f29 100644 --- a/StreamChatSwiftUITests/Tests/ChatChannel/ChatChannelHeader_Tests.swift +++ b/StreamChatSwiftUITests/Tests/ChatChannel/ChatChannelHeader_Tests.swift @@ -84,7 +84,7 @@ import XCTest // When adjustAppearance { appearance in - appearance.colorPalette.text = .red + appearance.colorPalette.textPrimary = .red appearance.colorPalette.textSecondary = .blue } let size = CGSize(width: 300, height: 100) diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChatChannelTestHelpers.swift b/StreamChatSwiftUITests/Tests/ChatChannel/ChatChannelTestHelpers.swift index 2997b7e26..19b75456f 100644 --- a/StreamChatSwiftUITests/Tests/ChatChannel/ChatChannelTestHelpers.swift +++ b/StreamChatSwiftUITests/Tests/ChatChannel/ChatChannelTestHelpers.swift @@ -125,7 +125,8 @@ class ChatChannelTestHelpers { static func imageAttachments( count: Int, originalWidth: Double? = nil, - originalHeight: Double? = nil + originalHeight: Double? = nil, + state: LocalAttachmentState = .pendingUpload ) -> [AnyChatMessageAttachment] { let urls = [ XCTestCase.TestImages.yoda.url, @@ -138,7 +139,8 @@ class ChatChannelTestHelpers { imageAttachment( url: urls[index % urls.count], originalWidth: originalWidth, - originalHeight: originalHeight + originalHeight: originalHeight, + state: state ) } } diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChatChannelViewDateOverlay_Tests.swift b/StreamChatSwiftUITests/Tests/ChatChannel/ChatChannelViewDateOverlay_Tests.swift index c07756b71..b3c7631eb 100644 --- a/StreamChatSwiftUITests/Tests/ChatChannel/ChatChannelViewDateOverlay_Tests.swift +++ b/StreamChatSwiftUITests/Tests/ChatChannel/ChatChannelViewDateOverlay_Tests.swift @@ -13,21 +13,21 @@ import XCTest @MainActor class ChatChannelViewDateOverlay_Tests: StreamChatTestCase { override func setUp() { super.setUp() - let utils = Utils( - dateFormatter: EmptyDateFormatter(), - messageListConfig: MessageListConfig(dateIndicatorPlacement: .messageList) - ) - streamChat = StreamChat(chatClient: chatClient, utils: utils) DelayedRenderingViewModifier.isEnabled = false } - + override func tearDown() { super.tearDown() DelayedRenderingViewModifier.isEnabled = true } - func test_chatChannelView_snapshot() { + func test_chatChannelView_snapshot_messageListPlacement() { // Given + let utils = Utils( + dateFormatter: EmptyDateFormatter(), + messageListConfig: MessageListConfig(dateIndicatorPlacement: .messageList) + ) + streamChat = StreamChat(chatClient: chatClient, utils: utils) let controller = ChatChannelController_Mock.mock( channelQuery: .init(cid: .unique), channelListQuery: nil, @@ -65,4 +65,57 @@ import XCTest // Then assertSnapshot(matching: view, as: .image(perceptualPrecision: precision)) } + + func test_chatChannelView_snapshot_overlayPlacement_dateIndicatorAppearsAtTop() { + // Given + let utils = Utils( + dateFormatter: EmptyDateFormatter(), + messageListConfig: MessageListConfig(dateIndicatorPlacement: .overlay) + ) + streamChat = StreamChat(chatClient: chatClient, utils: utils) + let controller = ChatChannelController_Mock.mock( + channelQuery: .init(cid: .unique), + channelListQuery: nil, + client: chatClient + ) + let mockChannel = ChatChannel.mock(cid: .unique, name: "Test channel") + var messages = [ChatMessage]() + let baseIntervalDistance: TimeInterval = 60 + for i in 0..<3 { + messages.append( + ChatMessage.mock( + id: .unique, + cid: mockChannel.cid, + text: "Test \(i)", + author: .mock(id: .unique, name: "Martin"), + createdAt: Date(timeIntervalSince1970: 100_000 - TimeInterval(i) * baseIntervalDistance) + ) + ) + } + controller.simulateInitial(channel: mockChannel, messages: messages, state: .remoteDataFetched) + + // When – inject a viewModel with currentDateString set to simulate the overlay being visible. + // showScrollToLatestButton must also be true: handleMessageAppear calls save(lastDate:) during + // rendering which triggers handleDateChange(); if showScrollToLatestButton is false that + // method immediately resets currentDateString back to nil. + let viewModel = ChatChannelViewModel(channelController: controller) + viewModel.showScrollToLatestButton = true + viewModel.currentDateString = "Today" + + let view = NavigationView { + ScrollView { + ChatChannelView( + viewFactory: DefaultViewFactory.shared, + viewModel: viewModel, + channelController: controller + ) + .frame(width: defaultScreenSize.width, height: defaultScreenSize.height - 64) + } + .navigationBarTitleDisplayMode(.inline) + } + .applyDefaultSize() + + // Then – date indicator must appear at the top, not the center + assertSnapshot(matching: view, as: .image(perceptualPrecision: precision)) + } } diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChatChannelViewModel_Tests.swift b/StreamChatSwiftUITests/Tests/ChatChannel/ChatChannelViewModel_Tests.swift index 80405b933..a6ec8e28d 100644 --- a/StreamChatSwiftUITests/Tests/ChatChannel/ChatChannelViewModel_Tests.swift +++ b/StreamChatSwiftUITests/Tests/ChatChannel/ChatChannelViewModel_Tests.swift @@ -116,6 +116,12 @@ import XCTest func test_chatChannelVM_currentDateString() { // Given + streamChat = StreamChat( + chatClient: chatClient, + utils: Utils( + messageListConfig: .init(dateIndicatorPlacement: .overlay) + ) + ) let expectedDate = "Jan 01" let channelController = makeChannelController() let viewModel = ChatChannelViewModel(channelController: channelController) diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChatMessageBubbles_Tests.swift b/StreamChatSwiftUITests/Tests/ChatChannel/ChatMessageBubbles_Tests.swift index d2af64940..4790b54e8 100644 --- a/StreamChatSwiftUITests/Tests/ChatChannel/ChatMessageBubbles_Tests.swift +++ b/StreamChatSwiftUITests/Tests/ChatChannel/ChatMessageBubbles_Tests.swift @@ -123,7 +123,7 @@ final class ChatMessageBubbles_Tests: StreamChatTestCase { func test_bubbleBackgrounds_currentUserEphemeral() { // Given let message = ChatMessage.mock(type: MessageType.ephemeral, isSentByCurrentUser: true) - let expected = colors.messageCurrentUserEmphemeralBackground.map { Color($0) } + let expected = [colors.chatBackgroundOutgoing.toColor] // When let background = message.bubbleBackground(colors: colors) diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ComposerQuotedMessageView_Tests.swift b/StreamChatSwiftUITests/Tests/ChatChannel/ComposerQuotedMessageView_Tests.swift index aaf00af2c..4f48d6c72 100644 --- a/StreamChatSwiftUITests/Tests/ChatChannel/ComposerQuotedMessageView_Tests.swift +++ b/StreamChatSwiftUITests/Tests/ChatChannel/ComposerQuotedMessageView_Tests.swift @@ -111,6 +111,42 @@ import XCTest AssertSnapshot(view, size: containerSize) } + func test_composerQuotedMessageView_withGiphyAttachment() { + // Given + let giphyAttachment = ChatMessageGiphyAttachment( + id: .unique, + type: .giphy, + payload: GiphyAttachmentPayload( + title: "Funny GIF", + previewURL: .localYodaImage, + actions: [] + ), + downloadingState: nil, + uploadingState: nil + ) + + let message = ChatMessage.mock( + id: .unique, + cid: .unique, + text: "", + author: author, + attachments: [giphyAttachment.asAnyAttachment], + isSentByCurrentUser: false + ) + + // When + let view = containerView { + ComposerQuotedMessageView( + factory: DefaultViewFactory.shared, + quotedMessage: message, + onDismiss: {} + ) + } + + // Then + AssertSnapshot(view, size: containerSize) + } + func test_composerQuotedMessageView_withFileAttachment() { // Given let fileAttachment = ChatMessageFileAttachment( diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/FileAttachmentView_Tests.swift b/StreamChatSwiftUITests/Tests/ChatChannel/FileAttachmentView_Tests.swift index cab3ce4e7..7db39ad67 100644 --- a/StreamChatSwiftUITests/Tests/ChatChannel/FileAttachmentView_Tests.swift +++ b/StreamChatSwiftUITests/Tests/ChatChannel/FileAttachmentView_Tests.swift @@ -11,126 +11,56 @@ import SwiftUI import XCTest class FileAttachmentView_Tests: StreamChatTestCase { - func test_fileAttachmentView_downloadButton() { - // Given - let utils = Utils( - messageListConfig: MessageListConfig(downloadFileAttachmentsEnabled: true) - ) - streamChat = StreamChat(chatClient: chatClient, utils: utils) - - let attachment = createFileAttachment(downloadingState: nil, uploadingState: nil) - - // When - let view = FileAttachmentView( - attachment: attachment, - width: 300, - isFirst: true - ) - .applyDefaultSize() + // MARK: - Upload States - // Then - assertSnapshot(matching: view, as: .image(perceptualPrecision: precision)) - } - - func test_fileAttachmentView_downloadingState() { - // Given - let utils = Utils( - messageListConfig: MessageListConfig(downloadFileAttachmentsEnabled: true) + func test_fileAttachmentView_uploadingProgress_snapshot() { + let uploadingState = AttachmentUploadingState( + localFileURL: ChatChannelTestHelpers.testURL, + state: .uploading(progress: 0.5), + file: AttachmentFile(type: .pdf, size: 1024, mimeType: "application/pdf") ) - streamChat = StreamChat(chatClient: chatClient, utils: utils) - - let downloadingState = AttachmentDownloadingState( - localFileURL: nil, - state: .downloading(progress: 0.5), - file: nil - ) - let attachment = createFileAttachment(downloadingState: downloadingState, uploadingState: nil) - - // When + let attachment = createFileAttachment(downloadingState: nil, uploadingState: uploadingState) let view = FileAttachmentView( attachment: attachment, width: 300, isFirst: true ) .applyDefaultSize() - - // Then - assertSnapshot(matching: view, as: .image(perceptualPrecision: precision)) + AssertSnapshot(view, variants: .onlyUserInterfaceStyles) } - - func test_fileAttachmentView_downloadedState() { - // Given - let utils = Utils( - messageListConfig: MessageListConfig(downloadFileAttachmentsEnabled: true) - ) - streamChat = StreamChat(chatClient: chatClient, utils: utils) - - let downloadingState = AttachmentDownloadingState( - localFileURL: URL(string: "file:///tmp/test.pdf")!, - state: .downloaded, - file: nil - ) - let attachment = createFileAttachment(downloadingState: downloadingState, uploadingState: nil) - // When - let view = FileAttachmentView( - attachment: attachment, - width: 300, - isFirst: true - ) - .applyDefaultSize() - - // Then - assertSnapshot(matching: view, as: .image(perceptualPrecision: precision)) - } - - func test_fileAttachmentView_downloadFailedState() { - // Given - let utils = Utils( - messageListConfig: MessageListConfig(downloadFileAttachmentsEnabled: true) - ) - streamChat = StreamChat(chatClient: chatClient, utils: utils) - - let downloadingState = AttachmentDownloadingState( - localFileURL: nil, - state: .downloadingFailed, - file: nil + func test_fileAttachmentView_uploadingFailed_snapshot() { + let uploadingState = AttachmentUploadingState( + localFileURL: ChatChannelTestHelpers.testURL, + state: .uploadingFailed, + file: AttachmentFile(type: .pdf, size: 1024, mimeType: "application/pdf") ) - let attachment = createFileAttachment(downloadingState: downloadingState, uploadingState: nil) - - // When + let attachment = createFileAttachment(downloadingState: nil, uploadingState: uploadingState) let view = FileAttachmentView( attachment: attachment, width: 300, isFirst: true ) .applyDefaultSize() - - // Then - assertSnapshot(matching: view, as: .image(perceptualPrecision: precision)) + AssertSnapshot(view, variants: .onlyUserInterfaceStyles) } - func test_fileAttachmentView_downloadDisabled() { - // Given - let utils = Utils( - messageListConfig: MessageListConfig(downloadFileAttachmentsEnabled: false) + func test_fileAttachmentView_uploaded_snapshot() { + let uploadingState = AttachmentUploadingState( + localFileURL: ChatChannelTestHelpers.testURL, + state: .uploaded, + file: AttachmentFile(type: .pdf, size: 1024, mimeType: "application/pdf") ) - streamChat = StreamChat(chatClient: chatClient, utils: utils) - - let attachment = createFileAttachment(downloadingState: nil, uploadingState: nil) - - // When + let attachment = createFileAttachment(downloadingState: nil, uploadingState: uploadingState) let view = FileAttachmentView( attachment: attachment, width: 300, isFirst: true ) .applyDefaultSize() - - // Then - assertSnapshot(matching: view, as: .image(perceptualPrecision: precision)) + AssertSnapshot(view, variants: .onlyUserInterfaceStyles) } - + // MARK: - Helper Methods private func createFileAttachment( diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/LazyImageExtensions_Tests.swift b/StreamChatSwiftUITests/Tests/ChatChannel/LazyImageExtensions_Tests.swift deleted file mode 100644 index 7e61f3b85..000000000 --- a/StreamChatSwiftUITests/Tests/ChatChannel/LazyImageExtensions_Tests.swift +++ /dev/null @@ -1,56 +0,0 @@ -// -// Copyright © 2026 Stream.io Inc. All rights reserved. -// - -import SnapshotTesting -@testable import StreamChat -@testable import StreamChatSwiftUI -import StreamSwiftTestHelpers -import SwiftUI -import XCTest - -@MainActor -final class LazyImageExtensions_Tests: StreamChatTestCase { - func test_imageURL_empty() { - // Given - let lazyImageView = LazyImage(imageURL: nil) { state in - if let image = state.image { - image - .resizable() - .aspectRatio(contentMode: .fill) - } - } - .applyDefaultSize() - - // Then - assertSnapshot(matching: lazyImageView, as: .image(perceptualPrecision: precision)) - } - - func test_imageURL_nonEmpty() { - // Given - let lazyImageView = LazyImage( - imageURL: .localYodaImage - ) { state in - if let image = state.image { - image - .resizable() - .aspectRatio(contentMode: .fill) - } - } - .applyDefaultSize() - - // Then - assertSnapshot(matching: lazyImageView, as: .image(perceptualPrecision: precision)) - } - - func test_imageRequest_emptyURL() { - // Given - let lazyImageView = LazyImage(request: nil) { _ in - ProgressView() - } - .applyDefaultSize() - - // Then - assertSnapshot(matching: lazyImageView, as: .image(perceptualPrecision: precision)) - } -} diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/LazyLoadingImage_Tests.swift b/StreamChatSwiftUITests/Tests/ChatChannel/LazyLoadingImage_Tests.swift new file mode 100644 index 000000000..7efe32c15 --- /dev/null +++ b/StreamChatSwiftUITests/Tests/ChatChannel/LazyLoadingImage_Tests.swift @@ -0,0 +1,250 @@ +// +// Copyright © 2026 Stream.io Inc. All rights reserved. +// + +import SnapshotTesting +@testable import StreamChat +@testable import StreamChatSwiftUI +import StreamSwiftTestHelpers +import SwiftUI +import XCTest + +@MainActor class LazyLoadingImage_Tests: StreamChatTestCase { + // MARK: - Snapshot + + func test_lazyLoadingImage_snapshot() { + // Given + let source = MediaAttachment(url: .localYodaImage, type: .image) + let view = LazyLoadingImage( + source: source, + width: 80, + height: 80, + resize: true, + showVideoIcon: false + ) + .frame(width: 80, height: 80) + + // Then + AssertSnapshot(view, variants: [.defaultLight], size: CGSize(width: 80, height: 80)) + } + + func test_lazyLoadingImage_noResize_snapshot() { + // Given + let source = MediaAttachment(url: .localYodaImage, type: .image) + let view = LazyLoadingImage( + source: source, + width: 80, + height: 80, + resize: false, + showVideoIcon: false + ) + .frame(width: 80, height: 80) + + // Then + AssertSnapshot(view, variants: [.defaultLight], size: CGSize(width: 80, height: 80)) + } + + // MARK: - Initial Load + + func test_lazyLoadingImage_loadsImageOnAppear() { + // Given + let imageLoader = streamChat?.utils.mediaLoader as? MediaLoader_Mock + let source = MediaAttachment(url: .localYodaImage, type: .image) + let view = LazyLoadingImage( + source: source, + width: 80, + height: 80, + resize: true, + showVideoIcon: false + ) + + // When + showView(view) + + let expectation = expectation(description: "Image loaded on appear") + DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { + expectation.fulfill() + } + wait(for: [expectation], timeout: 2.0) + + // Then + XCTAssertEqual(imageLoader?.loadImageCalled, true) + XCTAssertEqual(imageLoader?.loadImageCallCount, 1) + XCTAssertEqual(imageLoader?.loadedURLs.first, .localYodaImage) + } + + // MARK: - Source Change Reload + + func test_lazyLoadingImage_reloadsWhenSourceChanges() { + // Given + let imageLoader = streamChat?.utils.mediaLoader as? MediaLoader_Mock + let initialURL = URL(string: "https://example.com/yoda.jpg")! + let updatedURL = URL(string: "https://example.com/vader.jpg")! + let source = CurrentValueContainer(MediaAttachment(url: initialURL, type: .image)) + + let view = LazyLoadingImageSourceChangeTestView(source: source) + showView(view) + + // Wait for initial load + let initialLoad = expectation(description: "Initial image loaded") + DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { + initialLoad.fulfill() + } + wait(for: [initialLoad], timeout: 2.0) + + let initialCallCount = imageLoader?.loadImageCallCount ?? 0 + XCTAssertGreaterThanOrEqual(initialCallCount, 1) + + // When: change source + source.value = MediaAttachment(url: updatedURL, type: .image) + + // Wait for reload + let reload = expectation(description: "Image reloaded after source change") + DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { + reload.fulfill() + } + wait(for: [reload], timeout: 2.0) + + // Then + let finalCallCount = imageLoader?.loadImageCallCount ?? 0 + XCTAssertGreaterThan(finalCallCount, initialCallCount) + XCTAssertTrue(imageLoader?.loadedURLs.contains(updatedURL) ?? false) + } + + // MARK: - Generate Thumbnail + + func test_mediaAttachment_generateThumbnail_callsMediaLoader() { + // Given + let imageLoader = streamChat?.utils.mediaLoader as? MediaLoader_Mock + let attachment = MediaAttachment(url: .localYodaImage, type: .image) + + // When + let expectation = expectation(description: "Thumbnail generated") + attachment.generateThumbnail( + resize: true, + preferredSize: CGSize(width: 80, height: 80) + ) { _ in + expectation.fulfill() + } + wait(for: [expectation], timeout: 2.0) + + // Then + XCTAssertEqual(imageLoader?.loadImageCalled, true) + XCTAssertEqual(imageLoader?.loadedURLs.first, .localYodaImage) + } + + // MARK: - CDN Requester + + func test_mediaAttachment_generateThumbnail_usesInjectedCDNRequester() { + // Given + let customRequester = CDNRequester_Mock() + let mediaLoader = MediaLoader_Mock() + let utils = Utils(cdnRequester: customRequester, mediaLoader: mediaLoader) + streamChat = StreamChat(chatClient: chatClient, utils: utils) + let attachment = MediaAttachment(url: .localYodaImage, type: .image) + + // When + let expectation = expectation(description: "Thumbnail generated") + attachment.generateThumbnail( + resize: true, + preferredSize: CGSize(width: 80, height: 80) + ) { _ in + expectation.fulfill() + } + wait(for: [expectation], timeout: 2.0) + + // Then + XCTAssertEqual(mediaLoader.loadImageOptions.count, 1) + XCTAssert(mediaLoader.loadImageOptions.first?.cdnRequester is CDNRequester_Mock) + } + + func test_mediaAttachment_videoPreview_usesInjectedCDNRequester() { + // Given + let customRequester = CDNRequester_Mock() + let mediaLoader = MediaLoader_Mock() + let utils = Utils(cdnRequester: customRequester, mediaLoader: mediaLoader) + streamChat = StreamChat(chatClient: chatClient, utils: utils) + let videoAttachment = ChatMessageVideoAttachment( + id: .init(cid: .init(type: .messaging, id: "test"), messageId: "msg", index: 0), + type: .video, + payload: VideoAttachmentPayload( + title: nil, + videoRemoteURL: URL(string: "https://example.com/video.mp4")!, + file: .init(type: .mp4, size: 0, mimeType: nil), + extraData: nil + ), + downloadingState: nil, + uploadingState: nil + ) + let attachment = MediaAttachment( + url: URL(string: "https://example.com/video.mp4")!, + type: .video, + videoAttachment: videoAttachment + ) + + // When + let expectation = expectation(description: "Video preview generated") + attachment.generateThumbnail( + resize: false, + preferredSize: CGSize(width: 80, height: 80) + ) { _ in + expectation.fulfill() + } + wait(for: [expectation], timeout: 2.0) + + // Then + XCTAssertEqual(mediaLoader.loadVideoPreviewOptions.count, 1) + XCTAssert(mediaLoader.loadVideoPreviewOptions.first?.cdnRequester is CDNRequester_Mock) + } + + // MARK: - MediaAttachment Equatable + + func test_mediaAttachment_equalityByURL() { + // Given + let url1 = URL(string: "https://example.com/image1.jpg")! + let url2 = URL(string: "https://example.com/image2.jpg")! + + let attachment1 = MediaAttachment(url: url1, type: .image) + let attachment2 = MediaAttachment(url: url1, type: .image) + let attachment3 = MediaAttachment(url: url2, type: .image) + + // Then + XCTAssertEqual(attachment1, attachment2) + XCTAssertNotEqual(attachment1, attachment3) + } + + func test_mediaAttachment_equalityByType() { + // Given + let url = URL(string: "https://example.com/media.mp4")! + let imageAttachment = MediaAttachment(url: url, type: .image) + let videoAttachment = MediaAttachment(url: url, type: .video) + + // Then + XCTAssertNotEqual(imageAttachment, videoAttachment) + } +} + +// MARK: - Test Helpers + +@MainActor +private class CurrentValueContainer: ObservableObject { + @Published var value: T + init(_ value: T) { + self.value = value + } +} + +@MainActor +private struct LazyLoadingImageSourceChangeTestView: View { + @ObservedObject var source: CurrentValueContainer + + var body: some View { + LazyLoadingImage( + source: source.value, + width: 80, + height: 80, + resize: true, + showVideoIcon: false + ) + } +} diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/MediaViewer_Tests.swift b/StreamChatSwiftUITests/Tests/ChatChannel/MediaViewer_Tests.swift index 732612420..881d7de10 100644 --- a/StreamChatSwiftUITests/Tests/ChatChannel/MediaViewer_Tests.swift +++ b/StreamChatSwiftUITests/Tests/ChatChannel/MediaViewer_Tests.swift @@ -110,11 +110,24 @@ class MediaViewer_Tests: StreamChatTestCase { func test_gridViewVideoAndImage_snapshotLoading() { // Given + let dummyVideoURL = URL(string: "https://example.com/test.mp4")! + let videoAttachment = ChatMessageVideoAttachment( + id: .unique, + type: .video, + payload: VideoAttachmentPayload( + title: "test", + videoRemoteURL: dummyVideoURL, + file: AttachmentFile(type: .mp4, size: 0, mimeType: "video/mp4"), + extraData: nil + ), + downloadingState: nil, + uploadingState: nil + ) let view = GridMediaView( factory: DefaultViewFactory.shared, attachments: [ MediaAttachment(url: ChatChannelTestHelpers.testURL, type: .image), - MediaAttachment(url: ChatChannelTestHelpers.testURL.appendingPathComponent("test"), type: .video) + MediaAttachment(from: videoAttachment) ] ) .applyDefaultSize() diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/MessageActions_Tests.swift b/StreamChatSwiftUITests/Tests/ChatChannel/MessageActions_Tests.swift index 00d38285a..8b83b8d54 100644 --- a/StreamChatSwiftUITests/Tests/ChatChannel/MessageActions_Tests.swift +++ b/StreamChatSwiftUITests/Tests/ChatChannel/MessageActions_Tests.swift @@ -61,13 +61,14 @@ import XCTest ) // Then - XCTAssert(messageActions.count == 6) + XCTAssert(messageActions.count == 7) XCTAssert(messageActions[0].title == "Reply") XCTAssert(messageActions[1].title == "Thread Reply") XCTAssert(messageActions[2].title == "Pin to conversation") XCTAssert(messageActions[3].title == "Copy Message") XCTAssert(messageActions[4].title == "Mark Unread") XCTAssert(messageActions[5].title == "Mute User") + XCTAssert(messageActions[6].title == "Block User") } func test_messageActions_partOfThread() { @@ -94,11 +95,12 @@ import XCTest ) // Then - XCTAssertEqual(messageActions.count, 4) + XCTAssertEqual(messageActions.count, 5) XCTAssertEqual(messageActions[0].title, "Reply") XCTAssertEqual(messageActions[1].title, "Pin to conversation") XCTAssertEqual(messageActions[2].title, "Copy Message") XCTAssertEqual(messageActions[3].title, "Mute User") + XCTAssertEqual(messageActions[4].title, "Block User") } func test_messageActions_partOfThreadButAlsoInChannel() { @@ -125,12 +127,13 @@ import XCTest ) // Then - XCTAssertEqual(messageActions.count, 5) + XCTAssertEqual(messageActions.count, 6) XCTAssertEqual(messageActions[0].title, "Reply") XCTAssertEqual(messageActions[1].title, "Pin to conversation") XCTAssertEqual(messageActions[2].title, "Copy Message") XCTAssertEqual(messageActions[3].title, "Mark Unread") XCTAssertEqual(messageActions[4].title, "Mute User") + XCTAssertEqual(messageActions[5].title, "Block User") } func test_messageActions_rootOfThreadButAlsoInChannel() { @@ -158,12 +161,13 @@ import XCTest ) // Then - XCTAssertEqual(messageActions.count, 5) + XCTAssertEqual(messageActions.count, 6) XCTAssertEqual(messageActions[0].title, "Reply") XCTAssertEqual(messageActions[1].title, "Pin to conversation") XCTAssertEqual(messageActions[2].title, "Copy Message") XCTAssertEqual(messageActions[3].title, "Mark Unread") XCTAssertEqual(messageActions[4].title, "Mute User") + XCTAssertEqual(messageActions[5].title, "Block User") } func test_messageActions_otherUserDefaultReadEventsDisabled() { @@ -188,12 +192,13 @@ import XCTest ) // Then - XCTAssert(messageActions.count == 5) + XCTAssert(messageActions.count == 6) XCTAssert(messageActions[0].title == "Reply") XCTAssert(messageActions[1].title == "Thread Reply") XCTAssert(messageActions[2].title == "Pin to conversation") XCTAssert(messageActions[3].title == "Copy Message") XCTAssert(messageActions[4].title == "Mute User") + XCTAssertEqual(messageActions[5].title, "Block User") } func test_messageActions_otherUserDefaultBlockingEnabled() { diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/MessageAttachmentPreviewResolver_Tests.swift b/StreamChatSwiftUITests/Tests/ChatChannel/MessageAttachmentPreviewResolver_Tests.swift index 3ceb47464..766b72f2b 100644 --- a/StreamChatSwiftUITests/Tests/ChatChannel/MessageAttachmentPreviewResolver_Tests.swift +++ b/StreamChatSwiftUITests/Tests/ChatChannel/MessageAttachmentPreviewResolver_Tests.swift @@ -572,8 +572,8 @@ import XCTest let resolver = MessageAttachmentPreviewResolver(message: message) // Then - XCTAssertEqual(resolver.previewDescription, "Photo") - XCTAssertEqual(resolver.previewIcon, .photo) + XCTAssertEqual(resolver.previewDescription, "Giphy") + XCTAssertEqual(resolver.previewIcon, .document) XCTAssertNotNil(resolver.previewThumbnail) XCTAssertEqual(resolver.previewThumbnail?.url, giphyURL) XCTAssertTrue(resolver.previewThumbnail?.isImage == true) diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/MessageAttachmentsConverter_Tests.swift b/StreamChatSwiftUITests/Tests/ChatChannel/MessageAttachmentsConverter_Tests.swift index dd89576c5..4c8237e6a 100644 --- a/StreamChatSwiftUITests/Tests/ChatChannel/MessageAttachmentsConverter_Tests.swift +++ b/StreamChatSwiftUITests/Tests/ChatChannel/MessageAttachmentsConverter_Tests.swift @@ -49,6 +49,39 @@ class MessageAttachmentsConverter_Tests: StreamChatTestCase { // MARK: - Public Interface Tests + func test_attachmentsToAssets_voiceRecordingWithoutWaveformOrDuration() throws { + let attachmentFile = AttachmentFile(type: .aac, size: 120, mimeType: "audio/aac") + let attachment = ChatMessageVoiceRecordingAttachment( + id: .unique, + type: .voiceRecording, + payload: VoiceRecordingAttachmentPayload( + title: "Voice", + voiceRecordingRemoteURL: mockFileURL, + file: attachmentFile, + duration: nil, + waveformData: nil, + extraData: nil + ), + downloadingState: nil, + uploadingState: nil + ).asAnyAttachment + + let expectation = XCTestExpectation(description: "Voice without optional metadata converts to asset") + nonisolated(unsafe) var result: TotalAddedAssets? + + converter.attachmentsToAssets([attachment]) { totalAddedAssets in + result = totalAddedAssets + expectation.fulfill() + } + + wait(for: [expectation], timeout: 1.0) + XCTAssertEqual(result?.voiceAssets.count, 1) + let voice = try XCTUnwrap(result?.voiceAssets.first) + XCTAssertEqual(voice.url, mockFileURL) + XCTAssertEqual(voice.duration, 0, accuracy: 0.001) + XCTAssertTrue(voice.waveform.isEmpty) + } + func test_attachmentsToAssets_emptyAttachments() { // Given let attachments: [AnyChatMessageAttachment] = [] diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/MessageComposerViewModel_Tests.swift b/StreamChatSwiftUITests/Tests/ChatChannel/MessageComposerViewModel_Tests.swift index c14d6bdcc..233fcadf1 100644 --- a/StreamChatSwiftUITests/Tests/ChatChannel/MessageComposerViewModel_Tests.swift +++ b/StreamChatSwiftUITests/Tests/ChatChannel/MessageComposerViewModel_Tests.swift @@ -143,7 +143,60 @@ import XCTest // Then XCTAssertEqual(viewModel.composerCommand?.id, "/giphy") } - + + func test_messageComposerVM_instantCommand_clearsMediaAttachments() { + // Given + let viewModel = makeComposerViewModel() + viewModel.imageTapped(defaultAsset) + XCTAssertEqual(viewModel.composerAssets.count, 1) + + // When + viewModel.composerCommand = makeGiphyCommand() + + // Then + XCTAssertTrue(viewModel.composerAssets.isEmpty) + } + + func test_messageComposerVM_instantCommand_clearsFileAttachments() { + // Given + let viewModel = makeComposerViewModel() + viewModel.addFileURLs([mockURL]) + XCTAssertEqual(viewModel.composerAssets.count, 1) + + // When + viewModel.composerCommand = makeGiphyCommand() + + // Then + XCTAssertTrue(viewModel.composerAssets.isEmpty) + } + + func test_messageComposerVM_instantCommand_clearsCustomAttachments() { + // Given + let viewModel = makeComposerViewModel() + let attachment = CustomAttachment(id: .unique, content: .mockFile) + viewModel.customAttachmentTapped(attachment) + XCTAssertEqual(viewModel.addedCustomAttachments.count, 1) + + // When + viewModel.composerCommand = makeGiphyCommand() + + // Then + XCTAssertTrue(viewModel.addedCustomAttachments.isEmpty) + } + + func test_messageComposerVM_instantCommand_clearsVoiceRecordings() { + // Given + let viewModel = makeComposerViewModel() + let recording = AddedVoiceRecording(url: mockURL, duration: 1.0, waveform: []) + viewModel.addedVoiceRecordings = [recording] + + // When + viewModel.composerCommand = makeGiphyCommand() + + // Then + XCTAssertTrue(viewModel.addedVoiceRecordings.isEmpty) + } + func test_messageComposerVM_sendButtonEnabled_addedCustomAttachment() { // Given let viewModel = makeComposerViewModel() @@ -304,10 +357,7 @@ import XCTest viewModel.text = "test" viewModel.imageTapped(defaultAsset) viewModel.composerAssets.append(.addedFile(mockURL)) - viewModel.sendMessage( - quotedMessage: nil, - editedMessage: nil - ) { + viewModel.sendMessage { // Then XCTAssert(viewModel.errorShown == false) XCTAssert(viewModel.text == "") @@ -315,6 +365,84 @@ import XCTest } } + // MARK: - isSendingMessage guard (PR #1373) + + func test_messageComposerVM_isSendingMessage_initiallyFalse() { + // Given / When + let viewModel = makeComposerViewModel() + + // Then + XCTAssertFalse(viewModel.isSendingMessage) + } + + func test_messageComposerVM_isSendingMessage_trueWhileSending() { + // Given + let viewModel = makeComposerViewModel() + viewModel.text = "test" + + // When + viewModel.sendMessage() + + // Then – flag is set synchronously before clearInputData()'s delayed reset fires + XCTAssertTrue(viewModel.isSendingMessage) + } + + func test_messageComposerVM_isSendingMessage_preventsDoubleSend() { + // Given + let channelController = makeChannelController() + let viewModel = MessageComposerViewModel( + channelController: channelController, + messageController: nil + ) + viewModel.text = "test" + + // When – call sendMessage twice in rapid succession + viewModel.sendMessage() + viewModel.sendMessage() + + // Then – createNewMessage must only have been called once + XCTAssertEqual(channelController.createNewMessageCallCount, 1) + } + + func test_messageComposerVM_isSendingMessage_resetAfterClearInputDataDelay() { + // Given + let viewModel = makeComposerViewModel() + viewModel.text = "test" + let expectation = expectation(description: "isSendingMessage reset after 0.1 s delay") + + // When + viewModel.sendMessage() + XCTAssertTrue(viewModel.isSendingMessage) + + // Then – clearInputData() schedules the reset 0.1 s later; wait for it + DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) { + XCTAssertFalse(viewModel.isSendingMessage) + expectation.fulfill() + } + + waitForExpectations(timeout: 1) + } + + func test_messageComposerVM_isSendingMessage_secondCallIgnoredWhenAlreadySending() { + // Given + let channelController = makeChannelController() + let viewModel = MessageComposerViewModel( + channelController: channelController, + messageController: nil + ) + viewModel.text = "first message" + + // When – first send sets the guard; immediate second send must be a no-op + viewModel.sendMessage() + viewModel.text = "second message" + viewModel.sendMessage() + + // Then – still only one network call + XCTAssertEqual(channelController.createNewMessageCallCount, 1) + // Flag still true (clearInputData delay hasn't fired) + XCTAssertTrue(viewModel.isSendingMessage) + } + func test_messageComposerVM_notInThread() { // Given let viewModel = makeComposerViewModel() @@ -461,10 +589,11 @@ import XCTest func test_messageComposerVM_maxSizeExceeded() { // Given let viewModel = makeComposerViewModel() - let cdnClient = CDNClient_Mock() - CDNClient_Mock.maxAttachmentSize = 5 - let client = ChatClient.mock(customCDNClient: cdnClient) - streamChat = StreamChat(chatClient: client) + let client = ChatClient.mock(isLocalStorageEnabled: false) + streamChat = StreamChat( + chatClient: client, + utils: Utils(composerConfig: ComposerConfig(maxAttachmentSize: 5)) + ) // When let newAsset = defaultAsset @@ -1294,6 +1423,20 @@ import XCTest // When viewModel.showRecordingTip() + // Then + XCTAssertEqual(viewModel.snackBarText, L10n.Composer.Recording.tipSave) + } + + func test_messageComposer_showRecordingTip_whenAutoSendEnabled_showsSendTip() { + // Given + let utils = Utils(composerConfig: ComposerConfig(isVoiceRecordingAutoSendEnabled: true)) + streamChat = StreamChat(chatClient: chatClient, utils: utils) + let viewModel = makeComposerViewModel() + XCTAssertNil(viewModel.snackBarText) + + // When + viewModel.showRecordingTip() + // Then XCTAssertEqual(viewModel.snackBarText, L10n.Composer.Recording.tip) } @@ -1454,7 +1597,7 @@ import XCTest viewModel.text = "text" // When - viewModel.sendMessage(quotedMessage: nil, editedMessage: nil) {} + viewModel.sendMessage() // Then let expectation = XCTestExpectation(description: "Text cleared") @@ -1482,7 +1625,7 @@ import XCTest viewModel.text = "reply" // When - viewModel.sendMessage(quotedMessage: nil, editedMessage: nil) {} + viewModel.sendMessage() // Then let expectation = XCTestExpectation(description: "Text cleared") @@ -1665,6 +1808,63 @@ import XCTest XCTAssertEqual(channelController.deleteDraftMessage_callCount, 0) } + // MARK: - sendRecording + + func test_sendRecording_whenRecording_setsShouldSendOnRecordingFinish() { + let viewModel = makeComposerViewModel() + viewModel.recordingState = .recording + + viewModel.sendRecording() + + XCTAssertTrue(viewModel.shouldSendOnRecordingFinish) + } + + func test_sendRecording_whenNotRecording_doesNotSetShouldSendOnRecordingFinish() { + let viewModel = makeComposerViewModel() + viewModel.recordingState = .initial + + viewModel.sendRecording() + + XCTAssertFalse(viewModel.shouldSendOnRecordingFinish) + } + + func test_discardRecording_resetsShouldSendOnRecordingFinish() { + let viewModel = makeComposerViewModel() + viewModel.shouldSendOnRecordingFinish = true + + viewModel.discardRecording() + + XCTAssertFalse(viewModel.shouldSendOnRecordingFinish) + } + + // MARK: - saveRecording + + func test_saveRecording_whenRecording_setsShouldSendOnRecordingFinishToFalse() { + // Given + let viewModel = makeComposerViewModel() + viewModel.recordingState = .recording + viewModel.shouldSendOnRecordingFinish = true + + // When + viewModel.saveRecording() + + // Then + XCTAssertFalse(viewModel.shouldSendOnRecordingFinish) + } + + func test_saveRecording_whenNotRecording_doesNothing() { + // Given + let viewModel = makeComposerViewModel() + viewModel.recordingState = .initial + viewModel.shouldSendOnRecordingFinish = true + + // When + viewModel.saveRecording() + + // Then + XCTAssertTrue(viewModel.shouldSendOnRecordingFinish) + } + // MARK: - private private func makeComposerDraftsViewModel( @@ -1682,6 +1882,20 @@ import XCTest private func makeComposerViewModel() -> MessageComposerViewModel { MessageComposerTestUtils.makeComposerViewModel(chatClient: chatClient) } + + private func makeGiphyCommand() -> ComposerCommand { + let displayInfo = CommandDisplayInfo( + displayName: "Giphy", + icon: UIImage(systemName: "photo") ?? UIImage(), + format: "/giphy [text]", + isInstant: true + ) + return ComposerCommand( + id: "/giphy", + typingSuggestion: TypingSuggestion.empty, + displayInfo: displayInfo + ) + } private func makeChannelController( messages: [ChatMessage] = [] @@ -1715,7 +1929,6 @@ import XCTest pinnedMessages: [], pendingMessages: [], muteDetails: nil, - previewMessage: nil, draftMessage: nil, activeLiveLocations: [], pushPreference: nil diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/MessageComposerView_Tests.swift b/StreamChatSwiftUITests/Tests/ChatChannel/MessageComposerView_Tests.swift index c9a491ce4..8793ac419 100644 --- a/StreamChatSwiftUITests/Tests/ChatChannel/MessageComposerView_Tests.swift +++ b/StreamChatSwiftUITests/Tests/ChatChannel/MessageComposerView_Tests.swift @@ -18,9 +18,8 @@ import XCTest override func setUp() { super.setUp() - let imageLoader = TestImagesLoader_Mock() let utils = Utils( - imageLoader: imageLoader, + mediaLoader: MediaLoader_Mock(), messageListConfig: MessageListConfig( becomesFirstResponderOnOpen: true, draftMessagesEnabled: true @@ -42,7 +41,7 @@ import XCTest messageController: nil, quotedMessage: .constant(nil), editedMessage: .constant(nil), - onMessageSent: {} + willSendMessage: {} ) .frame(width: composerWidth, height: 200) @@ -62,7 +61,7 @@ import XCTest messageController: nil, quotedMessage: .constant(nil), editedMessage: .constant(nil), - onMessageSent: {} + willSendMessage: {} ) .environment(\.layoutDirection, .rightToLeft) .frame(width: defaultScreenSize.width, height: 100) @@ -86,7 +85,7 @@ import XCTest messageController: nil, quotedMessage: .constant(nil), editedMessage: .constant(nil), - onMessageSent: {} + willSendMessage: {} ) .environment(\.layoutDirection, .rightToLeft) .frame(width: defaultScreenSize.width, height: 100) @@ -113,7 +112,7 @@ import XCTest messageController: nil, quotedMessage: .constant(nil), editedMessage: .constant(nil), - onMessageSent: {} + willSendMessage: {} ) .frame(width: size.width, height: size.height) @@ -138,7 +137,7 @@ import XCTest messageController: nil, quotedMessage: .constant(nil), editedMessage: .constant(nil), - onMessageSent: {} + willSendMessage: {} ) .frame(width: size.width, height: size.height) @@ -166,7 +165,7 @@ import XCTest messageController: nil, quotedMessage: .constant(nil), editedMessage: .constant(nil), - onMessageSent: {} + willSendMessage: {} ) .frame(width: size.width, height: size.height) @@ -199,7 +198,7 @@ import XCTest messageController: nil, quotedMessage: .constant(nil), editedMessage: .constant(nil), - onMessageSent: {} + willSendMessage: {} ) .frame(width: size.width, height: size.height) @@ -227,7 +226,7 @@ import XCTest messageController: nil, quotedMessage: .constant(quoted), editedMessage: .constant(nil), - onMessageSent: {} + willSendMessage: {} ) .frame(width: size.width, height: size.height) @@ -250,7 +249,7 @@ import XCTest messageController: nil, quotedMessage: .constant(nil), editedMessage: .constant(nil), - onMessageSent: {} + willSendMessage: {} ) .frame(width: size.width, height: size.height) @@ -276,7 +275,7 @@ import XCTest messageController: nil, quotedMessage: .constant(nil), editedMessage: .constant(nil), - onMessageSent: {} + willSendMessage: {} ) .frame(width: size.width, height: size.height) @@ -449,7 +448,7 @@ import XCTest messageController: nil, quotedMessage: .constant(nil), editedMessage: .constant(nil), - onMessageSent: {} + willSendMessage: {} ) .frame(width: composerWidth, height: 200) @@ -457,6 +456,78 @@ import XCTest AssertSnapshot(view, variants: [.defaultLight, .defaultDark]) } + // MARK: - Send Button Icon + + func test_messageComposerView_sendButton_noCommandSelected() { + // Given — text entered, no command: send button shows the standard composerSend icon + let factory = DefaultViewFactory.shared + let channelController = ChatChannelTestHelpers.makeChannelController(chatClient: chatClient) + let viewModel = MessageComposerViewModel(channelController: channelController, messageController: nil) + viewModel.text = "Hello" + + // When + let view = MessageComposerView( + viewFactory: factory, + viewModel: viewModel, + channelController: channelController, + messageController: nil, + quotedMessage: .constant(nil), + editedMessage: .constant(nil), + willSendMessage: {} + ) + .frame(width: composerWidth, height: 56) + + // Then + AssertSnapshot(view, variants: [.defaultLight, .defaultDark]) + } + + func test_messageComposerView_sendButton_commandSelected_noText() { + // Given — instant command active, no text: send button shows selectionBadgeIcon (disabled) + let factory = DefaultViewFactory.shared + let channelController = ChatChannelTestHelpers.makeChannelController(chatClient: chatClient) + let viewModel = MessageComposerViewModel(channelController: channelController, messageController: nil) + viewModel.composerCommand = ComposerCommandFactory.shared.giphy() + + // When + let view = MessageComposerView( + viewFactory: factory, + viewModel: viewModel, + channelController: channelController, + messageController: nil, + quotedMessage: .constant(nil), + editedMessage: .constant(nil), + willSendMessage: {} + ) + .frame(width: composerWidth, height: 56) + + // Then + AssertSnapshot(view, variants: [.defaultLight, .defaultDark]) + } + + func test_messageComposerView_sendButton_commandSelected_withText() { + // Given — instant command active with text: send button shows selectionBadgeIcon (enabled) + let factory = DefaultViewFactory.shared + let channelController = ChatChannelTestHelpers.makeChannelController(chatClient: chatClient) + let viewModel = MessageComposerViewModel(channelController: channelController, messageController: nil) + viewModel.composerCommand = ComposerCommandFactory.shared.giphy() + viewModel.text = "funny cat" + + // When + let view = MessageComposerView( + viewFactory: factory, + viewModel: viewModel, + channelController: channelController, + messageController: nil, + quotedMessage: .constant(nil), + editedMessage: .constant(nil), + willSendMessage: {} + ) + .frame(width: composerWidth, height: 56) + + // Then + AssertSnapshot(view, variants: [.defaultLight, .defaultDark]) + } + // MARK: - Send In Channel func test_messageComposerView_sendInChannel_selected() { @@ -483,7 +554,7 @@ import XCTest messageController: messageController, quotedMessage: .constant(nil), editedMessage: .constant(nil), - onMessageSent: {} + willSendMessage: {} ) .frame(width: size.width, height: size.height) @@ -515,7 +586,7 @@ import XCTest messageController: messageController, quotedMessage: .constant(nil), editedMessage: .constant(nil), - onMessageSent: {} + willSendMessage: {} ) .frame(width: size.width, height: size.height) @@ -578,7 +649,7 @@ import XCTest messageController: nil, quotedMessage: .constant(nil), editedMessage: .constant(nil), - onMessageSent: {} + willSendMessage: {} ) .frame(width: composerWidth, height: 200) @@ -794,7 +865,7 @@ import XCTest messageController: nil, quotedMessage: .constant(nil), editedMessage: .constant(nil), - onMessageSent: {} + willSendMessage: {} ) .frame(width: composerWidth) @@ -844,7 +915,7 @@ import XCTest // Themed streamChat?.appearance.colorPalette.backgroundCoreInverse = UIColor(Color.indigo) - streamChat?.appearance.colorPalette.textOnDark = .yellow + streamChat?.appearance.colorPalette.textOnInverse = .yellow AssertSnapshot(view, variants: .onlyUserInterfaceStyles, size: size, suffix: "themed") } @@ -1079,7 +1150,7 @@ import XCTest channelController: channelController, quotedMessage: .constant(nil), editedMessage: .constant(nil), - onMessageSent: {} + willSendMessage: {} ) } @@ -1249,7 +1320,7 @@ import XCTest channelController: channelController, quotedMessage: .constant(nil), editedMessage: .constant(editedMessage), - onMessageSent: {} + willSendMessage: {} ) } @@ -1282,7 +1353,7 @@ import XCTest channelController: channelController, quotedMessage: .constant(mockQuotedMessage), editedMessage: .constant(nil), - onMessageSent: {} + willSendMessage: {} ) .frame(width: size.width, height: size.height) @@ -1318,7 +1389,7 @@ import XCTest messageController: nil, quotedMessage: .constant(nil), editedMessage: .constant(nil), - onMessageSent: {} + willSendMessage: {} ) view.addToViewHierarchy() @@ -1360,7 +1431,7 @@ import XCTest messageController: nil, quotedMessage: .constant(nil), editedMessage: .constant(nil), - onMessageSent: {} + willSendMessage: {} ) view.addToViewHierarchy() @@ -1398,7 +1469,7 @@ import XCTest messageController: nil, quotedMessage: .constant(nil), editedMessage: .constant(nil), - onMessageSent: {} + willSendMessage: {} ) view.addToViewHierarchy() @@ -1435,7 +1506,7 @@ import XCTest messageController: nil, quotedMessage: .constant(nil), editedMessage: .constant(nil), - onMessageSent: {} + willSendMessage: {} ) view.addToViewHierarchy() @@ -1464,7 +1535,7 @@ import XCTest messageController: nil, quotedMessage: .constant(nil), editedMessage: .constant(nil), - onMessageSent: {} + willSendMessage: {} ) .frame(width: size.width, height: size.height) @@ -1493,7 +1564,7 @@ import XCTest channelController: channelController, quotedMessage: .constant(nil), editedMessage: .constant(nil), - onMessageSent: {} + willSendMessage: {} ) .frame(width: size.width, height: size.height) @@ -1518,7 +1589,7 @@ import XCTest messageController: nil, quotedMessage: .constant(nil), editedMessage: .constant(nil), - onMessageSent: {} + willSendMessage: {} ) .frame(width: composerWidth) diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/MessageImagePreviewView_Tests.swift b/StreamChatSwiftUITests/Tests/ChatChannel/MessageImagePreviewView_Tests.swift new file mode 100644 index 000000000..6e1004132 --- /dev/null +++ b/StreamChatSwiftUITests/Tests/ChatChannel/MessageImagePreviewView_Tests.swift @@ -0,0 +1,72 @@ +// +// Copyright © 2026 Stream.io Inc. All rights reserved. +// + +import SnapshotTesting +@testable import StreamChat +@testable import StreamChatSwiftUI +import StreamSwiftTestHelpers +import SwiftUI +import XCTest + +@MainActor class MessageImagePreviewView_Tests: StreamChatTestCase { + private let containerSize = CGSize(width: 80, height: 80) + + // MARK: - Snapshot + + func test_messageImagePreviewView_defaultSize() { + // Given + let view = containerView { + MessageImagePreviewView(url: .localYodaImage) + } + + // Then + AssertSnapshot(view, variants: [.defaultLight], size: containerSize) + } + + func test_messageImagePreviewView_customSize() { + // Given + let customSize: CGFloat = 60 + let container = CGSize(width: customSize + 20, height: customSize + 20) + let view = containerView(size: container) { + MessageImagePreviewView(url: .localYodaImage, size: customSize) + } + + // Then + AssertSnapshot(view, variants: [.defaultLight], size: container) + } + + // MARK: - Image Loading + + func test_messageImagePreviewView_loadsImage() { + // Given + let imageLoader = streamChat?.utils.mediaLoader as? MediaLoader_Mock + let view = MessageImagePreviewView(url: .localYodaImage) + + // When + showView(view) + + let expectation = expectation(description: "Image loaded") + DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { + expectation.fulfill() + } + wait(for: [expectation], timeout: 2.0) + + // Then + XCTAssertEqual(imageLoader?.loadImageCalled, true) + } + + // MARK: - Helpers + + private func containerView( + size: CGSize? = nil, + @ViewBuilder content: () -> Content + ) -> some View { + let size = size ?? containerSize + return ZStack { + Color(UIColor.systemBackground) + content() + } + .frame(width: size.width, height: size.height) + } +} diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/MessageItemView_Tests.swift b/StreamChatSwiftUITests/Tests/ChatChannel/MessageItemView_Tests.swift index 910843204..06199dcc1 100644 --- a/StreamChatSwiftUITests/Tests/ChatChannel/MessageItemView_Tests.swift +++ b/StreamChatSwiftUITests/Tests/ChatChannel/MessageItemView_Tests.swift @@ -17,10 +17,8 @@ import XCTest override func setUp() { super.setUp() - let imageLoader = TestImagesLoader_Mock() let utils = Utils( - videoPreviewLoader: VideoPreviewLoader_Mock(), - imageLoader: imageLoader, + mediaLoader: MediaLoader_Mock(), composerConfig: ComposerConfig(isVoiceRecordingEnabled: true) ) streamChat = StreamChat(chatClient: chatClient, utils: utils) @@ -154,6 +152,24 @@ import XCTest assertSnapshot(matching: view, as: .image(perceptualPrecision: precision)) } + func test_messageContainerViewDeleted_snapshot() { + // Given + let message = ChatMessage.mock( + id: .unique, + cid: .unique, + text: "This was the original message", + author: .mock(id: Self.currentUserId, name: "Martin"), + deletedAt: Date(), + isSentByCurrentUser: true + ) + + // When + let view = testMessageViewContainer(message: message) + + // Then + assertSnapshot(matching: view, as: .image(perceptualPrecision: precision)) + } + func test_messageContainerViewPinned_snapshot() { // Given let message = ChatMessage.mock( @@ -355,6 +371,94 @@ import XCTest assertSnapshot(matching: view, as: .image(perceptualPrecision: precision)) } + func test_imageAttachments_uploading_snapshot() { + // Given + let message = ChatMessage.mock( + id: .unique, + cid: .unique, + text: "Uploading...", + author: .mock(id: Self.currentUserId), + attachments: [ChatChannelTestHelpers.imageAttachment(state: .uploading(progress: 0.5))], + localState: .sending, + isSentByCurrentUser: true + ) + + // When + let view = testMessageViewContainer(message: message, channel: .mockNonDMChannel(), height: 300) + + // Then + AssertSnapshot(view, variants: .onlyUserInterfaceStyles) + } + + func test_imageAttachments_uploadingWithoutText_snapshot() { + // Given + let message = ChatMessage.mock( + id: .unique, + cid: .unique, + text: "", + author: .mock(id: Self.currentUserId), + attachments: [ChatChannelTestHelpers.imageAttachment(state: .uploading(progress: 0.3))], + localState: .sending, + isSentByCurrentUser: true + ) + + // When + let view = testMessageViewContainer(message: message, channel: .mockNonDMChannel(), height: 300) + + // Then + AssertSnapshot(view, variants: .onlyUserInterfaceStyles) + } + + func test_multipleImageAttachments_uploading_snapshot() { + // Given + let attachments = ChatChannelTestHelpers.imageAttachments( + count: 3, + originalWidth: 1600, + originalHeight: 1200, + state: .uploading(progress: 0.6) + ) + let message = ChatMessage.mock( + id: .unique, + cid: .unique, + text: "", + author: .mock(id: Self.currentUserId), + attachments: attachments, + localState: .sending, + isSentByCurrentUser: true + ) + + // When + let view = testMessageViewContainer(message: message, channel: .mockNonDMChannel(), height: 300) + + // Then + AssertSnapshot(view, variants: .onlyUserInterfaceStyles) + } + + func test_multipleImageAttachments_failed_snapshot() { + // Given + let attachments = ChatChannelTestHelpers.imageAttachments( + count: 4, + originalWidth: 1600, + originalHeight: 1200, + state: .uploadingFailed + ) + let message = ChatMessage.mock( + id: .unique, + cid: .unique, + text: "", + author: .mock(id: Self.currentUserId), + attachments: attachments, + localState: .sendingFailed, + isSentByCurrentUser: true + ) + + // When + let view = testMessageViewContainer(message: message, channel: .mockNonDMChannel(), height: 300) + + // Then + AssertSnapshot(view, variants: .onlyUserInterfaceStyles) + } + func test_translatedText_participant_snapshot() { // Given let message = ChatMessage.mock( @@ -369,7 +473,6 @@ import XCTest // When let view = testMessageViewContainer(message: message) - .environment(\.channelTranslationLanguage, .spanish) // Then assertSnapshot(matching: view, as: .image(perceptualPrecision: precision)) @@ -390,7 +493,6 @@ import XCTest // When let view = testMessageViewContainer(message: message) - .environment(\.channelTranslationLanguage, .spanish) // Then AssertSnapshot(view, size: CGSize(width: 375, height: 200)) @@ -532,7 +634,6 @@ import XCTest ) messageViewModel.mockOriginalTextShown = true let view = testMessageViewContainer(message: message, messageViewModel: messageViewModel) - .environment(\.channelTranslationLanguage, .spanish) // Then assertSnapshot(matching: view, as: .image(perceptualPrecision: precision)) @@ -567,7 +668,6 @@ import XCTest ) messageViewModel.mockOriginalTextShown = false let view = testMessageViewContainer(message: message, messageViewModel: messageViewModel) - .environment(\.channelTranslationLanguage, .spanish) // Then assertSnapshot(matching: view, as: .image(perceptualPrecision: precision)) @@ -601,7 +701,6 @@ import XCTest ) ) let view = testMessageViewContainer(message: message, messageViewModel: messageViewModel) - .environment(\.channelTranslationLanguage, .spanish) // Then assertSnapshot(matching: view, as: .image(perceptualPrecision: precision)) @@ -730,7 +829,6 @@ import XCTest shownAsPreview: true ) .background(Color(colors.backgroundCoreScrim)) - .environment(\.channelTranslationLanguage, .spanish) // Then AssertSnapshot(view, size: CGSize(width: 375, height: 200)) @@ -889,14 +987,204 @@ import XCTest isSwipeToQuoteReplyPossible: true, quotedMessage: .constant(nil), initialOffsetX: offset - ) - ) + )) .offset(x: offset) // Then AssertSnapshot(view, size: CGSize(width: 375, height: 200)) } + func test_swipeToReplyIndicator_outgoing_snapshot() { + // Given + let message = ChatMessage.mock( + id: .unique, + cid: .unique, + text: "Swipe to reply message", + author: .mock(id: Self.currentUserId, name: "Martin"), + localState: nil, + isSentByCurrentUser: true + ) + let channel = ChatChannel.mockDMChannel(config: .mock(repliesEnabled: true)) + let offset: CGFloat = 50 + + let view = testMessageViewContainer(message: message, channel: channel) + .modifier(SwipeToReplyModifier( + message: message, + channel: channel, + isSwipeToQuoteReplyPossible: true, + quotedMessage: .constant(nil), + initialOffsetX: offset + )) + .offset(x: offset) + + // Then + AssertSnapshot(view, size: CGSize(width: 375, height: 200)) + } + + // MARK: - Single media without caption (sharp tail corner) + + func test_singleImageNoCaption_outgoing_firstInGroup_snapshot() { + // Given + let attachments = ChatChannelTestHelpers.imageAttachments( + count: 1, + originalWidth: 1600, + originalHeight: 1200 + ) + let message = ChatMessage.mock( + id: .unique, + cid: .unique, + text: "", + author: .mock(id: Self.currentUserId, name: "Martin"), + attachments: attachments, + isSentByCurrentUser: true + ) + + // When + let view = testMessageViewContainer(message: message, height: 300) + + // Then + assertSnapshot(matching: view, as: .image(perceptualPrecision: precision)) + } + + func test_singleImageNoCaption_incoming_firstInGroup_snapshot() { + // Given + let attachments = ChatChannelTestHelpers.imageAttachments( + count: 1, + originalWidth: 1600, + originalHeight: 1200 + ) + let message = ChatMessage.mock( + id: .unique, + cid: .unique, + text: "", + author: .mock(id: .unique, name: "Alice"), + attachments: attachments, + isSentByCurrentUser: false + ) + + // When + let view = testMessageViewContainer(message: message, channel: .mockNonDMChannel(), height: 300) + + // Then + assertSnapshot(matching: view, as: .image(perceptualPrecision: precision)) + } + + func test_singleImageNoCaption_notFirstInGroup_snapshot() { + // Given + let attachments = ChatChannelTestHelpers.imageAttachments( + count: 1, + originalWidth: 1600, + originalHeight: 1200 + ) + let message = ChatMessage.mock( + id: .unique, + cid: .unique, + text: "", + author: .mock(id: Self.currentUserId, name: "Martin"), + attachments: attachments, + isSentByCurrentUser: true + ) + + // When + let view = testMessageViewContainer(message: message, height: 300, showsAllInfo: false) + + // Then + assertSnapshot(matching: view, as: .image(perceptualPrecision: precision)) + } + + func test_singleImageWithCaption_outgoing_snapshot() { + // Given + let attachments = ChatChannelTestHelpers.imageAttachments( + count: 1, + originalWidth: 1600, + originalHeight: 1200 + ) + let message = ChatMessage.mock( + id: .unique, + cid: .unique, + text: "Photo caption", + author: .mock(id: Self.currentUserId, name: "Martin"), + attachments: attachments, + isSentByCurrentUser: true + ) + + // When + let view = testMessageViewContainer(message: message, height: 300) + + // Then + assertSnapshot(matching: view, as: .image(perceptualPrecision: precision)) + } + + func test_singleVideoNoCaption_outgoing_firstInGroup_snapshot() { + // Given + let message = ChatMessage.mock( + id: .unique, + cid: .unique, + text: "", + author: .mock(id: Self.currentUserId, name: "Martin"), + attachments: ChatChannelTestHelpers.videoAttachments, + isSentByCurrentUser: true + ) + + // When + let view = testMessageViewContainer(message: message, height: 300) + + // Then + assertSnapshot(matching: view, as: .image(perceptualPrecision: precision)) + } + + func test_singleImageNoCaption_portrait_outgoing_snapshot() { + // Given + let attachments = ChatChannelTestHelpers.imageAttachments( + count: 1, + originalWidth: 1200, + originalHeight: 1600 + ) + let message = ChatMessage.mock( + id: .unique, + cid: .unique, + text: "", + author: .mock(id: Self.currentUserId, name: "Martin"), + attachments: attachments, + isSentByCurrentUser: true + ) + + // When + let view = testMessageViewContainer(message: message, height: 300) + + // Then + assertSnapshot(matching: view, as: .image(perceptualPrecision: precision)) + } + + func test_portraitImageWithOneReaction_snapshot() { + // Given + let reactions: [MessageReactionType: Int] = [ + MessageReactionType(rawValue: "like"): 1 + ] + let channel = ChatChannel.mockNonDMChannel() + let attachments = ChatChannelTestHelpers.imageAttachments( + count: 1, + originalWidth: 1200, + originalHeight: 1600 + ) + let message = ChatMessage.mock( + id: .unique, + cid: channel.cid, + text: "", + author: .mock(id: .unique, name: "Alice"), + reactionScores: reactions, + reactionCounts: reactions, + attachments: attachments, + isSentByCurrentUser: false + ) + + // When + let view = testMessageViewContainer(message: message, channel: channel, height: 340) + + // Then + AssertSnapshot(view) + } + // MARK: - private func testMessageViewContainer( @@ -914,7 +1202,7 @@ import XCTest channel: channelOrMock, message: message, width: defaultScreenSize.width, - showsAllInfo: true, + showsAllInfo: showsAllInfo, shownAsPreview: shownAsPreview, isInThread: false, isLast: false, diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/MessageListView_Tests.swift b/StreamChatSwiftUITests/Tests/ChatChannel/MessageListView_Tests.swift index ddbacd626..bca3b4093 100644 --- a/StreamChatSwiftUITests/Tests/ChatChannel/MessageListView_Tests.swift +++ b/StreamChatSwiftUITests/Tests/ChatChannel/MessageListView_Tests.swift @@ -147,6 +147,33 @@ import XCTest assertSnapshot(matching: view, as: .image(perceptualPrecision: precision)) } + func test_jumpToUnreadButton_snapshotSingleUnread() { + // Given + let button = JumpToUnreadButton(unreadCount: 1, onTap: {}, onClose: {}) + .padding() + + // Then + AssertSnapshot(button, size: CGSize(width: 250, height: 60)) + } + + func test_jumpToUnreadButton_snapshotMultipleUnread() { + // Given + let button = JumpToUnreadButton(unreadCount: 17, onTap: {}, onClose: {}) + .padding() + + // Then + AssertSnapshot(button, size: CGSize(width: 250, height: 60)) + } + + func test_jumpToUnreadButton_snapshotHighUnreadCount() { + // Given + let button = JumpToUnreadButton(unreadCount: 99, onTap: {}, onClose: {}) + .padding() + + // Then + AssertSnapshot(button, size: CGSize(width: 250, height: 60)) + } + // MARK: - Init with ChatChannelViewModel snapshot tests func test_messageListView_viewModelInit_withReactions() { @@ -178,7 +205,7 @@ import XCTest .applyDefaultSize() // Then - assertSnapshot(matching: view, as: .image(perceptualPrecision: precision)) + AssertSnapshot(view) } func test_messageListView_groupChannel_withReactions() { @@ -264,6 +291,229 @@ import XCTest assertSnapshot(matching: view, as: .image(perceptualPrecision: precision)) } + // MARK: - Dividers + + func test_messageListView_threadRepliesSeparator() { + // Given + let channel = ChatChannel.mockDMChannel() + let parentId: MessageId = "parent-id" + let parentMessage = ChatMessage.mock( + id: parentId, + cid: channel.cid, + text: "Which item has priority?", + author: .mock(id: "user1", name: "Wesley"), + replyCount: 2 + ) + let reply1 = ChatMessage.mock( + id: "reply1", + cid: channel.cid, + text: "I think the first one is the most important.", + author: .mock(id: "user2", name: "Emma"), + parentMessageId: parentId + ) + let reply2 = ChatMessage.mock( + id: "reply2", + cid: channel.cid, + text: "Agreed, let's prioritize that.", + author: .mock(id: "user1", name: "Wesley"), + parentMessageId: parentId, + isSentByCurrentUser: true + ) + let messages: [ChatMessage] = [reply2, reply1, parentMessage] + let view = MessageListView( + factory: DefaultViewFactory.shared, + channel: channel, + messages: messages, + messagesGroupingInfo: [:], + scrolledId: .constant(nil), + showScrollToLatestButton: .constant(false), + quotedMessage: .constant(nil), + currentDateString: nil, + listId: "listId", + isMessageThread: true, + shouldShowTypingIndicator: false, + onMessageAppear: { _, _ in }, + onScrollToBottom: {}, + onLongPress: { _ in } + ) + .applyDefaultSize() + + // Then + AssertSnapshot(view) + } + + func test_messageListView_threadRepliesSeparator_hiddenWhenNotAllLoaded() { + // Given + let channel = ChatChannel.mockDMChannel() + let parentId: MessageId = "parent-id" + let parentMessage = ChatMessage.mock( + id: parentId, + cid: channel.cid, + text: "Which item has priority?", + author: .mock(id: "user1", name: "Wesley"), + replyCount: 5 + ) + let reply1 = ChatMessage.mock( + id: "reply1", + cid: channel.cid, + text: "I think the first one is the most important.", + author: .mock(id: "user2", name: "Emma"), + parentMessageId: parentId + ) + let messages: [ChatMessage] = [reply1, parentMessage] + let view = MessageListView( + factory: DefaultViewFactory.shared, + channel: channel, + messages: messages, + messagesGroupingInfo: [:], + scrolledId: .constant(nil), + showScrollToLatestButton: .constant(false), + quotedMessage: .constant(nil), + currentDateString: nil, + listId: "listId", + isMessageThread: true, + shouldShowTypingIndicator: false, + onMessageAppear: { _, _ in }, + onScrollToBottom: {}, + onLongPress: { _ in } + ) + .applyDefaultSize() + + // Then + AssertSnapshot(view) + } + + // MARK: - Grouped Messages with Annotations + + func test_messageListView_groupedMessages_withThreadReplyAnnotation() { + // Given + let channel = ChatChannel.mockNonDMChannel() + let author = ChatUser.mock(id: "martin", name: "Martin") + let baseTime = Date(timeIntervalSince1970: 1000) + let msg1 = ChatMessage.mock( + id: "msg1", + cid: channel.cid, + text: "Let me check the latest updates.", + author: author, + createdAt: baseTime.addingTimeInterval(-20) + ) + let msg2 = ChatMessage.mock( + id: "msg2", + cid: channel.cid, + text: "I found the issue in the logs.", + author: author, + createdAt: baseTime.addingTimeInterval(-10), + parentMessageId: .unique, + showReplyInChannel: true + ) + let msg3 = ChatMessage.mock( + id: "msg3", + cid: channel.cid, + text: "Looks like it was a timeout.", + author: author, + createdAt: baseTime + ) + let messages = [msg3, msg2, msg1] + let messagesGroupingInfo: [String: [String]] = [ + msg3.id: [firstMessageKey], + msg1.id: [lastMessageKey] + ] + let view = MessageListView( + factory: DefaultViewFactory.shared, + channel: channel, + messages: messages, + messagesGroupingInfo: messagesGroupingInfo, + scrolledId: .constant(nil), + showScrollToLatestButton: .constant(false), + quotedMessage: .constant(nil), + currentDateString: nil, + listId: "listId", + isMessageThread: false, + shouldShowTypingIndicator: false, + onMessageAppear: { _, _ in }, + onScrollToBottom: {}, + onLongPress: { _ in } + ) + .applyDefaultSize() + + // Then + assertSnapshot(matching: view, as: .image(perceptualPrecision: precision)) + } + + func test_messageListView_groupedMessages_withAllAnnotations() { + // Given + streamChat = StreamChat(chatClient: chatClient, utils: Utils( + messageListConfig: .init(messageDisplayOptions: MessageDisplayOptions(showOriginalTranslatedButton: true)) + )) + + let channel = ChatChannel.mock( + cid: .unique, + config: .mock(messageRemindersEnabled: true), + membership: .mock(id: .unique, language: .spanish) + ) + let author = ChatUser.mock(id: "martin", name: "Martin") + let baseTime = Date(timeIntervalSince1970: 1000) + let msg1 = ChatMessage.mock( + id: "msg1", + cid: channel.cid, + text: "Let me check the latest updates.", + author: author, + createdAt: baseTime.addingTimeInterval(-20) + ) + let msg2 = ChatMessage.mock( + id: "msg2", + cid: channel.cid, + text: "I found the issue in the logs.", + author: author, + createdAt: baseTime.addingTimeInterval(-10), + parentMessageId: .unique, + showReplyInChannel: true, + translations: [.spanish: "Encontré el problema en los registros."], + pinDetails: MessagePinDetails( + pinnedAt: Date(), + pinnedBy: .mock(id: .unique, name: "Martin"), + expiresAt: nil + ), + reminder: MessageReminderInfo( + remindAt: Date().addingTimeInterval(3600), + createdAt: Date(), + updatedAt: Date() + ) + ) + let msg3 = ChatMessage.mock( + id: "msg3", + cid: channel.cid, + text: "Looks like it was a timeout.", + author: author, + createdAt: baseTime + ) + let messages = [msg3, msg2, msg1] + let messagesGroupingInfo: [String: [String]] = [ + msg3.id: [firstMessageKey], + msg1.id: [lastMessageKey] + ] + let view = MessageListView( + factory: DefaultViewFactory.shared, + channel: channel, + messages: messages, + messagesGroupingInfo: messagesGroupingInfo, + scrolledId: .constant(nil), + showScrollToLatestButton: .constant(false), + quotedMessage: .constant(nil), + currentDateString: nil, + listId: "listId", + isMessageThread: false, + shouldShowTypingIndicator: false, + onMessageAppear: { _, _ in }, + onScrollToBottom: {}, + onLongPress: { _ in } + ) + .applyDefaultSize() + + // Then + assertSnapshot(matching: view, as: .image(perceptualPrecision: precision)) + } + // MARK: - private func makeMessageListView( diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/MessageTopView_Tests.swift b/StreamChatSwiftUITests/Tests/ChatChannel/MessageTopView_Tests.swift index 1a9ebd13d..17ce9d9b0 100644 --- a/StreamChatSwiftUITests/Tests/ChatChannel/MessageTopView_Tests.swift +++ b/StreamChatSwiftUITests/Tests/ChatChannel/MessageTopView_Tests.swift @@ -26,9 +26,30 @@ import XCTest ) ) - let view = makeAnnotationsView(message: message) + let size = CGSize(width: 375, height: 72) + let view = makeAnnotationsView(message: message, size: size) - AssertSnapshot(view, size: CGSize(width: 375, height: 40)) + AssertSnapshot(view, size: size) + } + + func test_pinnedByYouAnnotation_snapshot() { + let currentUserId = StreamChatTestCase.currentUserId + let message = ChatMessage.mock( + id: .unique, + cid: .unique, + text: "Pinned by me", + author: .mock(id: .unique, name: "Martin"), + pinDetails: MessagePinDetails( + pinnedAt: Date(), + pinnedBy: .mock(id: currentUserId, name: "Martin"), + expiresAt: nil + ) + ) + + let size = CGSize(width: 375, height: 72) + let view = makeAnnotationsView(message: message, size: size) + + AssertSnapshot(view, size: size) } // MARK: - Sent in channel @@ -43,9 +64,10 @@ import XCTest showReplyInChannel: true ) - let view = makeAnnotationsView(message: message, isInThread: true) + let size = CGSize(width: 375, height: 72) + let view = makeAnnotationsView(message: message, isInThread: true, size: size) - AssertSnapshot(view, size: CGSize(width: 375, height: 40)) + AssertSnapshot(view, size: size) } // MARK: - Replied to thread @@ -60,17 +82,19 @@ import XCTest showReplyInChannel: true ) - let view = makeAnnotationsView(message: message, isInThread: false) + let size = CGSize(width: 375, height: 72) + let view = makeAnnotationsView(message: message, isInThread: false, size: size) - AssertSnapshot(view, size: CGSize(width: 375, height: 40)) + AssertSnapshot(view, size: size) } // MARK: - Reminder func test_reminderAnnotation_snapshot() { + let channel = ChatChannel.mockDMChannel(config: .mock(messageRemindersEnabled: true)) let message = ChatMessage.mock( id: .unique, - cid: .unique, + cid: channel.cid, text: "Message with reminder", author: .mock(id: .unique), reminder: MessageReminderInfo( @@ -80,9 +104,10 @@ import XCTest ) ) - let view = makeAnnotationsView(message: message) + let size = CGSize(width: 375, height: 72) + let view = makeAnnotationsView(message: message, channel: channel, size: size) - AssertSnapshot(view, size: CGSize(width: 375, height: 40)) + AssertSnapshot(view, size: size) } // MARK: - Translated @@ -105,9 +130,10 @@ import XCTest translations: [.spanish: "Hola"] ) - let view = makeAnnotationsView(message: message, channel: channel) + let size = CGSize(width: 375, height: 72) + let view = makeAnnotationsView(message: message, channel: channel, size: size) - AssertSnapshot(view, size: CGSize(width: 375, height: 40)) + AssertSnapshot(view, size: size) } // MARK: - All annotations (not in thread) @@ -119,6 +145,7 @@ import XCTest let channel = ChatChannel.mock( cid: .unique, + config: .mock(messageRemindersEnabled: true), membership: .mock(id: .unique, language: .spanish) ) @@ -142,9 +169,10 @@ import XCTest ) ) - let view = makeAnnotationsView(message: message, channel: channel, isInThread: false) + let size = CGSize(width: 375, height: 100) + let view = makeAnnotationsView(message: message, channel: channel, isInThread: false, size: size) - AssertSnapshot(view, size: CGSize(width: 375, height: 140)) + AssertSnapshot(view, size: size) } // MARK: - All annotations (in thread) @@ -156,6 +184,7 @@ import XCTest let channel = ChatChannel.mock( cid: .unique, + config: .mock(messageRemindersEnabled: true), membership: .mock(id: .unique, language: .spanish) ) @@ -179,9 +208,10 @@ import XCTest ) ) - let view = makeAnnotationsView(message: message, channel: channel, isInThread: true) + let size = CGSize(width: 375, height: 100) + let view = makeAnnotationsView(message: message, channel: channel, isInThread: true, size: size) - AssertSnapshot(view, size: CGSize(width: 375, height: 140)) + AssertSnapshot(view, size: size) } // MARK: - Helpers @@ -189,7 +219,8 @@ import XCTest private func makeAnnotationsView( message: ChatMessage, channel: ChatChannel? = nil, - isInThread: Bool = false + isInThread: Bool = false, + size: CGSize ) -> some View { let ch = channel ?? .mockDMChannel() let viewModel = MessageViewModel(message: message, channel: ch, isInThread: isInThread) @@ -198,6 +229,6 @@ import XCTest channel: ch, messageViewModel: viewModel ) - .frame(width: 375) + .applySize(size) } } diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/MessageViewMultiRowReactions_Tests.swift b/StreamChatSwiftUITests/Tests/ChatChannel/MessageViewMultiRowReactions_Tests.swift index 056e7501a..fda7a1566 100644 --- a/StreamChatSwiftUITests/Tests/ChatChannel/MessageViewMultiRowReactions_Tests.swift +++ b/StreamChatSwiftUITests/Tests/ChatChannel/MessageViewMultiRowReactions_Tests.swift @@ -227,7 +227,7 @@ struct CustomMessageReactionView: View { private func color(for reaction: MessageReactionType) -> Color? { let containsUserReaction = userReactionIDs.contains(reaction) - let color = containsUserReaction ? colors.reactionCurrentUserColor : colors.reactionOtherUserColor + let color = containsUserReaction ? colors.accentPrimary : colors.textTertiary return Color(color) } diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/MessageView_Tests.swift b/StreamChatSwiftUITests/Tests/ChatChannel/MessageView_Tests.swift index 43550523d..6d79e24a4 100644 --- a/StreamChatSwiftUITests/Tests/ChatChannel/MessageView_Tests.swift +++ b/StreamChatSwiftUITests/Tests/ChatChannel/MessageView_Tests.swift @@ -11,6 +11,19 @@ import SwiftUI import XCTest @MainActor class MessageView_Tests: StreamChatTestCase { + override func setUp() { + super.setUp() + + streamChat = StreamChat( + chatClient: chatClient, + utils: Utils( + mediaLoader: MediaLoader_Mock(), + messageListConfig: .init(markdownSupportEnabled: true), + composerConfig: .init(isVoiceRecordingEnabled: true) + ) + ) + } + func test_messageViewText_snapshot() { // Given let textMessage = ChatMessage.mock( @@ -34,6 +47,56 @@ import XCTest assertSnapshot(matching: view, as: .image(perceptualPrecision: precision)) } + func test_messageViewText_sendingFailed_singleLine_snapshot() { + // Given + let textMessage = ChatMessage.mock( + id: .unique, + cid: .unique, + text: "test message", + author: .mock(id: .unique), + localState: .sendingFailed + ) + + // When + let view = MessageView( + factory: DefaultViewFactory.shared, + message: textMessage, + contentWidth: defaultScreenSize.width, + isFirst: true, + scrolledId: .constant(nil) + ) + .overlay(SendFailureIndicator()) + .frame(width: defaultScreenSize.width, height: 100) + + // Then + assertSnapshot(matching: view, as: .image(perceptualPrecision: precision)) + } + + func test_messageViewText_sendingFailed_multiLine_snapshot() { + // Given + let textMessage = ChatMessage.mock( + id: .unique, + cid: .unique, + text: "Hey, did you get a chance to look at the venue options for Saturday?", + author: .mock(id: .unique), + localState: .sendingFailed + ) + + // When + let view = MessageView( + factory: DefaultViewFactory.shared, + message: textMessage, + contentWidth: defaultScreenSize.width, + isFirst: true, + scrolledId: .constant(nil) + ) + .overlay(SendFailureIndicator()) + .frame(width: defaultScreenSize.width, height: 150) + + // Then + assertSnapshot(matching: view, as: .image(perceptualPrecision: precision)) + } + func test_messageViewTextMention_snapshot() { // Given let textMessage = ChatMessage.mock( @@ -105,7 +168,63 @@ import XCTest // Then assertSnapshot(matching: view, as: .image(perceptualPrecision: precision)) } - + + func test_messageViewPortraitImage_snapshot() { + // Given + let imageMessage = ChatMessage.mock( + id: .unique, + cid: .unique, + text: "test message", + author: .mock(id: .unique), + attachments: ChatChannelTestHelpers.imageAttachments( + count: 1, + originalWidth: 1200, + originalHeight: 1600 + ) + ) + + // When + let view = MessageView( + factory: DefaultViewFactory.shared, + message: imageMessage, + contentWidth: defaultScreenSize.width, + isFirst: true, + scrolledId: .constant(nil) + ) + .applyDefaultSize() + + // Then + assertSnapshot(matching: view, as: .image(perceptualPrecision: precision)) + } + + func test_messageViewPortraitImageLongText_snapshot() { + // Given + let imageMessage = ChatMessage.mock( + id: .unique, + cid: .unique, + text: "This is a much longer message that should span multiple lines when displayed below the portrait image attachment in the message bubble", + author: .mock(id: .unique), + attachments: ChatChannelTestHelpers.imageAttachments( + count: 1, + originalWidth: 1200, + originalHeight: 1600 + ) + ) + + // When + let view = MessageView( + factory: DefaultViewFactory.shared, + message: imageMessage, + contentWidth: defaultScreenSize.width, + isFirst: true, + scrolledId: .constant(nil) + ) + .applyDefaultSize() + + // Then + assertSnapshot(matching: view, as: .image(perceptualPrecision: precision)) + } + func test_messageViewImage_snapshot2Images() { // Given let imageMessage = ChatMessage.mock( @@ -220,6 +339,68 @@ import XCTest // Then assertSnapshot(matching: view, as: .image(perceptualPrecision: precision)) } + + func test_messageViewQuoted_singleImageAttachment_snapshot() { + // Given + let quoted = ChatMessage.mock( + id: .unique, + cid: .unique, + text: "This is a quoted message", + author: .mock(id: .unique, name: "John Wick") + ) + let message = ChatMessage.mock( + id: .unique, + cid: .unique, + text: "test message", + author: .mock(id: .unique), + quotedMessage: quoted, + attachments: [ChatChannelTestHelpers.imageAttachments[0]] + ) + + // When + let view = MessageView( + factory: DefaultViewFactory.shared, + message: message, + contentWidth: defaultScreenSize.width, + isFirst: true, + scrolledId: .constant(nil) + ) + .applyDefaultSize() + + // Then + AssertSnapshot(view) + } + + func test_messageViewQuoted_singleFileAttachment_snapshot() { + // Given + let quoted = ChatMessage.mock( + id: .unique, + cid: .unique, + text: "This is a quoted message", + author: .mock(id: .unique, name: "John Wick") + ) + let message = ChatMessage.mock( + id: .unique, + cid: .unique, + text: "test message", + author: .mock(id: .unique), + quotedMessage: quoted, + attachments: [ChatChannelTestHelpers.fileAttachments[0]] + ) + + // When + let view = MessageView( + factory: DefaultViewFactory.shared, + message: message, + contentWidth: defaultScreenSize.width, + isFirst: true, + scrolledId: .constant(nil) + ) + .applyDefaultSize() + + // Then + AssertSnapshot(view) + } func test_messageViewGiphy_snapshot() { // Given @@ -304,7 +485,7 @@ import XCTest // Then AssertSnapshot(view) } - + func test_messageViewVideo_snapshot() { // Given let videoMessage = ChatMessage.mock( @@ -540,13 +721,12 @@ import XCTest // When adjustAppearance { appearance in - appearance.colorPalette.messageCurrentUserBackground = [.orange] - appearance.colorPalette.background8 = .yellow - appearance.colorPalette.voiceMessageControlBackground = .cyan - appearance.colorPalette.messageCurrentUserTextColor = .blue - appearance.colorPalette.textLowEmphasis = .red + appearance.colorPalette.chatBackgroundOutgoing = .orange + appearance.colorPalette.backgroundCoreSurfaceStrong = .yellow + appearance.colorPalette.chatTextOutgoing = .blue + appearance.colorPalette.textTertiary = .red appearance.images.playFill = UIImage(systemName: "star")! - appearance.images.fileAac = UIImage(systemName: "scribble")! + appearance.images.fileIcons[.aac] = UIImage(systemName: "scribble")! } let view = MessageView( factory: DefaultViewFactory.shared, @@ -566,6 +746,150 @@ import XCTest ) } + func test_messageViewVoiceRecordingQuotedFromParticipant_snapshot() { + // Given + let quoted = ChatMessage.mock( + id: .unique, + cid: .unique, + text: "This is a quoted message", + author: .mock(id: .unique, name: "John Wick") + ) + let voiceMessage = ChatMessage.mock( + id: .unique, + cid: .unique, + text: "", + author: .mock(id: .unique), + quotedMessage: quoted, + attachments: ChatChannelTestHelpers.voiceRecordingAttachments, + isSentByCurrentUser: false + ) + + // When + let view = MessageView( + factory: DefaultViewFactory.shared, + message: voiceMessage, + contentWidth: defaultScreenSize.width, + isFirst: true, + scrolledId: .constant(nil) + ) + .frame(width: defaultScreenSize.width, height: 200) + .padding() + + // Then + AssertSnapshot( + view, + size: CGSize(width: defaultScreenSize.width, height: 200) + ) + } + + func test_messageViewVoiceRecordingQuotedFromMe_snapshot() { + // Given + let quoted = ChatMessage.mock( + id: .unique, + cid: .unique, + text: "This is a quoted message", + author: .mock(id: .unique, name: "John Wick") + ) + let voiceMessage = ChatMessage.mock( + id: .unique, + cid: .unique, + text: "", + author: .mock(id: .unique), + quotedMessage: quoted, + attachments: ChatChannelTestHelpers.voiceRecordingAttachments, + isSentByCurrentUser: true + ) + + // When + let view = MessageView( + factory: DefaultViewFactory.shared, + message: voiceMessage, + contentWidth: defaultScreenSize.width, + isFirst: true, + scrolledId: .constant(nil) + ) + .frame(width: defaultScreenSize.width, height: 200) + .padding() + + // Then + AssertSnapshot( + view, + size: CGSize(width: defaultScreenSize.width, height: 200) + ) + } + + func test_messageViewVoiceRecordingQuotedWithTextFromParticipant_snapshot() { + // Given + let quoted = ChatMessage.mock( + id: .unique, + cid: .unique, + text: "This is a quoted message", + author: .mock(id: .unique, name: "John Wick") + ) + let voiceMessage = ChatMessage.mock( + id: .unique, + cid: .unique, + text: "Check this voice note", + author: .mock(id: .unique), + quotedMessage: quoted, + attachments: ChatChannelTestHelpers.voiceRecordingAttachments, + isSentByCurrentUser: false + ) + + // When + let view = MessageView( + factory: DefaultViewFactory.shared, + message: voiceMessage, + contentWidth: defaultScreenSize.width, + isFirst: true, + scrolledId: .constant(nil) + ) + .frame(width: defaultScreenSize.width, height: 220) + .padding() + + // Then + AssertSnapshot( + view, + size: CGSize(width: defaultScreenSize.width, height: 220) + ) + } + + func test_messageViewVoiceRecordingQuotedWithTextFromMe_snapshot() { + // Given + let quoted = ChatMessage.mock( + id: .unique, + cid: .unique, + text: "This is a quoted message", + author: .mock(id: .unique, name: "John Wick") + ) + let voiceMessage = ChatMessage.mock( + id: .unique, + cid: .unique, + text: "Check this voice note", + author: .mock(id: .unique), + quotedMessage: quoted, + attachments: ChatChannelTestHelpers.voiceRecordingAttachments, + isSentByCurrentUser: true + ) + + // When + let view = MessageView( + factory: DefaultViewFactory.shared, + message: voiceMessage, + contentWidth: defaultScreenSize.width, + isFirst: true, + scrolledId: .constant(nil) + ) + .frame(width: defaultScreenSize.width, height: 220) + .padding() + + // Then + AssertSnapshot( + view, + size: CGSize(width: defaultScreenSize.width, height: 220) + ) + } + func test_voiceRecordingViewPlaying_snapshot() { // Given let url = URL(string: "https://example.com/recording.m4a")! @@ -676,9 +1000,9 @@ import XCTest func test_linkAttachmentView_customColors_snapshot() { // Given let colorPalette = Appearance.ColorPalette() - colorPalette.messageLinkAttachmentAuthorColor = .orange - colorPalette.messageLinkAttachmentTitleColor = .blue - colorPalette.messageLinkAttachmentTextColor = .red + colorPalette.textPrimary = .blue + colorPalette.chatTextIncoming = .orange + colorPalette.backgroundCoreElevation1 = .cyan var appearance = Appearance() appearance.colorPalette = colorPalette streamChat = StreamChat( @@ -699,7 +1023,8 @@ import XCTest previewURL: .localYodaImage ), width: 200, - isFirst: true + isFirst: true, + isRightAligned: false ) .frame(width: 200, height: 140) @@ -1115,7 +1440,10 @@ import XCTest NSAttributedString.Key.foregroundColor: UIColor.red ] } - let config = MessageListConfig(messageDisplayOptions: displayOptions) + let config = MessageListConfig( + messageDisplayOptions: displayOptions, + markdownSupportEnabled: true + ) let size = messageViewSize() let view = messageView( size: size, diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/PollAttachmentViewModel_Tests.swift b/StreamChatSwiftUITests/Tests/ChatChannel/PollAttachmentViewModel_Tests.swift index c3c95ee06..e6ba63eac 100644 --- a/StreamChatSwiftUITests/Tests/ChatChannel/PollAttachmentViewModel_Tests.swift +++ b/StreamChatSwiftUITests/Tests/ChatChannel/PollAttachmentViewModel_Tests.swift @@ -284,7 +284,7 @@ import XCTest XCTAssertFalse(viewModel.showEndVoteButton) } - func test_pollAttachmentViewModel_canInteract_falseWhenEndVoteConfirmationShown() { + func test_pollAttachmentViewModel_canInteract_trueWhenEndVoteConfirmationShown() { // Given let currentUser = ChatUser.mock(id: StreamChatTestCase.currentUserId) let poll = Poll.mock(createdBy: currentUser) @@ -298,7 +298,7 @@ import XCTest viewModel.endVoteConfirmationShown = true // Then - XCTAssertFalse(viewModel.canInteract) + XCTAssertTrue(viewModel.canInteract) } // MARK: - private diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/PollAttachmentView_Tests.swift b/StreamChatSwiftUITests/Tests/ChatChannel/PollAttachmentView_Tests.swift index 4a59c775e..dc63ea912 100644 --- a/StreamChatSwiftUITests/Tests/ChatChannel/PollAttachmentView_Tests.swift +++ b/StreamChatSwiftUITests/Tests/ChatChannel/PollAttachmentView_Tests.swift @@ -23,7 +23,8 @@ import XCTest factory: DefaultViewFactory.shared, message: message, poll: poll, - isFirst: true + isFirst: true, + width: defaultScreenSize.width ) .frame(width: defaultScreenSize.width, height: 420) @@ -46,7 +47,8 @@ import XCTest factory: DefaultViewFactory.shared, message: message, poll: poll, - isFirst: true + isFirst: true, + width: defaultScreenSize.width ) .frame(width: defaultScreenSize.width, height: 240) @@ -74,7 +76,8 @@ import XCTest factory: DefaultViewFactory.shared, message: message, poll: poll, - isFirst: true + isFirst: true, + width: defaultScreenSize.width ) .frame(width: defaultScreenSize.width, height: 180) @@ -103,7 +106,8 @@ import XCTest factory: DefaultViewFactory.shared, message: message, poll: poll, - isFirst: true + isFirst: true, + width: defaultScreenSize.width ) .frame(width: defaultScreenSize.width, height: 220) @@ -132,7 +136,8 @@ import XCTest factory: DefaultViewFactory.shared, message: message, poll: poll, - isFirst: true + isFirst: true, + width: defaultScreenSize.width ) .frame(width: defaultScreenSize.width, height: 170) diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/QuotedMessageView_Tests.swift b/StreamChatSwiftUITests/Tests/ChatChannel/QuotedMessageView_Tests.swift index 587d1e41a..11fe807e9 100644 --- a/StreamChatSwiftUITests/Tests/ChatChannel/QuotedMessageView_Tests.swift +++ b/StreamChatSwiftUITests/Tests/ChatChannel/QuotedMessageView_Tests.swift @@ -363,6 +363,39 @@ import XCTest AssertSnapshot(view, size: containerSize) } + // MARK: - Reply - Giphy + + func test_quotedMessageView_giphy() { + // Given + let giphyAttachment = ChatMessageGiphyAttachment( + id: .unique, + type: .giphy, + payload: GiphyAttachmentPayload( + title: "Funny GIF", + previewURL: .localYodaImage, + actions: [] + ), + downloadingState: nil, + uploadingState: nil + ) + + let message = ChatMessage.mock( + id: .unique, + cid: .unique, + text: "", + author: author, + attachments: [giphyAttachment.asAnyAttachment] + ) + + // When + let view = containerView { + QuotedMessageView(message: message) + } + + // Then + AssertSnapshot(view, size: containerSize) + } + // MARK: - Reply - Mixed Content (Caption) func test_quotedMessageView_mixedContentWithCaption() { diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ReactionsDetailViewModel_Tests.swift b/StreamChatSwiftUITests/Tests/ChatChannel/ReactionsDetailViewModel_Tests.swift index 40d855aff..b9b68c9a5 100644 --- a/StreamChatSwiftUITests/Tests/ChatChannel/ReactionsDetailViewModel_Tests.swift +++ b/StreamChatSwiftUITests/Tests/ChatChannel/ReactionsDetailViewModel_Tests.swift @@ -8,6 +8,8 @@ import XCTest @MainActor final class ReactionsDetailViewModel_Tests: StreamChatTestCase { + private let currentUserId = StreamChatTestCase.currentUserId + // MARK: - Init func test_init_thenSynchronizeCalled() { @@ -612,6 +614,98 @@ import XCTest XCTAssertEqual(viewModel.message.text, "Updated text") } + func test_messageControllerDidChangeMessage_thenCurrentUserReactionIsInsertedImmediately() { + // Given + let cid = ChannelId.unique + let like = MessageReactionType(rawValue: "like") + let love = MessageReactionType(rawValue: "love") + let message = ChatMessage.mock(cid: cid) + let controller = makeReactionListController(messageId: message.id) + let existingReaction = ChatMessageReaction.mock( + id: "existing", + type: love, + updatedAt: Date(timeIntervalSince1970: 100), + author: .mock(id: "other-user") + ) + controller.reactions_simulated = [existingReaction] + + let viewModel = ReactionsDetailViewModel(message: message, reactionListController: controller) + viewModel.controller(controller, didChangeReactions: []) + + let messageController = ChatMessageControllerSUI_Mock.mock( + chatClient: chatClient, + currentUserId: currentUserId, + cid: cid, + messageId: message.id + ) + let currentUserReaction = ChatMessageReaction.mock( + id: "current-user-reaction", + type: like, + updatedAt: Date(timeIntervalSince1970: 200), + author: .mock(id: currentUserId, name: "You") + ) + let updatedMessage = ChatMessage.mock( + id: message.id, + cid: cid, + reactionScores: [like: 1, love: 1], + reactionCounts: [like: 1, love: 1], + currentUserReactions: [currentUserReaction] + ) + messageController.message_mock = updatedMessage + + // When + viewModel.messageController(messageController, didChangeMessage: .update(updatedMessage)) + + // Then + XCTAssertEqual(viewModel.reactions.map(\.id), ["current-user-reaction", "existing"]) + } + + func test_messageControllerDidChangeMessage_thenCurrentUserReactionIsRemovedImmediately() { + // Given + let cid = ChannelId.unique + let like = MessageReactionType(rawValue: "like") + let love = MessageReactionType(rawValue: "love") + let message = ChatMessage.mock(cid: cid) + let controller = makeReactionListController(messageId: message.id) + let currentUserReaction = ChatMessageReaction.mock( + id: "current-user-reaction", + type: like, + updatedAt: Date(timeIntervalSince1970: 200), + author: .mock(id: currentUserId, name: "You") + ) + let existingReaction = ChatMessageReaction.mock( + id: "existing", + type: love, + updatedAt: Date(timeIntervalSince1970: 100), + author: .mock(id: "other-user") + ) + controller.reactions_simulated = [currentUserReaction, existingReaction] + + let viewModel = ReactionsDetailViewModel(message: message, reactionListController: controller) + viewModel.controller(controller, didChangeReactions: []) + + let messageController = ChatMessageControllerSUI_Mock.mock( + chatClient: chatClient, + currentUserId: currentUserId, + cid: cid, + messageId: message.id + ) + let updatedMessage = ChatMessage.mock( + id: message.id, + cid: cid, + reactionScores: [love: 1], + reactionCounts: [love: 1], + currentUserReactions: [] + ) + messageController.message_mock = updatedMessage + + // When + viewModel.messageController(messageController, didChangeMessage: .update(updatedMessage)) + + // Then + XCTAssertEqual(viewModel.reactions.map(\.id), ["existing"]) + } + func test_messageControllerDidChangeReactions_thenReactionsUpdated() { // Given let cid = ChannelId.unique diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ReactionsOverlayView_Tests.swift b/StreamChatSwiftUITests/Tests/ChatChannel/ReactionsOverlayView_Tests.swift index 0fda4bd20..002d5e921 100644 --- a/StreamChatSwiftUITests/Tests/ChatChannel/ReactionsOverlayView_Tests.swift +++ b/StreamChatSwiftUITests/Tests/ChatChannel/ReactionsOverlayView_Tests.swift @@ -222,12 +222,76 @@ import XCTest onBackgroundTap: {}, onActionExecuted: { _ in } ) - .environment(\.messageViewModel, MessageViewModel(message: testMessage, channel: channel)) } // Then assertSnapshot(matching: view, as: .image(perceptualPrecision: precision)) } + + func test_reactionsOverlayView_allAnnotations() { + // Given + let currentUserId = StreamChatTestCase.currentUserId + streamChat = StreamChat(chatClient: chatClient, utils: Utils( + messageListConfig: .init(messageDisplayOptions: MessageDisplayOptions(showOriginalTranslatedButton: true)) + )) + + let config = ChannelConfig( + reactionsEnabled: true, + readEventsEnabled: true, + messageRemindersEnabled: true + ) + let channel = ChatChannel.mock( + cid: .unique, + config: config, + ownCapabilities: [.sendMessage, .uploadFile, .readEvents], + membership: .mock(id: "test", language: .portuguese) + ) + + let readUser = ChatUser.mock(id: .unique, name: "reader") + let testMessage = ChatMessage.mock( + id: "test", + cid: channel.cid, + text: "Hey, did you get a chance to look at the venue options?", + author: .mock(id: currentUserId, name: "martin"), + parentMessageId: .unique, + showReplyInChannel: true, + replyCount: 3, + translations: [.portuguese: "Olá, conseguiu ver as opções de local?"], + threadParticipants: [.mock(id: .unique, name: "alice")], + isSentByCurrentUser: true, + pinDetails: MessagePinDetails( + pinnedAt: Date(), + pinnedBy: .mock(id: currentUserId, name: "martin"), + expiresAt: nil + ), + readBy: [readUser], + reminder: MessageReminderInfo( + remindAt: Date().addingTimeInterval(3600), + createdAt: Date(), + updatedAt: Date() + ) + ) + let messageDisplayInfo = MessageDisplayInfo( + message: testMessage, + frame: CGRect(x: 0, y: 650, width: defaultScreenSize.width, height: 200), + contentWidth: 240, + isFirst: true + ) + + let view = OverlayHostView { + ReactionsOverlayView( + factory: DefaultViewFactory.shared, + channel: channel, + currentSnapshot: self.overlayImage, + messageDisplayInfo: messageDisplayInfo, + onBackgroundTap: {}, + onActionExecuted: { _ in } + ) + } + + // Then + AssertSnapshot(view, variants: .onlyUserInterfaceStyles, size: defaultScreenSize) + } } private struct OverlayHostView: View { diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/Suggestions/UserSuggestionsView_Tests.swift b/StreamChatSwiftUITests/Tests/ChatChannel/Suggestions/UserSuggestionsView_Tests.swift index 7c5076808..9f08c279d 100644 --- a/StreamChatSwiftUITests/Tests/ChatChannel/Suggestions/UserSuggestionsView_Tests.swift +++ b/StreamChatSwiftUITests/Tests/ChatChannel/Suggestions/UserSuggestionsView_Tests.swift @@ -27,7 +27,7 @@ final class UserSuggestionsView_Tests: StreamChatTestCase { messageController: nil, quotedMessage: .constant(nil), editedMessage: .constant(nil), - onMessageSent: {} + willSendMessage: {} ) .frame(width: defaultScreenSize.width, height: 200) diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/Suggestions/__Snapshots__/CommandSuggestionsView_Tests/test_commandSuggestionView_snapshot.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/Suggestions/__Snapshots__/CommandSuggestionsView_Tests/test_commandSuggestionView_snapshot.1.png index 304d6db5d..1d15ce042 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/Suggestions/__Snapshots__/CommandSuggestionsView_Tests/test_commandSuggestionView_snapshot.1.png and b/StreamChatSwiftUITests/Tests/ChatChannel/Suggestions/__Snapshots__/CommandSuggestionsView_Tests/test_commandSuggestionView_snapshot.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/Suggestions/__Snapshots__/CommandSuggestionsView_Tests/test_commandSuggestionsContainerView_liquidGlassStyle.default-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/Suggestions/__Snapshots__/CommandSuggestionsView_Tests/test_commandSuggestionsContainerView_liquidGlassStyle.default-dark.png index 29cd1966b..509f2ac05 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/Suggestions/__Snapshots__/CommandSuggestionsView_Tests/test_commandSuggestionsContainerView_liquidGlassStyle.default-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/Suggestions/__Snapshots__/CommandSuggestionsView_Tests/test_commandSuggestionsContainerView_liquidGlassStyle.default-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/Suggestions/__Snapshots__/CommandSuggestionsView_Tests/test_commandSuggestionsContainerView_liquidGlassStyle.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/Suggestions/__Snapshots__/CommandSuggestionsView_Tests/test_commandSuggestionsContainerView_liquidGlassStyle.default-light.png index c1029964a..6d42ddc1f 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/Suggestions/__Snapshots__/CommandSuggestionsView_Tests/test_commandSuggestionsContainerView_liquidGlassStyle.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/Suggestions/__Snapshots__/CommandSuggestionsView_Tests/test_commandSuggestionsContainerView_liquidGlassStyle.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/Suggestions/__Snapshots__/CommandSuggestionsView_Tests/test_commandSuggestionsContainerView_regularStyle.default-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/Suggestions/__Snapshots__/CommandSuggestionsView_Tests/test_commandSuggestionsContainerView_regularStyle.default-dark.png index 95bbeb34f..68574652b 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/Suggestions/__Snapshots__/CommandSuggestionsView_Tests/test_commandSuggestionsContainerView_regularStyle.default-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/Suggestions/__Snapshots__/CommandSuggestionsView_Tests/test_commandSuggestionsContainerView_regularStyle.default-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/Suggestions/__Snapshots__/CommandSuggestionsView_Tests/test_commandSuggestionsContainerView_regularStyle.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/Suggestions/__Snapshots__/CommandSuggestionsView_Tests/test_commandSuggestionsContainerView_regularStyle.default-light.png index 5f73c8b00..98f665603 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/Suggestions/__Snapshots__/CommandSuggestionsView_Tests/test_commandSuggestionsContainerView_regularStyle.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/Suggestions/__Snapshots__/CommandSuggestionsView_Tests/test_commandSuggestionsContainerView_regularStyle.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/Suggestions/__Snapshots__/UserSuggestionsView_Tests/test_messageComposerView_emptyMentions.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/Suggestions/__Snapshots__/UserSuggestionsView_Tests/test_messageComposerView_emptyMentions.default-light.png index 35a465762..5a73536ae 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/Suggestions/__Snapshots__/UserSuggestionsView_Tests/test_messageComposerView_emptyMentions.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/Suggestions/__Snapshots__/UserSuggestionsView_Tests/test_messageComposerView_emptyMentions.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/Suggestions/__Snapshots__/UserSuggestionsView_Tests/test_userSuggestionsView_liquidGlassStyle.default-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/Suggestions/__Snapshots__/UserSuggestionsView_Tests/test_userSuggestionsView_liquidGlassStyle.default-dark.png index 0472f8fa3..fbeafde15 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/Suggestions/__Snapshots__/UserSuggestionsView_Tests/test_userSuggestionsView_liquidGlassStyle.default-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/Suggestions/__Snapshots__/UserSuggestionsView_Tests/test_userSuggestionsView_liquidGlassStyle.default-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/Suggestions/__Snapshots__/UserSuggestionsView_Tests/test_userSuggestionsView_liquidGlassStyle.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/Suggestions/__Snapshots__/UserSuggestionsView_Tests/test_userSuggestionsView_liquidGlassStyle.default-light.png index 67f3e35fa..d9ee873ad 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/Suggestions/__Snapshots__/UserSuggestionsView_Tests/test_userSuggestionsView_liquidGlassStyle.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/Suggestions/__Snapshots__/UserSuggestionsView_Tests/test_userSuggestionsView_liquidGlassStyle.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/Suggestions/__Snapshots__/UserSuggestionsView_Tests/test_userSuggestionsView_regularStyle.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/Suggestions/__Snapshots__/UserSuggestionsView_Tests/test_userSuggestionsView_regularStyle.default-light.png index f590a77e1..59a60f20e 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/Suggestions/__Snapshots__/UserSuggestionsView_Tests/test_userSuggestionsView_regularStyle.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/Suggestions/__Snapshots__/UserSuggestionsView_Tests/test_userSuggestionsView_regularStyle.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/Suggestions/__Snapshots__/UserSuggestionsView_Tests/test_userSuggestionsView_regularStyle.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/Suggestions/__Snapshots__/UserSuggestionsView_Tests/test_userSuggestionsView_regularStyle.extraExtraExtraLarge-light.png index 8b549e38f..079bcb3da 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/Suggestions/__Snapshots__/UserSuggestionsView_Tests/test_userSuggestionsView_regularStyle.extraExtraExtraLarge-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/Suggestions/__Snapshots__/UserSuggestionsView_Tests/test_userSuggestionsView_regularStyle.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/Suggestions/__Snapshots__/UserSuggestionsView_Tests/test_userSuggestionsView_regularStyle.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannel/Suggestions/__Snapshots__/UserSuggestionsView_Tests/test_userSuggestionsView_regularStyle.rightToLeftLayout-default.png index d561c5d2b..fdde2cf3e 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/Suggestions/__Snapshots__/UserSuggestionsView_Tests/test_userSuggestionsView_regularStyle.rightToLeftLayout-default.png and b/StreamChatSwiftUITests/Tests/ChatChannel/Suggestions/__Snapshots__/UserSuggestionsView_Tests/test_userSuggestionsView_regularStyle.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/Suggestions/__Snapshots__/UserSuggestionsView_Tests/test_userSuggestionsView_regularStyle.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/Suggestions/__Snapshots__/UserSuggestionsView_Tests/test_userSuggestionsView_regularStyle.small-dark.png index cdedbdd68..90081e3c2 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/Suggestions/__Snapshots__/UserSuggestionsView_Tests/test_userSuggestionsView_regularStyle.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/Suggestions/__Snapshots__/UserSuggestionsView_Tests/test_userSuggestionsView_regularStyle.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/VoiceRecordingHandler_Tests.swift b/StreamChatSwiftUITests/Tests/ChatChannel/VoiceRecordingHandler_Tests.swift new file mode 100644 index 000000000..291bc5e1b --- /dev/null +++ b/StreamChatSwiftUITests/Tests/ChatChannel/VoiceRecordingHandler_Tests.swift @@ -0,0 +1,321 @@ +// +// Copyright © 2026 Stream.io Inc. All rights reserved. +// + +@testable import StreamChat +@testable import StreamChatSwiftUI +@testable import StreamChatTestTools +import XCTest + +@MainActor +final class VoiceRecordingHandler_Tests: StreamChatTestCase { + private lazy var mockPlayer: MockAudioPlayer! = .init() + private lazy var handler: VoiceRecordingHandler! = .init() + private let url = URL(fileURLWithPath: "/tmp/voice.aac") + private let duration: TimeInterval = 30 + + override func setUp() { + super.setUp() + mockPlayer = MockAudioPlayer() + streamChat?.utils._audioPlayer = mockPlayer + handler = VoiceRecordingHandler() + } + + override func tearDown() { + handler = nil + mockPlayer = nil + super.tearDown() + } + + // MARK: - displayedTime(for:duration:) + + func test_displayedTime_whenNotActive_returnsTotalDuration() { + let result = handler.displayedTime(for: url, duration: duration) + + XCTAssertEqual(result, duration) + } + + func test_displayedTime_whenPlaying_returnsRemainingTime() { + handler.context = makeContext(currentTime: 10, state: .playing) + + let result = handler.displayedTime(for: url, duration: duration) + + XCTAssertEqual(result, 20, accuracy: 0.001) + } + + func test_displayedTime_whenPaused_returnsRemainingTime() { + handler.context = makeContext(currentTime: 25, state: .paused) + + let result = handler.displayedTime(for: url, duration: duration) + + XCTAssertEqual(result, 5, accuracy: 0.001) + } + + func test_displayedTime_whenPausedAtStart_returnsFullDuration() { + handler.context = makeContext(currentTime: 0, state: .paused) + + let result = handler.displayedTime(for: url, duration: duration) + + XCTAssertEqual(result, duration, accuracy: 0.001) + } + + func test_displayedTime_whenStopped_returnsTotalDuration() { + handler.context = makeContext(currentTime: 0, state: .stopped) + + let result = handler.displayedTime(for: url, duration: duration) + + XCTAssertEqual(result, duration) + } + + func test_displayedTime_whenPlayerDurationExceedsRecordingDuration_usesPlayerDuration() { + let playerDuration: TimeInterval = 32 + handler.context = makeContext(duration: playerDuration, currentTime: 10, state: .playing) + + let result = handler.displayedTime(for: url, duration: duration) + + XCTAssertEqual(result, playerDuration - 10, accuracy: 0.001) + } + + func test_displayedTime_clampsToZero_whenCurrentTimeExceedsDuration() { + handler.context = makeContext(currentTime: 35, state: .playing) + + let result = handler.displayedTime(for: url, duration: duration) + + XCTAssertEqual(result, 0) + } + + func test_displayedTime_whenActiveForDifferentURL_returnsTotalDuration() { + let otherURL = URL(fileURLWithPath: "/tmp/other.aac") + handler.context = AudioPlaybackContext( + assetLocation: otherURL, + duration: 60, + currentTime: 20, + state: .playing, + rate: .normal, + isSeeking: false + ) + + let result = handler.displayedTime(for: url, duration: duration) + + XCTAssertEqual(result, duration) + } + + // MARK: - updatePlaybackState(for:) + + func test_updatePlaybackState_whenPlaying_setsIsPlayingTrue() { + handler.context = makeContext(state: .playing) + + handler.updatePlaybackState(for: url) + + XCTAssertTrue(handler.isPlaying) + } + + func test_updatePlaybackState_whenPlaying_appliesHandlerRate() { + handler.rate = .double + handler.context = makeContext(state: .playing) + + handler.updatePlaybackState(for: url) + + XCTAssertEqual(mockPlayer.updateRateWasCalledWithRate, .double) + } + + func test_updatePlaybackState_whenPlaying_appliesDefaultRate() { + handler.rate = .normal + handler.context = makeContext(state: .playing) + + handler.updatePlaybackState(for: url) + + XCTAssertEqual(mockPlayer.updateRateWasCalledWithRate, .normal) + } + + func test_updatePlaybackState_whenAlreadyPlaying_doesNotReapplyRate() { + handler.isPlaying = true + handler.rate = .double + handler.context = makeContext(state: .playing) + + handler.updatePlaybackState(for: url) + + XCTAssertNil(mockPlayer.updateRateWasCalledWithRate) + } + + func test_updatePlaybackState_whenPaused_setsIsPlayingFalse() { + handler.isPlaying = true + handler.context = makeContext(state: .paused) + + handler.updatePlaybackState(for: url) + + XCTAssertFalse(handler.isPlaying) + } + + func test_updatePlaybackState_whenStopped_setsIsPlayingFalse() { + handler.isPlaying = true + handler.context = makeContext(state: .stopped) + + handler.updatePlaybackState(for: url) + + XCTAssertFalse(handler.isPlaying) + } + + func test_updatePlaybackState_whenDifferentURL_doesNotUpdate() { + handler.isPlaying = true + handler.context = AudioPlaybackContext( + assetLocation: URL(fileURLWithPath: "/tmp/other.aac"), + duration: 10, + currentTime: 0, + state: .stopped, + rate: .zero, + isSeeking: false + ) + + handler.updatePlaybackState(for: url) + + XCTAssertTrue(handler.isPlaying) + } + + // MARK: - togglePlayback(for:) + + func test_togglePlayback_whenPlaying_pausesPlayer() { + handler.isPlaying = true + + handler.togglePlayback(for: url) + + XCTAssertTrue(mockPlayer.pauseWasCalled) + XCTAssertNil(mockPlayer.loadAssetWasCalledWithURL) + } + + func test_togglePlayback_whenNotPlaying_loadsAssetWithoutApplyingRate() { + handler.isPlaying = false + handler.rate = .double + + handler.togglePlayback(for: url) + + XCTAssertEqual(mockPlayer.loadAssetWasCalledWithURL, url) + XCTAssertNil(mockPlayer.updateRateWasCalledWithRate) + } + + // MARK: - cycleRate() + + func test_cycleRate_fromNormal_setsDouble() { + handler.rate = .normal + handler.isPlaying = true + + handler.cycleRate() + + XCTAssertEqual(handler.rate, .double) + XCTAssertEqual(mockPlayer.updateRateWasCalledWithRate, .double) + } + + func test_cycleRate_fromDouble_setsHalf() { + handler.rate = .double + handler.isPlaying = true + + handler.cycleRate() + + XCTAssertEqual(handler.rate, .half) + XCTAssertEqual(mockPlayer.updateRateWasCalledWithRate, .half) + } + + func test_cycleRate_fromHalf_setsNormal() { + handler.rate = .half + handler.isPlaying = true + + handler.cycleRate() + + XCTAssertEqual(handler.rate, .normal) + XCTAssertEqual(mockPlayer.updateRateWasCalledWithRate, .normal) + } + + func test_cycleRate_whenNotPlaying_updatesRateWithoutCallingPlayer() { + handler.rate = .normal + handler.isPlaying = false + + handler.cycleRate() + + XCTAssertEqual(handler.rate, .double) + XCTAssertNil(mockPlayer.updateRateWasCalledWithRate) + } + + func test_cycleRate_whenNotPlaying_fullCycleDoesNotCallPlayer() { + handler.isPlaying = false + handler.rate = .normal + + handler.cycleRate() + XCTAssertEqual(handler.rate, .double) + + handler.cycleRate() + XCTAssertEqual(handler.rate, .half) + + handler.cycleRate() + XCTAssertEqual(handler.rate, .normal) + + XCTAssertNil(mockPlayer.updateRateWasCalledWithRate) + } + + // MARK: - rateTitle + + func test_rateTitle_normal() { + handler.rate = .normal + XCTAssertEqual(handler.rateTitle, "x1") + } + + func test_rateTitle_double() { + handler.rate = .double + XCTAssertEqual(handler.rateTitle, "x2") + } + + func test_rateTitle_half() { + handler.rate = .half + XCTAssertEqual(handler.rateTitle, "x0.5") + } + + // MARK: - isActive(for:) + + func test_isActive_whenURLMatches_returnsTrue() { + handler.context = makeContext(state: .playing) + + XCTAssertTrue(handler.isActive(for: url)) + } + + func test_isActive_whenURLDiffers_returnsFalse() { + handler.context = makeContext(state: .playing) + + XCTAssertFalse(handler.isActive(for: URL(fileURLWithPath: "/tmp/other.aac"))) + } + + // MARK: - seek(to:loadingFrom:) + + func test_seek_whenAlreadyActive_seeksWithoutLoading() { + handler.context = makeContext(state: .playing) + + handler.seek(to: 10) + + XCTAssertEqual(mockPlayer.seekWasCalledWithTime, 10) + XCTAssertNil(mockPlayer.loadAssetWasCalledWithURL) + } + + func test_seek_whenNotActive_loadsAssetAndSeeks() { + let newURL = URL(fileURLWithPath: "/tmp/new.aac") + + handler.seek(to: 5, loadingFrom: newURL) + + XCTAssertEqual(mockPlayer.loadAssetWasCalledWithURL, newURL) + XCTAssertEqual(mockPlayer.seekWasCalledWithTime, 5) + } + + // MARK: - Helpers + + private func makeContext( + duration: TimeInterval? = nil, + currentTime: TimeInterval = 0, + state: AudioPlaybackState + ) -> AudioPlaybackContext { + AudioPlaybackContext( + assetLocation: url, + duration: duration ?? self.duration, + currentTime: currentTime, + state: state, + rate: state == .playing ? .normal : .zero, + isSeeking: false + ) + } +} diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/AttachmentCommandsPickerView_Tests/test_attachmentCommandsPickerView_snapshot.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/AttachmentCommandsPickerView_Tests/test_attachmentCommandsPickerView_snapshot.default-light.png index 1396d5ed8..12efc48fc 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/AttachmentCommandsPickerView_Tests/test_attachmentCommandsPickerView_snapshot.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/AttachmentCommandsPickerView_Tests/test_attachmentCommandsPickerView_snapshot.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/AttachmentCommandsPickerView_Tests/test_attachmentCommandsPickerView_snapshot.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/AttachmentCommandsPickerView_Tests/test_attachmentCommandsPickerView_snapshot.extraExtraExtraLarge-light.png index cd4e8fe58..529882292 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/AttachmentCommandsPickerView_Tests/test_attachmentCommandsPickerView_snapshot.extraExtraExtraLarge-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/AttachmentCommandsPickerView_Tests/test_attachmentCommandsPickerView_snapshot.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/AttachmentCommandsPickerView_Tests/test_attachmentCommandsPickerView_snapshot.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/AttachmentCommandsPickerView_Tests/test_attachmentCommandsPickerView_snapshot.rightToLeftLayout-default.png index f544aed1f..723cf1c32 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/AttachmentCommandsPickerView_Tests/test_attachmentCommandsPickerView_snapshot.rightToLeftLayout-default.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/AttachmentCommandsPickerView_Tests/test_attachmentCommandsPickerView_snapshot.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/AttachmentCommandsPickerView_Tests/test_attachmentCommandsPickerView_snapshot.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/AttachmentCommandsPickerView_Tests/test_attachmentCommandsPickerView_snapshot.small-dark.png index b0c031e02..5c26b318b 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/AttachmentCommandsPickerView_Tests/test_attachmentCommandsPickerView_snapshot.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/AttachmentCommandsPickerView_Tests/test_attachmentCommandsPickerView_snapshot.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ChatChannelHeader_Tests/test_channelTitleView_snapshot.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ChatChannelHeader_Tests/test_channelTitleView_snapshot.1.png index 7c7d9d0e5..160dc0790 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ChatChannelHeader_Tests/test_channelTitleView_snapshot.1.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ChatChannelHeader_Tests/test_channelTitleView_snapshot.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ChatChannelHeader_Tests/test_channelTitleView_theme_snapshot.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ChatChannelHeader_Tests/test_channelTitleView_theme_snapshot.1.png index ac8400ed3..2c5781151 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ChatChannelHeader_Tests/test_channelTitleView_theme_snapshot.1.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ChatChannelHeader_Tests/test_channelTitleView_theme_snapshot.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ChatChannelHeader_Tests/test_chatChannelHeaderModifier_channelAvatarUpdated.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ChatChannelHeader_Tests/test_chatChannelHeaderModifier_channelAvatarUpdated.1.png index 6b0e7f617..8c19c4fdf 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ChatChannelHeader_Tests/test_chatChannelHeaderModifier_channelAvatarUpdated.1.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ChatChannelHeader_Tests/test_chatChannelHeaderModifier_channelAvatarUpdated.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ChatChannelHeader_Tests/test_chatChannelHeaderModifier_snapshot.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ChatChannelHeader_Tests/test_chatChannelHeaderModifier_snapshot.1.png index 30dcc81c4..a9406227b 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ChatChannelHeader_Tests/test_chatChannelHeaderModifier_snapshot.1.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ChatChannelHeader_Tests/test_chatChannelHeaderModifier_snapshot.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ChatChannelHeader_Tests/test_chatChannelHeader_snapshot.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ChatChannelHeader_Tests/test_chatChannelHeader_snapshot.1.png index 43f8cf591..c769f6d65 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ChatChannelHeader_Tests/test_chatChannelHeader_snapshot.1.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ChatChannelHeader_Tests/test_chatChannelHeader_snapshot.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ChatChannelViewDateOverlay_Tests/test_chatChannelView_snapshot.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ChatChannelViewDateOverlay_Tests/test_chatChannelView_snapshot.1.png deleted file mode 100644 index 1b1eaba06..000000000 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ChatChannelViewDateOverlay_Tests/test_chatChannelView_snapshot.1.png and /dev/null differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ChatChannelViewDateOverlay_Tests/test_chatChannelView_snapshot_messageListPlacement.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ChatChannelViewDateOverlay_Tests/test_chatChannelView_snapshot_messageListPlacement.1.png new file mode 100644 index 000000000..4adc59728 Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ChatChannelViewDateOverlay_Tests/test_chatChannelView_snapshot_messageListPlacement.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ChatChannelViewDateOverlay_Tests/test_chatChannelView_snapshot_overlayPlacement_dateIndicatorAppearsAtTop.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ChatChannelViewDateOverlay_Tests/test_chatChannelView_snapshot_overlayPlacement_dateIndicatorAppearsAtTop.1.png new file mode 100644 index 000000000..150d2e149 Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ChatChannelViewDateOverlay_Tests/test_chatChannelView_snapshot_overlayPlacement_dateIndicatorAppearsAtTop.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ChatChannelView_Tests/test_chatChannelView_liquidGlassStyle_composer_snapshot.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ChatChannelView_Tests/test_chatChannelView_liquidGlassStyle_composer_snapshot.1.png index 5dd05f049..bf4abce91 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ChatChannelView_Tests/test_chatChannelView_liquidGlassStyle_composer_snapshot.1.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ChatChannelView_Tests/test_chatChannelView_liquidGlassStyle_composer_snapshot.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ChatChannelView_Tests/test_chatChannelView_snapshot.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ChatChannelView_Tests/test_chatChannelView_snapshot.1.png index 4f8993a9d..41bb110e2 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ChatChannelView_Tests/test_chatChannelView_snapshot.1.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ChatChannelView_Tests/test_chatChannelView_snapshot.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ChatChannelView_Tests/test_chatChannelView_snapshotEmpty.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ChatChannelView_Tests/test_chatChannelView_snapshotEmpty.1.png index 3d7a1b9fb..de01bc88a 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ChatChannelView_Tests/test_chatChannelView_snapshotEmpty.1.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ChatChannelView_Tests/test_chatChannelView_snapshotEmpty.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ChatChannelView_Tests/test_chatChannelView_themedNavigationBar_snapshot.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ChatChannelView_Tests/test_chatChannelView_themedNavigationBar_snapshot.1.png index b176e16ae..d531ef902 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ChatChannelView_Tests/test_chatChannelView_themedNavigationBar_snapshot.1.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ChatChannelView_Tests/test_chatChannelView_themedNavigationBar_snapshot.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ChatChannelView_Tests/test_defaultChannelHeader_snapshot.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ChatChannelView_Tests/test_defaultChannelHeader_snapshot.1.png index 2983d56ca..89ef1137e 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ChatChannelView_Tests/test_defaultChannelHeader_snapshot.1.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ChatChannelView_Tests/test_defaultChannelHeader_snapshot.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ChatQuotedMessageView_Tests/test_chatQuotedMessageView_incoming.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ChatQuotedMessageView_Tests/test_chatQuotedMessageView_incoming.small-dark.png index 12fadea36..1a1caf584 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ChatQuotedMessageView_Tests/test_chatQuotedMessageView_incoming.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ChatQuotedMessageView_Tests/test_chatQuotedMessageView_incoming.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ChatQuotedMessageView_Tests/test_chatQuotedMessageView_outgoing.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ChatQuotedMessageView_Tests/test_chatQuotedMessageView_outgoing.small-dark.png index 368285c95..1815a9dfa 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ChatQuotedMessageView_Tests/test_chatQuotedMessageView_outgoing.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ChatQuotedMessageView_Tests/test_chatQuotedMessageView_outgoing.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ChatQuotedMessageView_Tests/test_chatQuotedMessageView_withAttachment.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ChatQuotedMessageView_Tests/test_chatQuotedMessageView_withAttachment.default-light.png index 536e67495..8d3f73774 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ChatQuotedMessageView_Tests/test_chatQuotedMessageView_withAttachment.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ChatQuotedMessageView_Tests/test_chatQuotedMessageView_withAttachment.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ChatQuotedMessageView_Tests/test_chatQuotedMessageView_withAttachment.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ChatQuotedMessageView_Tests/test_chatQuotedMessageView_withAttachment.extraExtraExtraLarge-light.png index 2ee1cded4..a3f83dbd9 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ChatQuotedMessageView_Tests/test_chatQuotedMessageView_withAttachment.extraExtraExtraLarge-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ChatQuotedMessageView_Tests/test_chatQuotedMessageView_withAttachment.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ChatQuotedMessageView_Tests/test_chatQuotedMessageView_withAttachment.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ChatQuotedMessageView_Tests/test_chatQuotedMessageView_withAttachment.rightToLeftLayout-default.png index 8fd17c756..ce3f0403f 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ChatQuotedMessageView_Tests/test_chatQuotedMessageView_withAttachment.rightToLeftLayout-default.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ChatQuotedMessageView_Tests/test_chatQuotedMessageView_withAttachment.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ChatQuotedMessageView_Tests/test_chatQuotedMessageView_withAttachment.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ChatQuotedMessageView_Tests/test_chatQuotedMessageView_withAttachment.small-dark.png index 301bf287d..ea8cbd941 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ChatQuotedMessageView_Tests/test_chatQuotedMessageView_withAttachment.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ChatQuotedMessageView_Tests/test_chatQuotedMessageView_withAttachment.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ComposerQuotedMessageView_Tests/test_composerQuotedMessageView_longText.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ComposerQuotedMessageView_Tests/test_composerQuotedMessageView_longText.default-light.png index cf5696b45..9b1774a8e 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ComposerQuotedMessageView_Tests/test_composerQuotedMessageView_longText.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ComposerQuotedMessageView_Tests/test_composerQuotedMessageView_longText.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ComposerQuotedMessageView_Tests/test_composerQuotedMessageView_longText.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ComposerQuotedMessageView_Tests/test_composerQuotedMessageView_longText.extraExtraExtraLarge-light.png index 728a7ebf4..6fa75f5c4 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ComposerQuotedMessageView_Tests/test_composerQuotedMessageView_longText.extraExtraExtraLarge-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ComposerQuotedMessageView_Tests/test_composerQuotedMessageView_longText.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ComposerQuotedMessageView_Tests/test_composerQuotedMessageView_longText.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ComposerQuotedMessageView_Tests/test_composerQuotedMessageView_longText.rightToLeftLayout-default.png index 9c738688e..593a2ee0b 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ComposerQuotedMessageView_Tests/test_composerQuotedMessageView_longText.rightToLeftLayout-default.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ComposerQuotedMessageView_Tests/test_composerQuotedMessageView_longText.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ComposerQuotedMessageView_Tests/test_composerQuotedMessageView_longText.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ComposerQuotedMessageView_Tests/test_composerQuotedMessageView_longText.small-dark.png index cf272996d..d85dd91fd 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ComposerQuotedMessageView_Tests/test_composerQuotedMessageView_longText.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ComposerQuotedMessageView_Tests/test_composerQuotedMessageView_longText.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ComposerQuotedMessageView_Tests/test_composerQuotedMessageView_outgoing.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ComposerQuotedMessageView_Tests/test_composerQuotedMessageView_outgoing.default-light.png index 67ad75e44..df1e71b02 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ComposerQuotedMessageView_Tests/test_composerQuotedMessageView_outgoing.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ComposerQuotedMessageView_Tests/test_composerQuotedMessageView_outgoing.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ComposerQuotedMessageView_Tests/test_composerQuotedMessageView_outgoing.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ComposerQuotedMessageView_Tests/test_composerQuotedMessageView_outgoing.extraExtraExtraLarge-light.png index 2f158eb83..086ab49de 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ComposerQuotedMessageView_Tests/test_composerQuotedMessageView_outgoing.extraExtraExtraLarge-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ComposerQuotedMessageView_Tests/test_composerQuotedMessageView_outgoing.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ComposerQuotedMessageView_Tests/test_composerQuotedMessageView_outgoing.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ComposerQuotedMessageView_Tests/test_composerQuotedMessageView_outgoing.rightToLeftLayout-default.png index ce93fff71..de5965448 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ComposerQuotedMessageView_Tests/test_composerQuotedMessageView_outgoing.rightToLeftLayout-default.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ComposerQuotedMessageView_Tests/test_composerQuotedMessageView_outgoing.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ComposerQuotedMessageView_Tests/test_composerQuotedMessageView_outgoing.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ComposerQuotedMessageView_Tests/test_composerQuotedMessageView_outgoing.small-dark.png index cfb7427dd..71914df4d 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ComposerQuotedMessageView_Tests/test_composerQuotedMessageView_outgoing.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ComposerQuotedMessageView_Tests/test_composerQuotedMessageView_outgoing.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ComposerQuotedMessageView_Tests/test_composerQuotedMessageView_withAttachmentAndDismissButton.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ComposerQuotedMessageView_Tests/test_composerQuotedMessageView_withAttachmentAndDismissButton.default-light.png index 85db2520b..7b4f6ee5c 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ComposerQuotedMessageView_Tests/test_composerQuotedMessageView_withAttachmentAndDismissButton.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ComposerQuotedMessageView_Tests/test_composerQuotedMessageView_withAttachmentAndDismissButton.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ComposerQuotedMessageView_Tests/test_composerQuotedMessageView_withAttachmentAndDismissButton.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ComposerQuotedMessageView_Tests/test_composerQuotedMessageView_withAttachmentAndDismissButton.extraExtraExtraLarge-light.png index 3d7ea3b98..4676966c9 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ComposerQuotedMessageView_Tests/test_composerQuotedMessageView_withAttachmentAndDismissButton.extraExtraExtraLarge-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ComposerQuotedMessageView_Tests/test_composerQuotedMessageView_withAttachmentAndDismissButton.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ComposerQuotedMessageView_Tests/test_composerQuotedMessageView_withAttachmentAndDismissButton.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ComposerQuotedMessageView_Tests/test_composerQuotedMessageView_withAttachmentAndDismissButton.rightToLeftLayout-default.png index 9e4abf25c..64dac410a 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ComposerQuotedMessageView_Tests/test_composerQuotedMessageView_withAttachmentAndDismissButton.rightToLeftLayout-default.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ComposerQuotedMessageView_Tests/test_composerQuotedMessageView_withAttachmentAndDismissButton.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ComposerQuotedMessageView_Tests/test_composerQuotedMessageView_withAttachmentAndDismissButton.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ComposerQuotedMessageView_Tests/test_composerQuotedMessageView_withAttachmentAndDismissButton.small-dark.png index 133a73e36..1fcd31391 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ComposerQuotedMessageView_Tests/test_composerQuotedMessageView_withAttachmentAndDismissButton.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ComposerQuotedMessageView_Tests/test_composerQuotedMessageView_withAttachmentAndDismissButton.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ComposerQuotedMessageView_Tests/test_composerQuotedMessageView_withDismissButton.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ComposerQuotedMessageView_Tests/test_composerQuotedMessageView_withDismissButton.default-light.png index 65d49de99..8116b314b 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ComposerQuotedMessageView_Tests/test_composerQuotedMessageView_withDismissButton.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ComposerQuotedMessageView_Tests/test_composerQuotedMessageView_withDismissButton.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ComposerQuotedMessageView_Tests/test_composerQuotedMessageView_withDismissButton.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ComposerQuotedMessageView_Tests/test_composerQuotedMessageView_withDismissButton.extraExtraExtraLarge-light.png index 48df18bb5..1c7c33f18 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ComposerQuotedMessageView_Tests/test_composerQuotedMessageView_withDismissButton.extraExtraExtraLarge-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ComposerQuotedMessageView_Tests/test_composerQuotedMessageView_withDismissButton.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ComposerQuotedMessageView_Tests/test_composerQuotedMessageView_withDismissButton.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ComposerQuotedMessageView_Tests/test_composerQuotedMessageView_withDismissButton.rightToLeftLayout-default.png index fbf1b5f80..c2e07011b 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ComposerQuotedMessageView_Tests/test_composerQuotedMessageView_withDismissButton.rightToLeftLayout-default.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ComposerQuotedMessageView_Tests/test_composerQuotedMessageView_withDismissButton.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ComposerQuotedMessageView_Tests/test_composerQuotedMessageView_withDismissButton.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ComposerQuotedMessageView_Tests/test_composerQuotedMessageView_withDismissButton.small-dark.png index 41d692287..a42354f17 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ComposerQuotedMessageView_Tests/test_composerQuotedMessageView_withDismissButton.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ComposerQuotedMessageView_Tests/test_composerQuotedMessageView_withDismissButton.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ComposerQuotedMessageView_Tests/test_composerQuotedMessageView_withFileAttachment.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ComposerQuotedMessageView_Tests/test_composerQuotedMessageView_withFileAttachment.default-light.png index f761cdc62..0c73fc4ed 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ComposerQuotedMessageView_Tests/test_composerQuotedMessageView_withFileAttachment.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ComposerQuotedMessageView_Tests/test_composerQuotedMessageView_withFileAttachment.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ComposerQuotedMessageView_Tests/test_composerQuotedMessageView_withFileAttachment.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ComposerQuotedMessageView_Tests/test_composerQuotedMessageView_withFileAttachment.extraExtraExtraLarge-light.png index 40559cee4..e20bbae60 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ComposerQuotedMessageView_Tests/test_composerQuotedMessageView_withFileAttachment.extraExtraExtraLarge-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ComposerQuotedMessageView_Tests/test_composerQuotedMessageView_withFileAttachment.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ComposerQuotedMessageView_Tests/test_composerQuotedMessageView_withFileAttachment.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ComposerQuotedMessageView_Tests/test_composerQuotedMessageView_withFileAttachment.rightToLeftLayout-default.png index 2e31be11e..8c6188c46 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ComposerQuotedMessageView_Tests/test_composerQuotedMessageView_withFileAttachment.rightToLeftLayout-default.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ComposerQuotedMessageView_Tests/test_composerQuotedMessageView_withFileAttachment.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ComposerQuotedMessageView_Tests/test_composerQuotedMessageView_withFileAttachment.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ComposerQuotedMessageView_Tests/test_composerQuotedMessageView_withFileAttachment.small-dark.png index bbe148b5b..87b1a007e 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ComposerQuotedMessageView_Tests/test_composerQuotedMessageView_withFileAttachment.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ComposerQuotedMessageView_Tests/test_composerQuotedMessageView_withFileAttachment.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ComposerQuotedMessageView_Tests/test_composerQuotedMessageView_withGiphyAttachment.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ComposerQuotedMessageView_Tests/test_composerQuotedMessageView_withGiphyAttachment.default-light.png new file mode 100644 index 000000000..ab21b2dd5 Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ComposerQuotedMessageView_Tests/test_composerQuotedMessageView_withGiphyAttachment.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ComposerQuotedMessageView_Tests/test_composerQuotedMessageView_withGiphyAttachment.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ComposerQuotedMessageView_Tests/test_composerQuotedMessageView_withGiphyAttachment.extraExtraExtraLarge-light.png new file mode 100644 index 000000000..d39efc57c Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ComposerQuotedMessageView_Tests/test_composerQuotedMessageView_withGiphyAttachment.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ComposerQuotedMessageView_Tests/test_composerQuotedMessageView_withGiphyAttachment.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ComposerQuotedMessageView_Tests/test_composerQuotedMessageView_withGiphyAttachment.rightToLeftLayout-default.png new file mode 100644 index 000000000..6efdfcbd0 Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ComposerQuotedMessageView_Tests/test_composerQuotedMessageView_withGiphyAttachment.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ComposerQuotedMessageView_Tests/test_composerQuotedMessageView_withGiphyAttachment.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ComposerQuotedMessageView_Tests/test_composerQuotedMessageView_withGiphyAttachment.small-dark.png new file mode 100644 index 000000000..a244dcd2f Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ComposerQuotedMessageView_Tests/test_composerQuotedMessageView_withGiphyAttachment.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ComposerVideoAttachmentView_Tests/test_composerVideoAttachmentView_durationFromExtraData.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ComposerVideoAttachmentView_Tests/test_composerVideoAttachmentView_durationFromExtraData.default-light.png index 82f9e3918..5aeb6d665 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ComposerVideoAttachmentView_Tests/test_composerVideoAttachmentView_durationFromExtraData.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ComposerVideoAttachmentView_Tests/test_composerVideoAttachmentView_durationFromExtraData.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ComposerVideoAttachmentView_Tests/test_composerVideoAttachmentView_durationFromProperty.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ComposerVideoAttachmentView_Tests/test_composerVideoAttachmentView_durationFromProperty.default-light.png index 5ad44a62c..5ce3b292c 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ComposerVideoAttachmentView_Tests/test_composerVideoAttachmentView_durationFromProperty.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ComposerVideoAttachmentView_Tests/test_composerVideoAttachmentView_durationFromProperty.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ComposerVideoAttachmentView_Tests/test_composerVideoAttachmentView_durationPropertyTakesPrecedence.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ComposerVideoAttachmentView_Tests/test_composerVideoAttachmentView_durationPropertyTakesPrecedence.default-light.png index 5a6f055ba..e01d56982 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ComposerVideoAttachmentView_Tests/test_composerVideoAttachmentView_durationPropertyTakesPrecedence.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ComposerVideoAttachmentView_Tests/test_composerVideoAttachmentView_durationPropertyTakesPrecedence.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ComposerVideoAttachmentView_Tests/test_composerVideoAttachmentView_noDuration.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ComposerVideoAttachmentView_Tests/test_composerVideoAttachmentView_noDuration.default-light.png index 216233340..ae0b23ced 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ComposerVideoAttachmentView_Tests/test_composerVideoAttachmentView_noDuration.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ComposerVideoAttachmentView_Tests/test_composerVideoAttachmentView_noDuration.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/CreatePollView_Tests/test_createPollView_allOptionsDisabledSnapshot.default-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/CreatePollView_Tests/test_createPollView_allOptionsDisabledSnapshot.default-dark.png index 480a35618..198beab67 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/CreatePollView_Tests/test_createPollView_allOptionsDisabledSnapshot.default-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/CreatePollView_Tests/test_createPollView_allOptionsDisabledSnapshot.default-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/CreatePollView_Tests/test_createPollView_allOptionsDisabledSnapshot.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/CreatePollView_Tests/test_createPollView_allOptionsDisabledSnapshot.default-light.png index 0bc281332..4c68a8ed5 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/CreatePollView_Tests/test_createPollView_allOptionsDisabledSnapshot.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/CreatePollView_Tests/test_createPollView_allOptionsDisabledSnapshot.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/CreatePollView_Tests/test_createPollView_allOptionsEnabledSnapshot.default-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/CreatePollView_Tests/test_createPollView_allOptionsEnabledSnapshot.default-dark.png index e09f2cfc2..9aef68b8b 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/CreatePollView_Tests/test_createPollView_allOptionsEnabledSnapshot.default-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/CreatePollView_Tests/test_createPollView_allOptionsEnabledSnapshot.default-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/CreatePollView_Tests/test_createPollView_allOptionsEnabledSnapshot.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/CreatePollView_Tests/test_createPollView_allOptionsEnabledSnapshot.default-light.png index c495df337..bc8c24bf6 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/CreatePollView_Tests/test_createPollView_allOptionsEnabledSnapshot.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/CreatePollView_Tests/test_createPollView_allOptionsEnabledSnapshot.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/CreatePollView_Tests/test_createPollView_duplicateOptionsSnapshot.default-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/CreatePollView_Tests/test_createPollView_duplicateOptionsSnapshot.default-dark.png index d5c719df2..c9db10ced 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/CreatePollView_Tests/test_createPollView_duplicateOptionsSnapshot.default-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/CreatePollView_Tests/test_createPollView_duplicateOptionsSnapshot.default-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/CreatePollView_Tests/test_createPollView_duplicateOptionsSnapshot.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/CreatePollView_Tests/test_createPollView_duplicateOptionsSnapshot.default-light.png index 7aab00513..dbc31dc7c 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/CreatePollView_Tests/test_createPollView_duplicateOptionsSnapshot.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/CreatePollView_Tests/test_createPollView_duplicateOptionsSnapshot.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/CreatePollView_Tests/test_createPollView_filledQuestionAndOptionsSnapshot.default-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/CreatePollView_Tests/test_createPollView_filledQuestionAndOptionsSnapshot.default-dark.png index c33a7b1bc..537fe5df4 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/CreatePollView_Tests/test_createPollView_filledQuestionAndOptionsSnapshot.default-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/CreatePollView_Tests/test_createPollView_filledQuestionAndOptionsSnapshot.default-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/CreatePollView_Tests/test_createPollView_filledQuestionAndOptionsSnapshot.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/CreatePollView_Tests/test_createPollView_filledQuestionAndOptionsSnapshot.default-light.png index 4f207b452..bcf35460a 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/CreatePollView_Tests/test_createPollView_filledQuestionAndOptionsSnapshot.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/CreatePollView_Tests/test_createPollView_filledQuestionAndOptionsSnapshot.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/CreatePollView_Tests/test_createPollView_manyOptionsSnapshot.default-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/CreatePollView_Tests/test_createPollView_manyOptionsSnapshot.default-dark.png index 56966df3a..616970d87 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/CreatePollView_Tests/test_createPollView_manyOptionsSnapshot.default-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/CreatePollView_Tests/test_createPollView_manyOptionsSnapshot.default-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/CreatePollView_Tests/test_createPollView_manyOptionsSnapshot.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/CreatePollView_Tests/test_createPollView_manyOptionsSnapshot.default-light.png index 58b997799..318d861f3 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/CreatePollView_Tests/test_createPollView_manyOptionsSnapshot.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/CreatePollView_Tests/test_createPollView_manyOptionsSnapshot.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/CreatePollView_Tests/test_createPollView_mixedOptionsSnapshot.default-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/CreatePollView_Tests/test_createPollView_mixedOptionsSnapshot.default-dark.png index 2b782109d..f00b6dece 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/CreatePollView_Tests/test_createPollView_mixedOptionsSnapshot.default-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/CreatePollView_Tests/test_createPollView_mixedOptionsSnapshot.default-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/CreatePollView_Tests/test_createPollView_mixedOptionsSnapshot.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/CreatePollView_Tests/test_createPollView_mixedOptionsSnapshot.default-light.png index cc1ed2ce3..70616bbc9 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/CreatePollView_Tests/test_createPollView_mixedOptionsSnapshot.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/CreatePollView_Tests/test_createPollView_mixedOptionsSnapshot.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/CreatePollView_Tests/test_createPollView_multipleVotesWithoutMaxVotesSnapshot.default-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/CreatePollView_Tests/test_createPollView_multipleVotesWithoutMaxVotesSnapshot.default-dark.png index 93495f88d..c3a247023 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/CreatePollView_Tests/test_createPollView_multipleVotesWithoutMaxVotesSnapshot.default-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/CreatePollView_Tests/test_createPollView_multipleVotesWithoutMaxVotesSnapshot.default-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/CreatePollView_Tests/test_createPollView_multipleVotesWithoutMaxVotesSnapshot.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/CreatePollView_Tests/test_createPollView_multipleVotesWithoutMaxVotesSnapshot.default-light.png index 0f57e1653..b0e0e5d43 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/CreatePollView_Tests/test_createPollView_multipleVotesWithoutMaxVotesSnapshot.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/CreatePollView_Tests/test_createPollView_multipleVotesWithoutMaxVotesSnapshot.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/CreatePollView_Tests/test_createPollView_snapshot.default-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/CreatePollView_Tests/test_createPollView_snapshot.default-dark.png index 86a4d7c3b..0c14a7343 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/CreatePollView_Tests/test_createPollView_snapshot.default-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/CreatePollView_Tests/test_createPollView_snapshot.default-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/CreatePollView_Tests/test_createPollView_snapshot.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/CreatePollView_Tests/test_createPollView_snapshot.default-light.png index 9aa58e754..e0f110747 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/CreatePollView_Tests/test_createPollView_snapshot.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/CreatePollView_Tests/test_createPollView_snapshot.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/EditedMessageView_Tests/test_editedMessageView_fileSingleNoCaption.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/EditedMessageView_Tests/test_editedMessageView_fileSingleNoCaption.default-light.png index 7935040dd..74bc935f5 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/EditedMessageView_Tests/test_editedMessageView_fileSingleNoCaption.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/EditedMessageView_Tests/test_editedMessageView_fileSingleNoCaption.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/EditedMessageView_Tests/test_editedMessageView_link.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/EditedMessageView_Tests/test_editedMessageView_link.default-light.png index 884bf948a..6f80c032d 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/EditedMessageView_Tests/test_editedMessageView_link.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/EditedMessageView_Tests/test_editedMessageView_link.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/EditedMessageView_Tests/test_editedMessageView_mixedContentNoCaption.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/EditedMessageView_Tests/test_editedMessageView_mixedContentNoCaption.default-light.png index fa808ec59..f3a3d83ed 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/EditedMessageView_Tests/test_editedMessageView_mixedContentNoCaption.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/EditedMessageView_Tests/test_editedMessageView_mixedContentNoCaption.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/EditedMessageView_Tests/test_editedMessageView_photoMultipleCaption.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/EditedMessageView_Tests/test_editedMessageView_photoMultipleCaption.default-light.png index e654ec541..1f000beed 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/EditedMessageView_Tests/test_editedMessageView_photoMultipleCaption.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/EditedMessageView_Tests/test_editedMessageView_photoMultipleCaption.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/EditedMessageView_Tests/test_editedMessageView_photoMultipleNoCaption.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/EditedMessageView_Tests/test_editedMessageView_photoMultipleNoCaption.default-light.png index 507e6307f..448937b8c 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/EditedMessageView_Tests/test_editedMessageView_photoMultipleNoCaption.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/EditedMessageView_Tests/test_editedMessageView_photoMultipleNoCaption.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/EditedMessageView_Tests/test_editedMessageView_photoSingleNoCaption.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/EditedMessageView_Tests/test_editedMessageView_photoSingleNoCaption.default-light.png index f04037042..e5b71f721 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/EditedMessageView_Tests/test_editedMessageView_photoSingleNoCaption.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/EditedMessageView_Tests/test_editedMessageView_photoSingleNoCaption.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/EditedMessageView_Tests/test_editedMessageView_photoSingleWithCaption.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/EditedMessageView_Tests/test_editedMessageView_photoSingleWithCaption.default-light.png index 01c386276..c9dfd5023 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/EditedMessageView_Tests/test_editedMessageView_photoSingleWithCaption.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/EditedMessageView_Tests/test_editedMessageView_photoSingleWithCaption.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/EditedMessageView_Tests/test_editedMessageView_poll.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/EditedMessageView_Tests/test_editedMessageView_poll.default-light.png index 6b7a17458..0eb8e308d 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/EditedMessageView_Tests/test_editedMessageView_poll.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/EditedMessageView_Tests/test_editedMessageView_poll.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/EditedMessageView_Tests/test_editedMessageView_textLong.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/EditedMessageView_Tests/test_editedMessageView_textLong.default-light.png index 386843441..a0e29b11d 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/EditedMessageView_Tests/test_editedMessageView_textLong.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/EditedMessageView_Tests/test_editedMessageView_textLong.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/EditedMessageView_Tests/test_editedMessageView_textShort.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/EditedMessageView_Tests/test_editedMessageView_textShort.default-light.png index ee98d1dec..82fab80dc 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/EditedMessageView_Tests/test_editedMessageView_textShort.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/EditedMessageView_Tests/test_editedMessageView_textShort.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/EditedMessageView_Tests/test_editedMessageView_videoMultipleNoCaption.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/EditedMessageView_Tests/test_editedMessageView_videoMultipleNoCaption.default-light.png index c644d369c..0b0d3f998 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/EditedMessageView_Tests/test_editedMessageView_videoMultipleNoCaption.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/EditedMessageView_Tests/test_editedMessageView_videoMultipleNoCaption.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/EditedMessageView_Tests/test_editedMessageView_videoSingleNoCaption.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/EditedMessageView_Tests/test_editedMessageView_videoSingleNoCaption.default-light.png index cd10851cd..c0f606c5f 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/EditedMessageView_Tests/test_editedMessageView_videoSingleNoCaption.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/EditedMessageView_Tests/test_editedMessageView_videoSingleNoCaption.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/EditedMessageView_Tests/test_editedMessageView_voiceMessageNoCaption.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/EditedMessageView_Tests/test_editedMessageView_voiceMessageNoCaption.default-light.png index 1ab1d203c..b47425455 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/EditedMessageView_Tests/test_editedMessageView_voiceMessageNoCaption.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/EditedMessageView_Tests/test_editedMessageView_voiceMessageNoCaption.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/FileAttachmentView_Tests/test_fileAttachmentView_downloadButton.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/FileAttachmentView_Tests/test_fileAttachmentView_downloadButton.1.png deleted file mode 100644 index 54c6b8096..000000000 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/FileAttachmentView_Tests/test_fileAttachmentView_downloadButton.1.png and /dev/null differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/FileAttachmentView_Tests/test_fileAttachmentView_downloadDisabled.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/FileAttachmentView_Tests/test_fileAttachmentView_downloadDisabled.1.png deleted file mode 100644 index 929afd4a0..000000000 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/FileAttachmentView_Tests/test_fileAttachmentView_downloadDisabled.1.png and /dev/null differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/FileAttachmentView_Tests/test_fileAttachmentView_downloadFailedState.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/FileAttachmentView_Tests/test_fileAttachmentView_downloadFailedState.1.png deleted file mode 100644 index cd90ebd0d..000000000 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/FileAttachmentView_Tests/test_fileAttachmentView_downloadFailedState.1.png and /dev/null differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/FileAttachmentView_Tests/test_fileAttachmentView_downloadedState.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/FileAttachmentView_Tests/test_fileAttachmentView_downloadedState.1.png deleted file mode 100644 index e04b49f23..000000000 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/FileAttachmentView_Tests/test_fileAttachmentView_downloadedState.1.png and /dev/null differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/FileAttachmentView_Tests/test_fileAttachmentView_downloadingState.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/FileAttachmentView_Tests/test_fileAttachmentView_downloadingState.1.png deleted file mode 100644 index 9fdc13db8..000000000 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/FileAttachmentView_Tests/test_fileAttachmentView_downloadingState.1.png and /dev/null differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/FileAttachmentView_Tests/test_fileAttachmentView_uploaded_snapshot.default-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/FileAttachmentView_Tests/test_fileAttachmentView_uploaded_snapshot.default-dark.png new file mode 100644 index 000000000..cefccb240 Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/FileAttachmentView_Tests/test_fileAttachmentView_uploaded_snapshot.default-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/FileAttachmentView_Tests/test_fileAttachmentView_uploaded_snapshot.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/FileAttachmentView_Tests/test_fileAttachmentView_uploaded_snapshot.default-light.png new file mode 100644 index 000000000..ec5d845b3 Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/FileAttachmentView_Tests/test_fileAttachmentView_uploaded_snapshot.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/FileAttachmentView_Tests/test_fileAttachmentView_uploadingFailed_snapshot.default-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/FileAttachmentView_Tests/test_fileAttachmentView_uploadingFailed_snapshot.default-dark.png new file mode 100644 index 000000000..49a9de247 Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/FileAttachmentView_Tests/test_fileAttachmentView_uploadingFailed_snapshot.default-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/FileAttachmentView_Tests/test_fileAttachmentView_uploadingFailed_snapshot.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/FileAttachmentView_Tests/test_fileAttachmentView_uploadingFailed_snapshot.default-light.png new file mode 100644 index 000000000..7b12d26be Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/FileAttachmentView_Tests/test_fileAttachmentView_uploadingFailed_snapshot.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/FileAttachmentView_Tests/test_fileAttachmentView_uploadingProgress_snapshot.default-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/FileAttachmentView_Tests/test_fileAttachmentView_uploadingProgress_snapshot.default-dark.png new file mode 100644 index 000000000..186a6291c Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/FileAttachmentView_Tests/test_fileAttachmentView_uploadingProgress_snapshot.default-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/FileAttachmentView_Tests/test_fileAttachmentView_uploadingProgress_snapshot.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/FileAttachmentView_Tests/test_fileAttachmentView_uploadingProgress_snapshot.default-light.png new file mode 100644 index 000000000..66cfc9c01 Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/FileAttachmentView_Tests/test_fileAttachmentView_uploadingProgress_snapshot.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/LazyImageExtensions_Tests/test_imageRequest_emptyURL.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/LazyImageExtensions_Tests/test_imageRequest_emptyURL.1.png deleted file mode 100644 index 89e696240..000000000 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/LazyImageExtensions_Tests/test_imageRequest_emptyURL.1.png and /dev/null differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/LazyImageExtensions_Tests/test_imageURL_empty.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/LazyImageExtensions_Tests/test_imageURL_empty.1.png deleted file mode 100644 index 234d19d4e..000000000 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/LazyImageExtensions_Tests/test_imageURL_empty.1.png and /dev/null differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/LazyImageExtensions_Tests/test_imageURL_nonEmpty.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/LazyImageExtensions_Tests/test_imageURL_nonEmpty.1.png deleted file mode 100644 index 234d19d4e..000000000 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/LazyImageExtensions_Tests/test_imageURL_nonEmpty.1.png and /dev/null differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/LazyLoadingImage_Tests/test_lazyLoadingImage_noResize_snapshot.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/LazyLoadingImage_Tests/test_lazyLoadingImage_noResize_snapshot.default-light.png new file mode 100644 index 000000000..1c72aa051 Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/LazyLoadingImage_Tests/test_lazyLoadingImage_noResize_snapshot.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/LazyLoadingImage_Tests/test_lazyLoadingImage_snapshot.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/LazyLoadingImage_Tests/test_lazyLoadingImage_snapshot.default-light.png new file mode 100644 index 000000000..1c72aa051 Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/LazyLoadingImage_Tests/test_lazyLoadingImage_snapshot.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MediaViewer_Tests/test_gridViewVideoAndImage_snapshotLoading.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MediaViewer_Tests/test_gridViewVideoAndImage_snapshotLoading.1.png index d0d751cb8..4fce088c8 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MediaViewer_Tests/test_gridViewVideoAndImage_snapshotLoading.1.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MediaViewer_Tests/test_gridViewVideoAndImage_snapshotLoading.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MediaViewer_Tests/test_gridView_snapshotLoading.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MediaViewer_Tests/test_gridView_snapshotLoading.1.png index 8a2cf6138..e69e9a6c1 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MediaViewer_Tests/test_gridView_snapshotLoading.1.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MediaViewer_Tests/test_gridView_snapshotLoading.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MediaViewer_Tests/test_mediaViewerHeader_snapshot.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MediaViewer_Tests/test_mediaViewerHeader_snapshot.1.png index db525d013..8f17cb2cd 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MediaViewer_Tests/test_mediaViewerHeader_snapshot.1.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MediaViewer_Tests/test_mediaViewerHeader_snapshot.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MediaViewer_Tests/test_mediaViewerHeader_withMessageCreatedToday_snapshot.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MediaViewer_Tests/test_mediaViewerHeader_withMessageCreatedToday_snapshot.1.png index f6feffa4a..28011d85f 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MediaViewer_Tests/test_mediaViewerHeader_withMessageCreatedToday_snapshot.1.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MediaViewer_Tests/test_mediaViewerHeader_withMessageCreatedToday_snapshot.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MediaViewer_Tests/test_mediaViewerHeader_withMessageExactDate_snapshot.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MediaViewer_Tests/test_mediaViewerHeader_withMessageExactDate_snapshot.1.png index 90439a1b2..4b886b7ac 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MediaViewer_Tests/test_mediaViewerHeader_withMessageExactDate_snapshot.1.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MediaViewer_Tests/test_mediaViewerHeader_withMessageExactDate_snapshot.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MediaViewer_Tests/test_mediaViewer_snapshotLoading.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MediaViewer_Tests/test_mediaViewer_snapshotLoading.1.png index 09812d22c..ff15b441e 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MediaViewer_Tests/test_mediaViewer_snapshotLoading.1.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MediaViewer_Tests/test_mediaViewer_snapshotLoading.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_cameraAccessDeniedPromptView_snapshot.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_cameraAccessDeniedPromptView_snapshot.default-light.png index 61605eb7f..a3f7b64d0 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_cameraAccessDeniedPromptView_snapshot.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_cameraAccessDeniedPromptView_snapshot.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_cameraAccessDeniedPromptView_snapshot.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_cameraAccessDeniedPromptView_snapshot.extraExtraExtraLarge-light.png index 73538f9a4..a427f9f68 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_cameraAccessDeniedPromptView_snapshot.extraExtraExtraLarge-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_cameraAccessDeniedPromptView_snapshot.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_cameraAccessDeniedPromptView_snapshot.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_cameraAccessDeniedPromptView_snapshot.rightToLeftLayout-default.png index 66f3522a0..9f7c0d0cc 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_cameraAccessDeniedPromptView_snapshot.rightToLeftLayout-default.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_cameraAccessDeniedPromptView_snapshot.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_cameraAccessDeniedPromptView_snapshot.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_cameraAccessDeniedPromptView_snapshot.small-dark.png index a04b52633..7cdfd89c0 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_cameraAccessDeniedPromptView_snapshot.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_cameraAccessDeniedPromptView_snapshot.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_cameraOpenPromptView_snapshot.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_cameraOpenPromptView_snapshot.default-light.png index 88c02f77f..5a854d6c3 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_cameraOpenPromptView_snapshot.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_cameraOpenPromptView_snapshot.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_cameraOpenPromptView_snapshot.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_cameraOpenPromptView_snapshot.extraExtraExtraLarge-light.png index b4d39fb9d..3995f7feb 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_cameraOpenPromptView_snapshot.extraExtraExtraLarge-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_cameraOpenPromptView_snapshot.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_cameraOpenPromptView_snapshot.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_cameraOpenPromptView_snapshot.rightToLeftLayout-default.png index bad4a459e..017b0d6d7 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_cameraOpenPromptView_snapshot.rightToLeftLayout-default.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_cameraOpenPromptView_snapshot.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_cameraOpenPromptView_snapshot.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_cameraOpenPromptView_snapshot.small-dark.png index 8cfb2ba68..0dceaefa9 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_cameraOpenPromptView_snapshot.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_cameraOpenPromptView_snapshot.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_composerInputView_command.default-dark-themed.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_composerInputView_command.default-dark-themed.png index 80896b260..3a6599978 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_composerInputView_command.default-dark-themed.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_composerInputView_command.default-dark-themed.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_composerInputView_command.default-light-themed.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_composerInputView_command.default-light-themed.png index bcfe4b3fe..17b660f60 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_composerInputView_command.default-light-themed.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_composerInputView_command.default-light-themed.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_composerInputView_command.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_composerInputView_command.default-light.png index 792551c10..344e2fe0b 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_composerInputView_command.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_composerInputView_command.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_composerInputView_command.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_composerInputView_command.extraExtraExtraLarge-light.png index c77d581bb..665f2dac4 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_composerInputView_command.extraExtraExtraLarge-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_composerInputView_command.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_composerInputView_command.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_composerInputView_command.rightToLeftLayout-default.png index 65cfb7fee..9df3079e3 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_composerInputView_command.rightToLeftLayout-default.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_composerInputView_command.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_composerInputView_command.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_composerInputView_command.small-dark.png index a35e911fd..fb940d8fe 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_composerInputView_command.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_composerInputView_command.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_composerInputView_command_empty.default-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_composerInputView_command_empty.default-dark.png index 2d4ee8923..6f14d124c 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_composerInputView_command_empty.default-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_composerInputView_command_empty.default-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_composerInputView_command_empty.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_composerInputView_command_empty.default-light.png index ea7ca1789..429a6fe18 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_composerInputView_command_empty.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_composerInputView_command_empty.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_composerInputView_command_mute.default-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_composerInputView_command_mute.default-dark.png index 4303e1f3e..417339368 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_composerInputView_command_mute.default-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_composerInputView_command_mute.default-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_composerInputView_command_mute.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_composerInputView_command_mute.default-light.png index ad536aedb..80ad5e89a 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_composerInputView_command_mute.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_composerInputView_command_mute.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_composerInputView_composerInputTextView.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_composerInputView_composerInputTextView.1.png index 75714593f..4b407cd06 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_composerInputView_composerInputTextView.1.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_composerInputView_composerInputTextView.1.png differ 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 index 10f944d5b..643b03e5e 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_composerInputView_frozenChannel.1.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_composerInputView_frozenChannel.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_composerInputView_inputTextView.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_composerInputView_inputTextView.1.png index 2176dbc7e..3a3d8ab63 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_composerInputView_inputTextView.1.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_composerInputView_inputTextView.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_composerInputView_slowMode.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_composerInputView_slowMode.1.png index b83098059..3f2d23382 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_composerInputView_slowMode.1.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_composerInputView_slowMode.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_composerInputView_snapshot.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_composerInputView_snapshot.1.png index 6c205af79..2f0f5f172 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_composerInputView_snapshot.1.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_composerInputView_snapshot.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_composerView_draftWithCommand.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_composerView_draftWithCommand.default-light.png index 0b975f89c..375671d42 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_composerView_draftWithCommand.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_composerView_draftWithCommand.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_composerView_draftWithFileAttachment.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_composerView_draftWithFileAttachment.default-light.png index 92d035420..9b1ad6479 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_composerView_draftWithFileAttachment.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_composerView_draftWithFileAttachment.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_composerView_draftWithImageAttachment.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_composerView_draftWithImageAttachment.default-light.png index e95d34e25..ddc503fe2 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_composerView_draftWithImageAttachment.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_composerView_draftWithImageAttachment.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_composerView_draftWithVideoAttachment.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_composerView_draftWithVideoAttachment.default-light.png index a9041e131..db29449ad 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_composerView_draftWithVideoAttachment.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_composerView_draftWithVideoAttachment.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_composerView_draftWithVoiceRecordingAttachment.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_composerView_draftWithVoiceRecordingAttachment.default-light.png index 7e09d9c57..9c830d875 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_composerView_draftWithVoiceRecordingAttachment.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_composerView_draftWithVoiceRecordingAttachment.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_composerView_editingMessageWithFileAttachment.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_composerView_editingMessageWithFileAttachment.default-light.png index 3ee023264..f7cd476fa 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_composerView_editingMessageWithFileAttachment.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_composerView_editingMessageWithFileAttachment.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_composerView_editingMessageWithImageAttachment.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_composerView_editingMessageWithImageAttachment.default-light.png index bb8a444bc..9404aa87b 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_composerView_editingMessageWithImageAttachment.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_composerView_editingMessageWithImageAttachment.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_composerView_editingMessageWithQuotedMessage.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_composerView_editingMessageWithQuotedMessage.default-light.png index 39f5cc88a..722b6d4e5 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_composerView_editingMessageWithQuotedMessage.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_composerView_editingMessageWithQuotedMessage.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_composerView_editingMessageWithText.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_composerView_editingMessageWithText.default-light.png index 39f5cc88a..722b6d4e5 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_composerView_editingMessageWithText.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_composerView_editingMessageWithText.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_composerView_editingMessageWithVideoAttachment.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_composerView_editingMessageWithVideoAttachment.default-light.png index efef8874e..f0c90db43 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_composerView_editingMessageWithVideoAttachment.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_composerView_editingMessageWithVideoAttachment.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_composerView_editingMessageWithVoiceRecording.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_composerView_editingMessageWithVoiceRecording.default-light.png index d432785d1..037ad7ea7 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_composerView_editingMessageWithVoiceRecording.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_composerView_editingMessageWithVoiceRecording.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_composerView_quotingMessageWithImageAttachment.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_composerView_quotingMessageWithImageAttachment.default-light.png index c6643ae41..a48c46acf 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_composerView_quotingMessageWithImageAttachment.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_composerView_quotingMessageWithImageAttachment.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_fileOpenPromptView_snapshot.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_fileOpenPromptView_snapshot.default-light.png index b31336b1c..4dfcc2cf1 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_fileOpenPromptView_snapshot.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_fileOpenPromptView_snapshot.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_fileOpenPromptView_snapshot.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_fileOpenPromptView_snapshot.extraExtraExtraLarge-light.png index 8a3291e96..f2643af6b 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_fileOpenPromptView_snapshot.extraExtraExtraLarge-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_fileOpenPromptView_snapshot.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_fileOpenPromptView_snapshot.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_fileOpenPromptView_snapshot.rightToLeftLayout-default.png index d18a86618..e265b92ec 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_fileOpenPromptView_snapshot.rightToLeftLayout-default.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_fileOpenPromptView_snapshot.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_fileOpenPromptView_snapshot.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_fileOpenPromptView_snapshot.small-dark.png index 42880f1c2..e6ecbd03f 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_fileOpenPromptView_snapshot.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_fileOpenPromptView_snapshot.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_addedVoiceRecording.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_addedVoiceRecording.default-light.png index 4bf1ea1c1..2860fdc60 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_addedVoiceRecording.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_addedVoiceRecording.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_addedVoiceRecording.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_addedVoiceRecording.extraExtraExtraLarge-light.png index f636227d1..6f340c3f5 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_addedVoiceRecording.extraExtraExtraLarge-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_addedVoiceRecording.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_addedVoiceRecording.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_addedVoiceRecording.rightToLeftLayout-default.png index c558850eb..5bd9f2b90 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_addedVoiceRecording.rightToLeftLayout-default.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_addedVoiceRecording.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_addedVoiceRecording.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_addedVoiceRecording.small-dark.png index 645a64fec..38513cc8b 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_addedVoiceRecording.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_addedVoiceRecording.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_commandActive.default-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_commandActive.default-dark.png index 5bada9f03..e36a7f097 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_commandActive.default-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_commandActive.default-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_commandActive.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_commandActive.default-light.png index 6d5240bec..134ed7257 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_commandActive.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_commandActive.default-light.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 index 4051bdb3a..8d2ddf782 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_frozenChannel.1.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_frozenChannel.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_liquidGlass_snapshot.default-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_liquidGlass_snapshot.default-dark.png index 2765916d1..409c7214f 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_liquidGlass_snapshot.default-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_liquidGlass_snapshot.default-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_liquidGlass_snapshot.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_liquidGlass_snapshot.default-light.png index 1bc1bcc4a..2cd2eb3e6 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_liquidGlass_snapshot.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_liquidGlass_snapshot.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_liquidGlass_withAttachmentPicker.default-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_liquidGlass_withAttachmentPicker.default-dark.png index 6dfecc646..9b5ce8436 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_liquidGlass_withAttachmentPicker.default-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_liquidGlass_withAttachmentPicker.default-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_liquidGlass_withAttachmentPicker.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_liquidGlass_withAttachmentPicker.default-light.png index 1d47833a7..e637860f9 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_liquidGlass_withAttachmentPicker.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_liquidGlass_withAttachmentPicker.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_liquidGlass_withImageAttachment.default-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_liquidGlass_withImageAttachment.default-dark.png index 1617f2bb5..130351079 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_liquidGlass_withImageAttachment.default-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_liquidGlass_withImageAttachment.default-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_liquidGlass_withImageAttachment.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_liquidGlass_withImageAttachment.default-light.png index 948b9a067..acf086a21 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_liquidGlass_withImageAttachment.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_liquidGlass_withImageAttachment.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_recording.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_recording.default-light.png index a7ca87ed6..230e87b51 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_recording.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_recording.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_recording.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_recording.extraExtraExtraLarge-light.png index 6aceba0ba..0365ee3f3 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_recording.extraExtraExtraLarge-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_recording.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_recording.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_recording.rightToLeftLayout-default.png index ea38bafa3..80042be7d 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_recording.rightToLeftLayout-default.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_recording.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_recording.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_recording.small-dark.png index 2b2ce0d0c..9a756b63a 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_recording.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_recording.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_recordingLocked.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_recordingLocked.small-dark.png index eedc51e9c..0c45b7ee4 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_recordingLocked.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_recordingLocked.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_recordingSlideToCancel.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_recordingSlideToCancel.default-light.png index 94073c070..af551adc4 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_recordingSlideToCancel.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_recordingSlideToCancel.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_recordingSlideToCancel.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_recordingSlideToCancel.extraExtraExtraLarge-light.png index 6fd97a44a..2ae3f9cab 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_recordingSlideToCancel.extraExtraExtraLarge-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_recordingSlideToCancel.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_recordingSlideToCancel.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_recordingSlideToCancel.rightToLeftLayout-default.png index d46d05c51..4b2f0d7a8 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_recordingSlideToCancel.rightToLeftLayout-default.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_recordingSlideToCancel.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_recordingSlideToCancel.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_recordingSlideToCancel.small-dark.png index 4a2657a0e..9fe84f717 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_recordingSlideToCancel.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_recordingSlideToCancel.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_recordingStopped.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_recordingStopped.default-light.png index 6b4b9a7eb..a97cf90fe 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_recordingStopped.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_recordingStopped.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_recordingStopped.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_recordingStopped.extraExtraExtraLarge-light.png index 82c5e14e1..70827a83f 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_recordingStopped.extraExtraExtraLarge-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_recordingStopped.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_recordingStopped.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_recordingStopped.rightToLeftLayout-default.png index 8d0d1c291..113ca0833 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_recordingStopped.rightToLeftLayout-default.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_recordingStopped.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_recordingStopped.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_recordingStopped.small-dark.png index c010c764c..6ec9612db 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_recordingStopped.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_recordingStopped.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_recordingTipSnackbar.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_recordingTipSnackbar.default-light.png index 150ee4249..f7b68ca67 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_recordingTipSnackbar.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_recordingTipSnackbar.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_recordingTipSnackbar.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_recordingTipSnackbar.extraExtraExtraLarge-light.png index a804cf7e9..7312e1abd 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_recordingTipSnackbar.extraExtraExtraLarge-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_recordingTipSnackbar.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_recordingTipSnackbar.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_recordingTipSnackbar.rightToLeftLayout-default.png index 66f47e84a..ab330892b 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_recordingTipSnackbar.rightToLeftLayout-default.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_recordingTipSnackbar.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_recordingTipSnackbar.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_recordingTipSnackbar.small-dark.png index 8a72bac7e..661b46f76 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_recordingTipSnackbar.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_recordingTipSnackbar.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_recordingWhileQuoting.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_recordingWhileQuoting.default-light.png index a7ca87ed6..230e87b51 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_recordingWhileQuoting.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_recordingWhileQuoting.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_rtlSnapshot.rtl.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_rtlSnapshot.rtl.png index 5c2cd6e61..491d87268 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_rtlSnapshot.rtl.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_rtlSnapshot.rtl.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_rtlWithTextSnapshot.rtl-with-text.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_rtlWithTextSnapshot.rtl-with-text.png index 2c3644939..e8f2df6f4 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_rtlWithTextSnapshot.rtl-with-text.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_rtlWithTextSnapshot.rtl-with-text.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_sendButton_commandSelected_noText.default-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_sendButton_commandSelected_noText.default-dark.png new file mode 100644 index 000000000..2a2a6859b Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_sendButton_commandSelected_noText.default-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_sendButton_commandSelected_noText.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_sendButton_commandSelected_noText.default-light.png new file mode 100644 index 000000000..907eb943b Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_sendButton_commandSelected_noText.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_sendButton_commandSelected_withText.default-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_sendButton_commandSelected_withText.default-dark.png new file mode 100644 index 000000000..ea318e46d Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_sendButton_commandSelected_withText.default-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_sendButton_commandSelected_withText.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_sendButton_commandSelected_withText.default-light.png new file mode 100644 index 000000000..8ae1fc575 Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_sendButton_commandSelected_withText.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_sendButton_noCommandSelected.default-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_sendButton_noCommandSelected.default-dark.png new file mode 100644 index 000000000..7e30ed0cb Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_sendButton_noCommandSelected.default-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_sendButton_noCommandSelected.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_sendButton_noCommandSelected.default-light.png new file mode 100644 index 000000000..ef103412b Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_sendButton_noCommandSelected.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_sendInChannel_selected.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_sendInChannel_selected.default-light.png index 91ed3f9b2..aa576f0c0 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_sendInChannel_selected.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_sendInChannel_selected.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_sendInChannel_selected.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_sendInChannel_selected.extraExtraExtraLarge-light.png index 25d32ca61..450e3d06a 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_sendInChannel_selected.extraExtraExtraLarge-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_sendInChannel_selected.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_sendInChannel_selected.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_sendInChannel_selected.rightToLeftLayout-default.png index 414713082..3fc381d43 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_sendInChannel_selected.rightToLeftLayout-default.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_sendInChannel_selected.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_sendInChannel_selected.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_sendInChannel_selected.small-dark.png index 2fc271864..8c32aede7 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_sendInChannel_selected.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_sendInChannel_selected.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_sendInChannel_unselected.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_sendInChannel_unselected.default-light.png index 94f8a78fe..9ca77a4f6 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_sendInChannel_unselected.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_sendInChannel_unselected.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_sendInChannel_unselected.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_sendInChannel_unselected.extraExtraExtraLarge-light.png index 33e536efd..9ce0064ed 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_sendInChannel_unselected.extraExtraExtraLarge-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_sendInChannel_unselected.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_sendInChannel_unselected.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_sendInChannel_unselected.rightToLeftLayout-default.png index 759b4019f..56b2b98e6 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_sendInChannel_unselected.rightToLeftLayout-default.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_sendInChannel_unselected.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_sendInChannel_unselected.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_sendInChannel_unselected.small-dark.png index 1cda8868b..d3296a3e8 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_sendInChannel_unselected.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_sendInChannel_unselected.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_snapshot.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_snapshot.1.png index c4826aabf..21ffdf01d 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_snapshot.1.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_snapshot.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_voiceRecordingPlaying.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_voiceRecordingPlaying.default-light.png index f606fb6dd..9f97cbd04 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_voiceRecordingPlaying.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_voiceRecordingPlaying.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_withAttachmentPicker.default-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_withAttachmentPicker.default-dark.png index f76129b23..c0970a45a 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_withAttachmentPicker.default-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_withAttachmentPicker.default-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_withAttachmentPicker.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_withAttachmentPicker.default-light.png index 292ca4c7a..77600d37b 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_withAttachmentPicker.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_messageComposerView_withAttachmentPicker.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_photoLibraryAccessPromptView_snapshot.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_photoLibraryAccessPromptView_snapshot.default-light.png index bc895f60c..808519a4b 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_photoLibraryAccessPromptView_snapshot.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_photoLibraryAccessPromptView_snapshot.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_photoLibraryAccessPromptView_snapshot.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_photoLibraryAccessPromptView_snapshot.extraExtraExtraLarge-light.png index d4012422a..a7f9a0388 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_photoLibraryAccessPromptView_snapshot.extraExtraExtraLarge-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_photoLibraryAccessPromptView_snapshot.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_photoLibraryAccessPromptView_snapshot.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_photoLibraryAccessPromptView_snapshot.rightToLeftLayout-default.png index dc9e39445..8b8d6da70 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_photoLibraryAccessPromptView_snapshot.rightToLeftLayout-default.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_photoLibraryAccessPromptView_snapshot.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_photoLibraryAccessPromptView_snapshot.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_photoLibraryAccessPromptView_snapshot.small-dark.png index d3145b5db..42b7e90d0 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_photoLibraryAccessPromptView_snapshot.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_photoLibraryAccessPromptView_snapshot.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_pollCreatePromptView_snapshot.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_pollCreatePromptView_snapshot.default-light.png index fba296d93..5dd2ede26 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_pollCreatePromptView_snapshot.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_pollCreatePromptView_snapshot.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_pollCreatePromptView_snapshot.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_pollCreatePromptView_snapshot.extraExtraExtraLarge-light.png index 698e6c441..a7e35c70f 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_pollCreatePromptView_snapshot.extraExtraExtraLarge-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_pollCreatePromptView_snapshot.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_pollCreatePromptView_snapshot.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_pollCreatePromptView_snapshot.rightToLeftLayout-default.png index 9c9f837f3..ff3126712 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_pollCreatePromptView_snapshot.rightToLeftLayout-default.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_pollCreatePromptView_snapshot.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_pollCreatePromptView_snapshot.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_pollCreatePromptView_snapshot.small-dark.png index 49856b08e..ffe819723 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_pollCreatePromptView_snapshot.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageComposerView_Tests/test_pollCreatePromptView_snapshot.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageImagePreviewView_Tests/test_messageImagePreviewView_customSize.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageImagePreviewView_Tests/test_messageImagePreviewView_customSize.default-light.png new file mode 100644 index 000000000..ba9bb37df Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageImagePreviewView_Tests/test_messageImagePreviewView_customSize.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageImagePreviewView_Tests/test_messageImagePreviewView_defaultSize.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageImagePreviewView_Tests/test_messageImagePreviewView_defaultSize.default-light.png new file mode 100644 index 000000000..0ef38c515 Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageImagePreviewView_Tests/test_messageImagePreviewView_defaultSize.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_imageAttachments_failedWhenMessageTextIsEmpty_snapshot.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_imageAttachments_failedWhenMessageTextIsEmpty_snapshot.1.png index ebb275d52..3ba969c24 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_imageAttachments_failedWhenMessageTextIsEmpty_snapshot.1.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_imageAttachments_failedWhenMessageTextIsEmpty_snapshot.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_imageAttachments_failed_snapshot.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_imageAttachments_failed_snapshot.1.png index 86c39d2cb..ae317f509 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_imageAttachments_failed_snapshot.1.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_imageAttachments_failed_snapshot.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_imageAttachments_uploadingWithoutText_snapshot.default-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_imageAttachments_uploadingWithoutText_snapshot.default-dark.png new file mode 100644 index 000000000..b7182b671 Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_imageAttachments_uploadingWithoutText_snapshot.default-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_imageAttachments_uploadingWithoutText_snapshot.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_imageAttachments_uploadingWithoutText_snapshot.default-light.png new file mode 100644 index 000000000..6311b2d45 Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_imageAttachments_uploadingWithoutText_snapshot.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_imageAttachments_uploading_snapshot.default-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_imageAttachments_uploading_snapshot.default-dark.png new file mode 100644 index 000000000..814d58a90 Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_imageAttachments_uploading_snapshot.default-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_imageAttachments_uploading_snapshot.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_imageAttachments_uploading_snapshot.default-light.png new file mode 100644 index 000000000..c27bf1ccf Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_imageAttachments_uploading_snapshot.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_mediaGallery_landscape_1_snapshot.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_mediaGallery_landscape_1_snapshot.1.png index be6de9a2b..51a2d8938 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_mediaGallery_landscape_1_snapshot.1.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_mediaGallery_landscape_1_snapshot.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_mediaGallery_landscape_2_snapshot.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_mediaGallery_landscape_2_snapshot.1.png index 91b5ef44b..9a1223b03 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_mediaGallery_landscape_2_snapshot.1.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_mediaGallery_landscape_2_snapshot.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_mediaGallery_landscape_3_snapshot.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_mediaGallery_landscape_3_snapshot.1.png index 927c029d2..7187c15b7 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_mediaGallery_landscape_3_snapshot.1.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_mediaGallery_landscape_3_snapshot.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_mediaGallery_landscape_4_snapshot.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_mediaGallery_landscape_4_snapshot.1.png index 365b03d03..9262bc72b 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_mediaGallery_landscape_4_snapshot.1.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_mediaGallery_landscape_4_snapshot.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_mediaGallery_landscape_5_snapshot.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_mediaGallery_landscape_5_snapshot.1.png index 618ae7c38..fec7c9c71 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_mediaGallery_landscape_5_snapshot.1.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_mediaGallery_landscape_5_snapshot.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_mediaGallery_portrait_1_snapshot.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_mediaGallery_portrait_1_snapshot.1.png index 5ad0e15b9..f7dc8a1cb 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_mediaGallery_portrait_1_snapshot.1.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_mediaGallery_portrait_1_snapshot.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_mediaGallery_portrait_2_snapshot.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_mediaGallery_portrait_2_snapshot.1.png index 17e03ddb3..1de22d4c1 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_mediaGallery_portrait_2_snapshot.1.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_mediaGallery_portrait_2_snapshot.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_mediaGallery_portrait_3_snapshot.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_mediaGallery_portrait_3_snapshot.1.png index e8ddfec5e..87dbc632a 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_mediaGallery_portrait_3_snapshot.1.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_mediaGallery_portrait_3_snapshot.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_mediaGallery_portrait_4_snapshot.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_mediaGallery_portrait_4_snapshot.1.png index 365b03d03..9262bc72b 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_mediaGallery_portrait_4_snapshot.1.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_mediaGallery_portrait_4_snapshot.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_mediaGallery_portrait_5_snapshot.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_mediaGallery_portrait_5_snapshot.1.png index 618ae7c38..fec7c9c71 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_mediaGallery_portrait_5_snapshot.1.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_mediaGallery_portrait_5_snapshot.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_mediaGallery_square_1_snapshot.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_mediaGallery_square_1_snapshot.1.png index 2d0264127..4e24f36f0 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_mediaGallery_square_1_snapshot.1.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_mediaGallery_square_1_snapshot.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_mediaGallery_square_2_snapshot.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_mediaGallery_square_2_snapshot.1.png index 17e03ddb3..1de22d4c1 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_mediaGallery_square_2_snapshot.1.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_mediaGallery_square_2_snapshot.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_mediaGallery_square_3_snapshot.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_mediaGallery_square_3_snapshot.1.png index e8ddfec5e..87dbc632a 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_mediaGallery_square_3_snapshot.1.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_mediaGallery_square_3_snapshot.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_mediaGallery_square_4_snapshot.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_mediaGallery_square_4_snapshot.1.png index 365b03d03..9262bc72b 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_mediaGallery_square_4_snapshot.1.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_mediaGallery_square_4_snapshot.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_mediaGallery_square_5_snapshot.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_mediaGallery_square_5_snapshot.1.png index 618ae7c38..fec7c9c71 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_mediaGallery_square_5_snapshot.1.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_mediaGallery_square_5_snapshot.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messageContainerCurrentUserColor_snapshot.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messageContainerCurrentUserColor_snapshot.1.png index 6483aebae..9a14acea5 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messageContainerCurrentUserColor_snapshot.1.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messageContainerCurrentUserColor_snapshot.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messageContainerEditedAIGenerated_snapshot.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messageContainerEditedAIGenerated_snapshot.1.png index 184074234..2a3286a37 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messageContainerEditedAIGenerated_snapshot.1.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messageContainerEditedAIGenerated_snapshot.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messageContainerEdited_snapshot.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messageContainerEdited_snapshot.1.png index 98b1c8dfc..8bcf5bc6b 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messageContainerEdited_snapshot.1.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messageContainerEdited_snapshot.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messageContainerHighlighted_snapshot.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messageContainerHighlighted_snapshot.1.png index cd40d9391..d500c70fb 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messageContainerHighlighted_snapshot.1.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messageContainerHighlighted_snapshot.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messageContainerViewDeleted_snapshot.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messageContainerViewDeleted_snapshot.1.png new file mode 100644 index 000000000..7811b253c Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messageContainerViewDeleted_snapshot.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messageContainerViewPinned_snapshot.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messageContainerViewPinned_snapshot.1.png index a3803ee48..6372c80a0 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messageContainerViewPinned_snapshot.1.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messageContainerViewPinned_snapshot.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messageContainerViewSentThisUser_snapshot.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messageContainerViewSentThisUser_snapshot.1.png index 73c7ca383..472ccaad8 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messageContainerViewSentThisUser_snapshot.1.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messageContainerViewSentThisUser_snapshot.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messageContainerView_editingFailed_snapshot.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messageContainerView_editingFailed_snapshot.1.png index c6df706bf..9784da99f 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messageContainerView_editingFailed_snapshot.1.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messageContainerView_editingFailed_snapshot.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messageContainerView_sendingFailed_snapshot.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messageContainerView_sendingFailed_snapshot.1.png index c6df706bf..9784da99f 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messageContainerView_sendingFailed_snapshot.1.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messageContainerView_sendingFailed_snapshot.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messageContainerView_topReactionsWithPinnedAnnotation_snapshot.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messageContainerView_topReactionsWithPinnedAnnotation_snapshot.default-light.png index c05b98ca8..88a91fd85 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messageContainerView_topReactionsWithPinnedAnnotation_snapshot.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messageContainerView_topReactionsWithPinnedAnnotation_snapshot.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messageContainerView_topReactionsWithPinnedAnnotation_snapshot.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messageContainerView_topReactionsWithPinnedAnnotation_snapshot.extraExtraExtraLarge-light.png index 0968e9391..8c582028e 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messageContainerView_topReactionsWithPinnedAnnotation_snapshot.extraExtraExtraLarge-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messageContainerView_topReactionsWithPinnedAnnotation_snapshot.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messageContainerView_topReactionsWithPinnedAnnotation_snapshot.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messageContainerView_topReactionsWithPinnedAnnotation_snapshot.rightToLeftLayout-default.png index cc366d770..3af95e44e 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messageContainerView_topReactionsWithPinnedAnnotation_snapshot.rightToLeftLayout-default.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messageContainerView_topReactionsWithPinnedAnnotation_snapshot.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messageContainerView_topReactionsWithPinnedAnnotation_snapshot.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messageContainerView_topReactionsWithPinnedAnnotation_snapshot.small-dark.png index 2d3a63595..1e709acd0 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messageContainerView_topReactionsWithPinnedAnnotation_snapshot.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messageContainerView_topReactionsWithPinnedAnnotation_snapshot.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messageContainerView_topReactionsWithReminderAnnotation_snapshot.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messageContainerView_topReactionsWithReminderAnnotation_snapshot.default-light.png index 84bb830ee..2cd5a0cc3 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messageContainerView_topReactionsWithReminderAnnotation_snapshot.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messageContainerView_topReactionsWithReminderAnnotation_snapshot.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messageContainerView_topReactionsWithReminderAnnotation_snapshot.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messageContainerView_topReactionsWithReminderAnnotation_snapshot.extraExtraExtraLarge-light.png index 7c9ce523b..58e43e261 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messageContainerView_topReactionsWithReminderAnnotation_snapshot.extraExtraExtraLarge-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messageContainerView_topReactionsWithReminderAnnotation_snapshot.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messageContainerView_topReactionsWithReminderAnnotation_snapshot.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messageContainerView_topReactionsWithReminderAnnotation_snapshot.rightToLeftLayout-default.png index 3f86ec5ea..4db699e3f 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messageContainerView_topReactionsWithReminderAnnotation_snapshot.rightToLeftLayout-default.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messageContainerView_topReactionsWithReminderAnnotation_snapshot.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messageContainerView_topReactionsWithReminderAnnotation_snapshot.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messageContainerView_topReactionsWithReminderAnnotation_snapshot.small-dark.png index b019b3ca6..0ac9116b2 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messageContainerView_topReactionsWithReminderAnnotation_snapshot.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messageContainerView_topReactionsWithReminderAnnotation_snapshot.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messageContainerView_topReactionsWithThreadReplyAnnotation_snapshot.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messageContainerView_topReactionsWithThreadReplyAnnotation_snapshot.default-light.png index 7aa2e7fbf..e40b4798e 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messageContainerView_topReactionsWithThreadReplyAnnotation_snapshot.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messageContainerView_topReactionsWithThreadReplyAnnotation_snapshot.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messageContainerView_topReactionsWithThreadReplyAnnotation_snapshot.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messageContainerView_topReactionsWithThreadReplyAnnotation_snapshot.extraExtraExtraLarge-light.png index 74b3d3bfd..ca99e2084 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messageContainerView_topReactionsWithThreadReplyAnnotation_snapshot.extraExtraExtraLarge-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messageContainerView_topReactionsWithThreadReplyAnnotation_snapshot.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messageContainerView_topReactionsWithThreadReplyAnnotation_snapshot.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messageContainerView_topReactionsWithThreadReplyAnnotation_snapshot.rightToLeftLayout-default.png index a231ce11f..bb0f2cad4 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messageContainerView_topReactionsWithThreadReplyAnnotation_snapshot.rightToLeftLayout-default.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messageContainerView_topReactionsWithThreadReplyAnnotation_snapshot.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messageContainerView_topReactionsWithThreadReplyAnnotation_snapshot.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messageContainerView_topReactionsWithThreadReplyAnnotation_snapshot.small-dark.png index 0eaf6a1c1..4c0b574d7 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messageContainerView_topReactionsWithThreadReplyAnnotation_snapshot.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messageContainerView_topReactionsWithThreadReplyAnnotation_snapshot.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messageItemView_incomingAvatarHidden_snapshot.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messageItemView_incomingAvatarHidden_snapshot.small-dark.png index ad7df3756..348dabfda 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messageItemView_incomingAvatarHidden_snapshot.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messageItemView_incomingAvatarHidden_snapshot.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messagePreview_authorAndTimestamp_snapshot.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messagePreview_authorAndTimestamp_snapshot.default-light.png index 4a6c090f4..54b0905fb 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messagePreview_authorAndTimestamp_snapshot.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messagePreview_authorAndTimestamp_snapshot.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messagePreview_authorAndTimestamp_snapshot.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messagePreview_authorAndTimestamp_snapshot.extraExtraExtraLarge-light.png index bc14a1160..58172b439 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messagePreview_authorAndTimestamp_snapshot.extraExtraExtraLarge-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messagePreview_authorAndTimestamp_snapshot.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messagePreview_authorAndTimestamp_snapshot.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messagePreview_authorAndTimestamp_snapshot.rightToLeftLayout-default.png index e00768452..b8a124892 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messagePreview_authorAndTimestamp_snapshot.rightToLeftLayout-default.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messagePreview_authorAndTimestamp_snapshot.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messagePreview_authorAndTimestamp_snapshot.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messagePreview_authorAndTimestamp_snapshot.small-dark.png index cea9d3ab7..aa3794112 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messagePreview_authorAndTimestamp_snapshot.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messagePreview_authorAndTimestamp_snapshot.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messagePreview_threadReplies_snapshot.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messagePreview_threadReplies_snapshot.default-light.png index 0a807ef8d..4d8d5b707 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messagePreview_threadReplies_snapshot.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messagePreview_threadReplies_snapshot.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messagePreview_threadReplies_snapshot.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messagePreview_threadReplies_snapshot.extraExtraExtraLarge-light.png index 70011e821..e06b42252 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messagePreview_threadReplies_snapshot.extraExtraExtraLarge-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messagePreview_threadReplies_snapshot.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messagePreview_threadReplies_snapshot.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messagePreview_threadReplies_snapshot.rightToLeftLayout-default.png index 6019ad543..84d10b520 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messagePreview_threadReplies_snapshot.rightToLeftLayout-default.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messagePreview_threadReplies_snapshot.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messagePreview_threadReplies_snapshot.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messagePreview_threadReplies_snapshot.small-dark.png index 516d2edac..4f1f92656 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messagePreview_threadReplies_snapshot.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messagePreview_threadReplies_snapshot.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messagePreview_timestampOnly_snapshot.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messagePreview_timestampOnly_snapshot.default-light.png index 585da7066..001ed56ba 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messagePreview_timestampOnly_snapshot.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messagePreview_timestampOnly_snapshot.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messagePreview_timestampOnly_snapshot.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messagePreview_timestampOnly_snapshot.extraExtraExtraLarge-light.png index 055d92e73..9e8eb2892 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messagePreview_timestampOnly_snapshot.extraExtraExtraLarge-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messagePreview_timestampOnly_snapshot.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messagePreview_timestampOnly_snapshot.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messagePreview_timestampOnly_snapshot.rightToLeftLayout-default.png index 606b14cc7..fa35cc09f 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messagePreview_timestampOnly_snapshot.rightToLeftLayout-default.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messagePreview_timestampOnly_snapshot.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messagePreview_timestampOnly_snapshot.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messagePreview_timestampOnly_snapshot.small-dark.png index eb2a2715e..55102b1d8 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messagePreview_timestampOnly_snapshot.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messagePreview_timestampOnly_snapshot.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messagePreview_translatedText_snapshot.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messagePreview_translatedText_snapshot.default-light.png index 08e899b4e..786f24346 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messagePreview_translatedText_snapshot.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messagePreview_translatedText_snapshot.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messagePreview_translatedText_snapshot.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messagePreview_translatedText_snapshot.extraExtraExtraLarge-light.png index 53794b5b8..90894f075 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messagePreview_translatedText_snapshot.extraExtraExtraLarge-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messagePreview_translatedText_snapshot.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messagePreview_translatedText_snapshot.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messagePreview_translatedText_snapshot.rightToLeftLayout-default.png index 3198cf3c1..0ab2f827a 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messagePreview_translatedText_snapshot.rightToLeftLayout-default.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messagePreview_translatedText_snapshot.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messagePreview_translatedText_snapshot.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messagePreview_translatedText_snapshot.small-dark.png index 376609c19..a5f5369de 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messagePreview_translatedText_snapshot.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_messagePreview_translatedText_snapshot.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_multipleImageAttachments_failed_snapshot.default-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_multipleImageAttachments_failed_snapshot.default-dark.png new file mode 100644 index 000000000..510bd4882 Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_multipleImageAttachments_failed_snapshot.default-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_multipleImageAttachments_failed_snapshot.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_multipleImageAttachments_failed_snapshot.default-light.png new file mode 100644 index 000000000..a90a3f94e Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_multipleImageAttachments_failed_snapshot.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_multipleImageAttachments_uploading_snapshot.default-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_multipleImageAttachments_uploading_snapshot.default-dark.png new file mode 100644 index 000000000..bc72052c9 Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_multipleImageAttachments_uploading_snapshot.default-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_multipleImageAttachments_uploading_snapshot.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_multipleImageAttachments_uploading_snapshot.default-light.png new file mode 100644 index 000000000..8b3455eee Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_multipleImageAttachments_uploading_snapshot.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_portraitImageWithOneReaction_snapshot.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_portraitImageWithOneReaction_snapshot.default-light.png new file mode 100644 index 000000000..7ce27308b Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_portraitImageWithOneReaction_snapshot.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_portraitImageWithOneReaction_snapshot.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_portraitImageWithOneReaction_snapshot.extraExtraExtraLarge-light.png new file mode 100644 index 000000000..dbc0a257b Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_portraitImageWithOneReaction_snapshot.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_portraitImageWithOneReaction_snapshot.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_portraitImageWithOneReaction_snapshot.rightToLeftLayout-default.png new file mode 100644 index 000000000..bfea53437 Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_portraitImageWithOneReaction_snapshot.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_portraitImageWithOneReaction_snapshot.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_portraitImageWithOneReaction_snapshot.small-dark.png new file mode 100644 index 000000000..6f67d26b7 Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_portraitImageWithOneReaction_snapshot.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_singleImageNoCaption_incoming_firstInGroup_snapshot.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_singleImageNoCaption_incoming_firstInGroup_snapshot.1.png new file mode 100644 index 000000000..c77bef743 Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_singleImageNoCaption_incoming_firstInGroup_snapshot.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_singleImageNoCaption_notFirstInGroup_snapshot.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_singleImageNoCaption_notFirstInGroup_snapshot.1.png new file mode 100644 index 000000000..54b2b0b3e Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_singleImageNoCaption_notFirstInGroup_snapshot.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_singleImageNoCaption_outgoing_firstInGroup_snapshot.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_singleImageNoCaption_outgoing_firstInGroup_snapshot.1.png new file mode 100644 index 000000000..144ee4597 Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_singleImageNoCaption_outgoing_firstInGroup_snapshot.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_singleImageNoCaption_portrait_outgoing_snapshot.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_singleImageNoCaption_portrait_outgoing_snapshot.1.png new file mode 100644 index 000000000..c0d5579c9 Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_singleImageNoCaption_portrait_outgoing_snapshot.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_singleImageWithCaption_outgoing_snapshot.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_singleImageWithCaption_outgoing_snapshot.1.png new file mode 100644 index 000000000..89d899136 Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_singleImageWithCaption_outgoing_snapshot.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_singleVideoNoCaption_outgoing_firstInGroup_snapshot.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_singleVideoNoCaption_outgoing_firstInGroup_snapshot.1.png new file mode 100644 index 000000000..144ee4597 Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_singleVideoNoCaption_outgoing_firstInGroup_snapshot.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_swipeToReplyIndicator_outgoing_snapshot.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_swipeToReplyIndicator_outgoing_snapshot.default-light.png new file mode 100644 index 000000000..c7ee8924b Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_swipeToReplyIndicator_outgoing_snapshot.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_swipeToReplyIndicator_outgoing_snapshot.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_swipeToReplyIndicator_outgoing_snapshot.extraExtraExtraLarge-light.png new file mode 100644 index 000000000..d5bfb7ef3 Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_swipeToReplyIndicator_outgoing_snapshot.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_swipeToReplyIndicator_outgoing_snapshot.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_swipeToReplyIndicator_outgoing_snapshot.rightToLeftLayout-default.png new file mode 100644 index 000000000..591f4cda0 Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_swipeToReplyIndicator_outgoing_snapshot.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_swipeToReplyIndicator_outgoing_snapshot.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_swipeToReplyIndicator_outgoing_snapshot.small-dark.png new file mode 100644 index 000000000..d2c414526 Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_swipeToReplyIndicator_outgoing_snapshot.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_swipeToReplyIndicator_snapshot.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_swipeToReplyIndicator_snapshot.small-dark.png index 05bff3935..b8a285f65 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_swipeToReplyIndicator_snapshot.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_swipeToReplyIndicator_snapshot.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_translatedText_showOriginalTranslatedButtonDisabled_translatedTextShown_snapshot.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_translatedText_showOriginalTranslatedButtonDisabled_translatedTextShown_snapshot.1.png index 3f2e3f724..cd93664fe 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_translatedText_showOriginalTranslatedButtonDisabled_translatedTextShown_snapshot.1.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_translatedText_showOriginalTranslatedButtonDisabled_translatedTextShown_snapshot.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_translatedText_showOriginalTranslatedButtonEnabled_originalTextShown_snapshot.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_translatedText_showOriginalTranslatedButtonEnabled_originalTextShown_snapshot.1.png index 0c68f5e2d..84dd76fc4 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_translatedText_showOriginalTranslatedButtonEnabled_originalTextShown_snapshot.1.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_translatedText_showOriginalTranslatedButtonEnabled_originalTextShown_snapshot.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_translatedText_showOriginalTranslatedButtonEnabled_translatedTextShown_snapshot.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_translatedText_showOriginalTranslatedButtonEnabled_translatedTextShown_snapshot.1.png index a6cc1cfe4..3281f0e28 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_translatedText_showOriginalTranslatedButtonEnabled_translatedTextShown_snapshot.1.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_translatedText_showOriginalTranslatedButtonEnabled_translatedTextShown_snapshot.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_videoAttachment_snapshotNoText.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_videoAttachment_snapshotNoText.1.png index 8221e2630..43151767d 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_videoAttachment_snapshotNoText.1.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_videoAttachment_snapshotNoText.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_videoAttachment_snapshotText.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_videoAttachment_snapshotText.1.png index 8221e2630..d0544e8e8 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_videoAttachment_snapshotText.1.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageItemView_Tests/test_videoAttachment_snapshotText.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListViewAvatars_Tests/test_messageListView_defaultDMChannel.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListViewAvatars_Tests/test_messageListView_defaultDMChannel.1.png index af4345d4d..362171682 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListViewAvatars_Tests/test_messageListView_defaultDMChannel.1.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListViewAvatars_Tests/test_messageListView_defaultDMChannel.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListViewAvatars_Tests/test_messageListView_defaultGroupsChannel.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListViewAvatars_Tests/test_messageListView_defaultGroupsChannel.1.png index af4345d4d..362171682 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListViewAvatars_Tests/test_messageListView_defaultGroupsChannel.1.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListViewAvatars_Tests/test_messageListView_defaultGroupsChannel.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListViewAvatars_Tests/test_messageListView_dmChannelAvatarsOff.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListViewAvatars_Tests/test_messageListView_dmChannelAvatarsOff.1.png index de3b4b5bb..4af7dfc97 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListViewAvatars_Tests/test_messageListView_dmChannelAvatarsOff.1.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListViewAvatars_Tests/test_messageListView_dmChannelAvatarsOff.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListViewAvatars_Tests/test_messageListView_groupsChannelAvatarsOff.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListViewAvatars_Tests/test_messageListView_groupsChannelAvatarsOff.1.png index de3b4b5bb..4af7dfc97 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListViewAvatars_Tests/test_messageListView_groupsChannelAvatarsOff.1.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListViewAvatars_Tests/test_messageListView_groupsChannelAvatarsOff.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListViewLastGroupHeader_Tests/test_messageListView_headerOnTop.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListViewLastGroupHeader_Tests/test_messageListView_headerOnTop.1.png index 5e04ccfc6..5f6e7744d 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListViewLastGroupHeader_Tests/test_messageListView_headerOnTop.1.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListViewLastGroupHeader_Tests/test_messageListView_headerOnTop.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListViewNewMessages_Tests/test_messageListViewNewMessages_moreMessages.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListViewNewMessages_Tests/test_messageListViewNewMessages_moreMessages.1.png index 4c3c1cef5..3656ce5f3 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListViewNewMessages_Tests/test_messageListViewNewMessages_moreMessages.1.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListViewNewMessages_Tests/test_messageListViewNewMessages_moreMessages.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListViewNewMessages_Tests/test_messageListViewNewMessages_moreMessagesInBetween.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListViewNewMessages_Tests/test_messageListViewNewMessages_moreMessagesInBetween.1.png index 5f80d0101..4aa2d661b 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListViewNewMessages_Tests/test_messageListViewNewMessages_moreMessagesInBetween.1.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListViewNewMessages_Tests/test_messageListViewNewMessages_moreMessagesInBetween.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListViewNewMessages_Tests/test_messageListViewNewMessages_noMessages.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListViewNewMessages_Tests/test_messageListViewNewMessages_noMessages.1.png index 9686a910b..78b7dc629 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListViewNewMessages_Tests/test_messageListViewNewMessages_noMessages.1.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListViewNewMessages_Tests/test_messageListViewNewMessages_noMessages.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListViewNewMessages_Tests/test_messageListViewNewMessages_singleMessage.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListViewNewMessages_Tests/test_messageListViewNewMessages_singleMessage.1.png index 9830e0fa5..40410f3bf 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListViewNewMessages_Tests/test_messageListViewNewMessages_singleMessage.1.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListViewNewMessages_Tests/test_messageListViewNewMessages_singleMessage.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_jumpToUnreadButton_snapshotHighUnreadCount.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_jumpToUnreadButton_snapshotHighUnreadCount.default-light.png new file mode 100644 index 000000000..8b0381999 Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_jumpToUnreadButton_snapshotHighUnreadCount.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_jumpToUnreadButton_snapshotHighUnreadCount.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_jumpToUnreadButton_snapshotHighUnreadCount.extraExtraExtraLarge-light.png new file mode 100644 index 000000000..10be369a2 Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_jumpToUnreadButton_snapshotHighUnreadCount.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_jumpToUnreadButton_snapshotHighUnreadCount.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_jumpToUnreadButton_snapshotHighUnreadCount.rightToLeftLayout-default.png new file mode 100644 index 000000000..364e4b8a5 Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_jumpToUnreadButton_snapshotHighUnreadCount.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_jumpToUnreadButton_snapshotHighUnreadCount.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_jumpToUnreadButton_snapshotHighUnreadCount.small-dark.png new file mode 100644 index 000000000..084dfa359 Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_jumpToUnreadButton_snapshotHighUnreadCount.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_jumpToUnreadButton_snapshotMultipleUnread.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_jumpToUnreadButton_snapshotMultipleUnread.default-light.png new file mode 100644 index 000000000..915c83fc0 Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_jumpToUnreadButton_snapshotMultipleUnread.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_jumpToUnreadButton_snapshotMultipleUnread.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_jumpToUnreadButton_snapshotMultipleUnread.extraExtraExtraLarge-light.png new file mode 100644 index 000000000..63540d8f9 Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_jumpToUnreadButton_snapshotMultipleUnread.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_jumpToUnreadButton_snapshotMultipleUnread.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_jumpToUnreadButton_snapshotMultipleUnread.rightToLeftLayout-default.png new file mode 100644 index 000000000..379d1f6f6 Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_jumpToUnreadButton_snapshotMultipleUnread.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_jumpToUnreadButton_snapshotMultipleUnread.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_jumpToUnreadButton_snapshotMultipleUnread.small-dark.png new file mode 100644 index 000000000..79845202f Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_jumpToUnreadButton_snapshotMultipleUnread.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_jumpToUnreadButton_snapshotSingleUnread.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_jumpToUnreadButton_snapshotSingleUnread.default-light.png new file mode 100644 index 000000000..113157ebd Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_jumpToUnreadButton_snapshotSingleUnread.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_jumpToUnreadButton_snapshotSingleUnread.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_jumpToUnreadButton_snapshotSingleUnread.extraExtraExtraLarge-light.png new file mode 100644 index 000000000..2d8ffea12 Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_jumpToUnreadButton_snapshotSingleUnread.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_jumpToUnreadButton_snapshotSingleUnread.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_jumpToUnreadButton_snapshotSingleUnread.rightToLeftLayout-default.png new file mode 100644 index 000000000..2116600d1 Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_jumpToUnreadButton_snapshotSingleUnread.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_jumpToUnreadButton_snapshotSingleUnread.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_jumpToUnreadButton_snapshotSingleUnread.small-dark.png new file mode 100644 index 000000000..d5ce9a5ea Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_jumpToUnreadButton_snapshotSingleUnread.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_messageListView_groupChannel_withReactions.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_messageListView_groupChannel_withReactions.1.png index b5d3d7be8..f81e0cf2b 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_messageListView_groupChannel_withReactions.1.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_messageListView_groupChannel_withReactions.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_messageListView_groupedMessages_withAllAnnotations.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_messageListView_groupedMessages_withAllAnnotations.1.png new file mode 100644 index 000000000..7e347fa50 Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_messageListView_groupedMessages_withAllAnnotations.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_messageListView_groupedMessages_withThreadReplyAnnotation.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_messageListView_groupedMessages_withThreadReplyAnnotation.1.png new file mode 100644 index 000000000..1205dab7c Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_messageListView_groupedMessages_withThreadReplyAnnotation.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_messageListView_jumpToUnreadButton.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_messageListView_jumpToUnreadButton.1.png index 941cdc354..4d65735e5 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_messageListView_jumpToUnreadButton.1.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_messageListView_jumpToUnreadButton.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_messageListView_noReactions.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_messageListView_noReactions.1.png index af4345d4d..362171682 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_messageListView_noReactions.1.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_messageListView_noReactions.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_messageListView_systemMessage.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_messageListView_systemMessage.1.png index a41b510da..d6748ccbc 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_messageListView_systemMessage.1.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_messageListView_systemMessage.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_messageListView_threadRepliesSeparator.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_messageListView_threadRepliesSeparator.default-light.png new file mode 100644 index 000000000..b146567b7 Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_messageListView_threadRepliesSeparator.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_messageListView_threadRepliesSeparator.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_messageListView_threadRepliesSeparator.extraExtraExtraLarge-light.png new file mode 100644 index 000000000..808af680b Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_messageListView_threadRepliesSeparator.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_messageListView_threadRepliesSeparator.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_messageListView_threadRepliesSeparator.rightToLeftLayout-default.png new file mode 100644 index 000000000..d9972a109 Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_messageListView_threadRepliesSeparator.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_messageListView_threadRepliesSeparator.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_messageListView_threadRepliesSeparator.small-dark.png new file mode 100644 index 000000000..4f84d1aac Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_messageListView_threadRepliesSeparator.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_messageListView_threadRepliesSeparator_hiddenWhenNotAllLoaded.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_messageListView_threadRepliesSeparator_hiddenWhenNotAllLoaded.default-light.png new file mode 100644 index 000000000..606138f46 Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_messageListView_threadRepliesSeparator_hiddenWhenNotAllLoaded.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_messageListView_threadRepliesSeparator_hiddenWhenNotAllLoaded.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_messageListView_threadRepliesSeparator_hiddenWhenNotAllLoaded.extraExtraExtraLarge-light.png new file mode 100644 index 000000000..07be07cb5 Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_messageListView_threadRepliesSeparator_hiddenWhenNotAllLoaded.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_messageListView_threadRepliesSeparator_hiddenWhenNotAllLoaded.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_messageListView_threadRepliesSeparator_hiddenWhenNotAllLoaded.rightToLeftLayout-default.png new file mode 100644 index 000000000..928120ed3 Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_messageListView_threadRepliesSeparator_hiddenWhenNotAllLoaded.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_messageListView_threadRepliesSeparator_hiddenWhenNotAllLoaded.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_messageListView_threadRepliesSeparator_hiddenWhenNotAllLoaded.small-dark.png new file mode 100644 index 000000000..2690318b0 Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_messageListView_threadRepliesSeparator_hiddenWhenNotAllLoaded.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_messageListView_typingIndicator.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_messageListView_typingIndicator.1.png index 968e183e2..d90cfb9db 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_messageListView_typingIndicator.1.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_messageListView_typingIndicator.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_messageListView_viewModelInit_noReactions.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_messageListView_viewModelInit_noReactions.1.png index 03a9523e7..910a2d743 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_messageListView_viewModelInit_noReactions.1.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_messageListView_viewModelInit_noReactions.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_messageListView_viewModelInit_unreadIndicator.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_messageListView_viewModelInit_unreadIndicator.1.png deleted file mode 100644 index 3d55c8850..000000000 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_messageListView_viewModelInit_unreadIndicator.1.png and /dev/null differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_messageListView_viewModelInit_unreadIndicator.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_messageListView_viewModelInit_unreadIndicator.default-light.png new file mode 100644 index 000000000..3743197c8 Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_messageListView_viewModelInit_unreadIndicator.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_messageListView_viewModelInit_unreadIndicator.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_messageListView_viewModelInit_unreadIndicator.extraExtraExtraLarge-light.png new file mode 100644 index 000000000..f106c1ce7 Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_messageListView_viewModelInit_unreadIndicator.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_messageListView_viewModelInit_unreadIndicator.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_messageListView_viewModelInit_unreadIndicator.rightToLeftLayout-default.png new file mode 100644 index 000000000..0ad369cf8 Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_messageListView_viewModelInit_unreadIndicator.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_messageListView_viewModelInit_unreadIndicator.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_messageListView_viewModelInit_unreadIndicator.small-dark.png new file mode 100644 index 000000000..eb22a1d8b Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_messageListView_viewModelInit_unreadIndicator.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_messageListView_viewModelInit_withReactions.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_messageListView_viewModelInit_withReactions.1.png index 70a080e38..780dab63d 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_messageListView_viewModelInit_withReactions.1.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_messageListView_viewModelInit_withReactions.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_messageListView_withReactions.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_messageListView_withReactions.1.png index 628df3734..e35ab5e85 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_messageListView_withReactions.1.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_messageListView_withReactions.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_scrollToBottomButton_snapshotEmptyCount.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_scrollToBottomButton_snapshotEmptyCount.default-light.png index 073b70bf8..f132cbe2e 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_scrollToBottomButton_snapshotEmptyCount.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_scrollToBottomButton_snapshotEmptyCount.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_scrollToBottomButton_snapshotEmptyCount.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_scrollToBottomButton_snapshotEmptyCount.extraExtraExtraLarge-light.png index 073b70bf8..f132cbe2e 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_scrollToBottomButton_snapshotEmptyCount.extraExtraExtraLarge-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_scrollToBottomButton_snapshotEmptyCount.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_scrollToBottomButton_snapshotEmptyCount.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_scrollToBottomButton_snapshotEmptyCount.rightToLeftLayout-default.png index f6ff57499..46f77297e 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_scrollToBottomButton_snapshotEmptyCount.rightToLeftLayout-default.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_scrollToBottomButton_snapshotEmptyCount.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_scrollToBottomButton_snapshotEmptyCount.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_scrollToBottomButton_snapshotEmptyCount.small-dark.png index 4db3a765f..a632701b0 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_scrollToBottomButton_snapshotEmptyCount.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_scrollToBottomButton_snapshotEmptyCount.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_scrollToBottomButton_snapshotHighUnreadCount.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_scrollToBottomButton_snapshotHighUnreadCount.default-light.png index 553b80c78..ee7d07059 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_scrollToBottomButton_snapshotHighUnreadCount.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_scrollToBottomButton_snapshotHighUnreadCount.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_scrollToBottomButton_snapshotHighUnreadCount.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_scrollToBottomButton_snapshotHighUnreadCount.extraExtraExtraLarge-light.png index a07f53fb5..7447e5357 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_scrollToBottomButton_snapshotHighUnreadCount.extraExtraExtraLarge-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_scrollToBottomButton_snapshotHighUnreadCount.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_scrollToBottomButton_snapshotHighUnreadCount.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_scrollToBottomButton_snapshotHighUnreadCount.rightToLeftLayout-default.png index b3c1fa17d..447edd140 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_scrollToBottomButton_snapshotHighUnreadCount.rightToLeftLayout-default.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_scrollToBottomButton_snapshotHighUnreadCount.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_scrollToBottomButton_snapshotHighUnreadCount.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_scrollToBottomButton_snapshotHighUnreadCount.small-dark.png index c36dbd088..7510190bb 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_scrollToBottomButton_snapshotHighUnreadCount.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_scrollToBottomButton_snapshotHighUnreadCount.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_scrollToBottomButton_snapshotUnreadCount.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_scrollToBottomButton_snapshotUnreadCount.default-light.png index c55a6980f..7dbe0114c 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_scrollToBottomButton_snapshotUnreadCount.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_scrollToBottomButton_snapshotUnreadCount.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_scrollToBottomButton_snapshotUnreadCount.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_scrollToBottomButton_snapshotUnreadCount.extraExtraExtraLarge-light.png index 6d9af229d..11cde8db2 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_scrollToBottomButton_snapshotUnreadCount.extraExtraExtraLarge-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_scrollToBottomButton_snapshotUnreadCount.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_scrollToBottomButton_snapshotUnreadCount.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_scrollToBottomButton_snapshotUnreadCount.rightToLeftLayout-default.png index bba203b89..a1bb28adb 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_scrollToBottomButton_snapshotUnreadCount.rightToLeftLayout-default.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_scrollToBottomButton_snapshotUnreadCount.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_scrollToBottomButton_snapshotUnreadCount.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_scrollToBottomButton_snapshotUnreadCount.small-dark.png index 304393531..180ea885d 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_scrollToBottomButton_snapshotUnreadCount.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageListView_Tests/test_scrollToBottomButton_snapshotUnreadCount.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_allAnnotations_inThread_snapshot.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_allAnnotations_inThread_snapshot.default-light.png index 18295d16b..0334444da 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_allAnnotations_inThread_snapshot.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_allAnnotations_inThread_snapshot.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_allAnnotations_inThread_snapshot.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_allAnnotations_inThread_snapshot.extraExtraExtraLarge-light.png index 97eb5d9f1..98dbb88fb 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_allAnnotations_inThread_snapshot.extraExtraExtraLarge-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_allAnnotations_inThread_snapshot.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_allAnnotations_inThread_snapshot.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_allAnnotations_inThread_snapshot.rightToLeftLayout-default.png index c4a990c44..af3565cb6 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_allAnnotations_inThread_snapshot.rightToLeftLayout-default.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_allAnnotations_inThread_snapshot.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_allAnnotations_inThread_snapshot.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_allAnnotations_inThread_snapshot.small-dark.png index 6d13be2a7..82ee24779 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_allAnnotations_inThread_snapshot.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_allAnnotations_inThread_snapshot.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_allAnnotations_snapshot.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_allAnnotations_snapshot.default-light.png index 43641c716..35b596b57 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_allAnnotations_snapshot.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_allAnnotations_snapshot.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_allAnnotations_snapshot.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_allAnnotations_snapshot.extraExtraExtraLarge-light.png index 46ad41609..97369901d 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_allAnnotations_snapshot.extraExtraExtraLarge-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_allAnnotations_snapshot.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_allAnnotations_snapshot.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_allAnnotations_snapshot.rightToLeftLayout-default.png index 1c086f71e..de1b83598 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_allAnnotations_snapshot.rightToLeftLayout-default.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_allAnnotations_snapshot.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_allAnnotations_snapshot.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_allAnnotations_snapshot.small-dark.png index 20c876d83..ea11468bb 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_allAnnotations_snapshot.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_allAnnotations_snapshot.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_pinnedAnnotation_snapshot.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_pinnedAnnotation_snapshot.default-light.png index 7152d480a..5436b82c5 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_pinnedAnnotation_snapshot.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_pinnedAnnotation_snapshot.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_pinnedAnnotation_snapshot.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_pinnedAnnotation_snapshot.extraExtraExtraLarge-light.png index f6bf027eb..a25f3b833 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_pinnedAnnotation_snapshot.extraExtraExtraLarge-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_pinnedAnnotation_snapshot.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_pinnedAnnotation_snapshot.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_pinnedAnnotation_snapshot.rightToLeftLayout-default.png index e9b4500f2..ccd74ae2e 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_pinnedAnnotation_snapshot.rightToLeftLayout-default.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_pinnedAnnotation_snapshot.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_pinnedAnnotation_snapshot.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_pinnedAnnotation_snapshot.small-dark.png index ebe17e1db..1e69d9fc3 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_pinnedAnnotation_snapshot.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_pinnedAnnotation_snapshot.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_pinnedByYouAnnotation_snapshot.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_pinnedByYouAnnotation_snapshot.default-light.png new file mode 100644 index 000000000..03f78af8b Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_pinnedByYouAnnotation_snapshot.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_pinnedByYouAnnotation_snapshot.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_pinnedByYouAnnotation_snapshot.extraExtraExtraLarge-light.png new file mode 100644 index 000000000..2231a8c64 Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_pinnedByYouAnnotation_snapshot.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_pinnedByYouAnnotation_snapshot.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_pinnedByYouAnnotation_snapshot.rightToLeftLayout-default.png new file mode 100644 index 000000000..554e1785f Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_pinnedByYouAnnotation_snapshot.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_pinnedByYouAnnotation_snapshot.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_pinnedByYouAnnotation_snapshot.small-dark.png new file mode 100644 index 000000000..f286c78f9 Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_pinnedByYouAnnotation_snapshot.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_reminderAnnotation_snapshot.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_reminderAnnotation_snapshot.default-light.png index 1db067963..3894e1e6d 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_reminderAnnotation_snapshot.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_reminderAnnotation_snapshot.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_reminderAnnotation_snapshot.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_reminderAnnotation_snapshot.extraExtraExtraLarge-light.png index 1db067963..e61d088d6 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_reminderAnnotation_snapshot.extraExtraExtraLarge-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_reminderAnnotation_snapshot.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_reminderAnnotation_snapshot.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_reminderAnnotation_snapshot.rightToLeftLayout-default.png index 1db067963..d1a7a3511 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_reminderAnnotation_snapshot.rightToLeftLayout-default.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_reminderAnnotation_snapshot.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_reminderAnnotation_snapshot.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_reminderAnnotation_snapshot.small-dark.png index 6ad220356..e24ce967b 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_reminderAnnotation_snapshot.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_reminderAnnotation_snapshot.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_repliedToThreadAnnotation_snapshot.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_repliedToThreadAnnotation_snapshot.default-light.png index 826fcbf30..f1e10b4e2 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_repliedToThreadAnnotation_snapshot.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_repliedToThreadAnnotation_snapshot.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_repliedToThreadAnnotation_snapshot.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_repliedToThreadAnnotation_snapshot.extraExtraExtraLarge-light.png index fa7cfac33..39cbb81cc 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_repliedToThreadAnnotation_snapshot.extraExtraExtraLarge-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_repliedToThreadAnnotation_snapshot.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_repliedToThreadAnnotation_snapshot.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_repliedToThreadAnnotation_snapshot.rightToLeftLayout-default.png index 4f27b793c..85e75ecff 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_repliedToThreadAnnotation_snapshot.rightToLeftLayout-default.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_repliedToThreadAnnotation_snapshot.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_repliedToThreadAnnotation_snapshot.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_repliedToThreadAnnotation_snapshot.small-dark.png index 48b0ab6c2..f7248994a 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_repliedToThreadAnnotation_snapshot.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_repliedToThreadAnnotation_snapshot.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_sentInChannelAnnotation_snapshot.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_sentInChannelAnnotation_snapshot.default-light.png index 2273eb9db..c6d92a63d 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_sentInChannelAnnotation_snapshot.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_sentInChannelAnnotation_snapshot.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_sentInChannelAnnotation_snapshot.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_sentInChannelAnnotation_snapshot.extraExtraExtraLarge-light.png index abfcd5418..9938a7a95 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_sentInChannelAnnotation_snapshot.extraExtraExtraLarge-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_sentInChannelAnnotation_snapshot.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_sentInChannelAnnotation_snapshot.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_sentInChannelAnnotation_snapshot.rightToLeftLayout-default.png index 6b0e1a4ab..8f1f13fa3 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_sentInChannelAnnotation_snapshot.rightToLeftLayout-default.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_sentInChannelAnnotation_snapshot.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_sentInChannelAnnotation_snapshot.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_sentInChannelAnnotation_snapshot.small-dark.png index 49037f48f..8b3c8d749 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_sentInChannelAnnotation_snapshot.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_sentInChannelAnnotation_snapshot.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_translatedAnnotation_snapshot.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_translatedAnnotation_snapshot.default-light.png index 548ae1de1..b8f9e501c 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_translatedAnnotation_snapshot.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_translatedAnnotation_snapshot.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_translatedAnnotation_snapshot.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_translatedAnnotation_snapshot.extraExtraExtraLarge-light.png index 00e3f0c72..bf558f440 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_translatedAnnotation_snapshot.extraExtraExtraLarge-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_translatedAnnotation_snapshot.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_translatedAnnotation_snapshot.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_translatedAnnotation_snapshot.rightToLeftLayout-default.png index b52b0da8d..c91d5c255 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_translatedAnnotation_snapshot.rightToLeftLayout-default.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_translatedAnnotation_snapshot.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_translatedAnnotation_snapshot.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_translatedAnnotation_snapshot.small-dark.png index 3212e2200..d4f9dd5dc 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_translatedAnnotation_snapshot.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageTopView_Tests/test_translatedAnnotation_snapshot.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageViewMultiRowReactions_Tests/test_messageViewMultiRowReactions_snapshot.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageViewMultiRowReactions_Tests/test_messageViewMultiRowReactions_snapshot.1.png index c36058c32..c96d6e8d4 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageViewMultiRowReactions_Tests/test_messageViewMultiRowReactions_snapshot.1.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageViewMultiRowReactions_Tests/test_messageViewMultiRowReactions_snapshot.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_code_inlineOnMultipleLines.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_code_inlineOnMultipleLines.small-dark.png index d717a94a1..e608bf689 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_code_inlineOnMultipleLines.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_code_inlineOnMultipleLines.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_deletedMessageView_snapshot.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_deletedMessageView_snapshot.1.png index 38b582bd9..886b3b7d9 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_deletedMessageView_snapshot.1.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_deletedMessageView_snapshot.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_linkAttachmentView_customColors_snapshot.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_linkAttachmentView_customColors_snapshot.1.png index a9b203653..465894818 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_linkAttachmentView_customColors_snapshot.1.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_linkAttachmentView_customColors_snapshot.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_linkAttachmentView_shouldNotRenderLinkPreviewWithOtherAttachments.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_linkAttachmentView_shouldNotRenderLinkPreviewWithOtherAttachments.1.png index a185d84e2..9c7b690f0 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_linkAttachmentView_shouldNotRenderLinkPreviewWithOtherAttachments.1.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_linkAttachmentView_shouldNotRenderLinkPreviewWithOtherAttachments.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_linkAttachmentView_snapshot.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_linkAttachmentView_snapshot.1.png index fbb2f1cf5..acbc1f2ad 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_linkAttachmentView_snapshot.1.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_linkAttachmentView_snapshot.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_linkDetection_markdownPlainAndMention.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_linkDetection_markdownPlainAndMention.small-dark.png index 1287ca7f6..ebbbd6289 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_linkDetection_markdownPlainAndMention.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_linkDetection_markdownPlainAndMention.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_markdown_code.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_markdown_code.small-dark.png index 128c6dfee..bf6c43b7e 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_markdown_code.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_markdown_code.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_markdown_headers.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_markdown_headers.default-light.png index 6aa08971b..3cc3b23a2 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_markdown_headers.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_markdown_headers.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_markdown_headers.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_markdown_headers.extraExtraExtraLarge-light.png index 960d4b0a9..d58ecfdfd 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_markdown_headers.extraExtraExtraLarge-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_markdown_headers.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_markdown_headers.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_markdown_headers.rightToLeftLayout-default.png index 42af25436..a9a18725d 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_markdown_headers.rightToLeftLayout-default.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_markdown_headers.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_markdown_headers.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_markdown_headers.small-dark.png index 76c535536..57e3bd2a0 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_markdown_headers.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_markdown_headers.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_markdown_linkSupportDisabled.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_markdown_linkSupportDisabled.1.png index 38f17e7ad..73c22269b 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_markdown_linkSupportDisabled.1.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_markdown_linkSupportDisabled.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_markdown_links.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_markdown_links.small-dark.png index 3a54fbd0e..5ce467c96 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_markdown_links.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_markdown_links.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_markdown_links_customColor.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_markdown_links_customColor.small-dark.png index 57f049958..176d0fb0a 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_markdown_links_customColor.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_markdown_links_customColor.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_markdown_links_inLists.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_markdown_links_inLists.small-dark.png index dc41c860c..e473798d6 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_markdown_links_inLists.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_markdown_links_inLists.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_markdown_links_markdownDisabled.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_markdown_links_markdownDisabled.small-dark.png index d765adcc1..9c57933e0 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_markdown_links_markdownDisabled.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_markdown_links_markdownDisabled.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_markdown_mixedLists_nested.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_markdown_mixedLists_nested.small-dark.png index b90eff7a0..4f60581fd 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_markdown_mixedLists_nested.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_markdown_mixedLists_nested.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_markdown_orderedList_nested_wrappedTextItem.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_markdown_orderedList_nested_wrappedTextItem.small-dark.png index 1ba9a0c9e..da7619531 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_markdown_orderedList_nested_wrappedTextItem.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_markdown_orderedList_nested_wrappedTextItem.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_markdown_orderedLists.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_markdown_orderedLists.small-dark.png index a61ddbbe6..bf036af53 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_markdown_orderedLists.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_markdown_orderedLists.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_markdown_orderedLists_nested.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_markdown_orderedLists_nested.small-dark.png index ad55a8586..6c1a75b01 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_markdown_orderedLists_nested.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_markdown_orderedLists_nested.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_markdown_quote.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_markdown_quote.default-light.png index 5f1a63712..c19bd45ec 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_markdown_quote.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_markdown_quote.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_markdown_quote.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_markdown_quote.extraExtraExtraLarge-light.png index 89f00945a..6617ef961 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_markdown_quote.extraExtraExtraLarge-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_markdown_quote.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_markdown_quote.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_markdown_quote.rightToLeftLayout-default.png index 9232ee024..2e546cc9c 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_markdown_quote.rightToLeftLayout-default.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_markdown_quote.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_markdown_quote.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_markdown_quote.small-dark.png index f59ccf901..b2a6ae6b3 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_markdown_quote.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_markdown_quote.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_markdown_quote_multipleLines.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_markdown_quote_multipleLines.default-light.png index 204c0a592..5ba7cd4d4 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_markdown_quote_multipleLines.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_markdown_quote_multipleLines.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_markdown_quote_multipleLines.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_markdown_quote_multipleLines.extraExtraExtraLarge-light.png index 6dff579b1..fce8d5631 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_markdown_quote_multipleLines.extraExtraExtraLarge-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_markdown_quote_multipleLines.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_markdown_quote_multipleLines.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_markdown_quote_multipleLines.rightToLeftLayout-default.png index 4924186d9..ed2e0f7cb 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_markdown_quote_multipleLines.rightToLeftLayout-default.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_markdown_quote_multipleLines.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_markdown_quote_multipleLines.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_markdown_quote_multipleLines.small-dark.png index af52a67d5..23faacf04 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_markdown_quote_multipleLines.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_markdown_quote_multipleLines.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_markdown_quote_separate.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_markdown_quote_separate.default-light.png index b4fd13a3a..0fbb517b5 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_markdown_quote_separate.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_markdown_quote_separate.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_markdown_quote_separate.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_markdown_quote_separate.extraExtraExtraLarge-light.png index 8eff1c244..cd081384c 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_markdown_quote_separate.extraExtraExtraLarge-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_markdown_quote_separate.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_markdown_quote_separate.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_markdown_quote_separate.rightToLeftLayout-default.png index c7deaed28..516c33c86 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_markdown_quote_separate.rightToLeftLayout-default.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_markdown_quote_separate.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_markdown_quote_separate.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_markdown_quote_separate.small-dark.png index 8162aaab5..94e8c7e66 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_markdown_quote_separate.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_markdown_quote_separate.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_markdown_text.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_markdown_text.small-dark.png index d4bba6e92..c1eb376ae 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_markdown_text.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_markdown_text.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_markdown_thematicBreak.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_markdown_thematicBreak.small-dark.png index 8fd903057..b41402e49 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_markdown_thematicBreak.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_markdown_thematicBreak.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_markdown_unorderedLists.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_markdown_unorderedLists.small-dark.png index 2fb4cf801..09598c091 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_markdown_unorderedLists.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_markdown_unorderedLists.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_markdown_unorderedLists_nested.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_markdown_unorderedLists_nested.small-dark.png index d5e486dc3..a2d0d0c82 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_markdown_unorderedLists_nested.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_markdown_unorderedLists_nested.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewFileText_snapshot.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewFileText_snapshot.1.png index 17da5680e..fe7a5267a 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewFileText_snapshot.1.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewFileText_snapshot.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewFile_snapshot.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewFile_snapshot.1.png index b464c824b..c005a3a77 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewFile_snapshot.1.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewFile_snapshot.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewGiphy_snapshot.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewGiphy_snapshot.1.png index 6c67aff53..024c69743 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewGiphy_snapshot.1.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewGiphy_snapshot.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewImage_snapshot.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewImage_snapshot.1.png index 8da76fa75..f33e1dd21 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewImage_snapshot.1.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewImage_snapshot.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewImage_snapshot2Images.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewImage_snapshot2Images.1.png index 5d2ca1253..0393f0f9e 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewImage_snapshot2Images.1.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewImage_snapshot2Images.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewImage_snapshot3Images.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewImage_snapshot3Images.1.png index e018dfa88..da7e7b85e 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewImage_snapshot3Images.1.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewImage_snapshot3Images.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewImage_snapshot3ImagesAndVideo.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewImage_snapshot3ImagesAndVideo.1.png index 338e8954f..764b31e26 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewImage_snapshot3ImagesAndVideo.1.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewImage_snapshot3ImagesAndVideo.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewImage_snapshotQuoted.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewImage_snapshotQuoted.1.png index ab7b9890a..75914f897 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewImage_snapshotQuoted.1.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewImage_snapshotQuoted.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewPendingGiphy_snapshot.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewPendingGiphy_snapshot.default-light.png index 98a50a0b1..9fd216e59 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewPendingGiphy_snapshot.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewPendingGiphy_snapshot.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewPendingGiphy_snapshot.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewPendingGiphy_snapshot.extraExtraExtraLarge-light.png index 6a672c12d..7e7ba2366 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewPendingGiphy_snapshot.extraExtraExtraLarge-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewPendingGiphy_snapshot.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewPendingGiphy_snapshot.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewPendingGiphy_snapshot.rightToLeftLayout-default.png index 1558c64e2..c230578fb 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewPendingGiphy_snapshot.rightToLeftLayout-default.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewPendingGiphy_snapshot.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewPendingGiphy_snapshot.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewPendingGiphy_snapshot.small-dark.png index 110a9ca1c..145875be9 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewPendingGiphy_snapshot.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewPendingGiphy_snapshot.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewPortraitImageLongText_snapshot.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewPortraitImageLongText_snapshot.1.png new file mode 100644 index 000000000..41bb02834 Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewPortraitImageLongText_snapshot.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewPortraitImage_snapshot.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewPortraitImage_snapshot.1.png new file mode 100644 index 000000000..25a62b71b Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewPortraitImage_snapshot.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewQuoted_singleFileAttachment_snapshot.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewQuoted_singleFileAttachment_snapshot.default-light.png new file mode 100644 index 000000000..a9c2bf307 Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewQuoted_singleFileAttachment_snapshot.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewQuoted_singleFileAttachment_snapshot.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewQuoted_singleFileAttachment_snapshot.extraExtraExtraLarge-light.png new file mode 100644 index 000000000..f789f9396 Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewQuoted_singleFileAttachment_snapshot.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewQuoted_singleFileAttachment_snapshot.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewQuoted_singleFileAttachment_snapshot.rightToLeftLayout-default.png new file mode 100644 index 000000000..c39b1460f Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewQuoted_singleFileAttachment_snapshot.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewQuoted_singleFileAttachment_snapshot.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewQuoted_singleFileAttachment_snapshot.small-dark.png new file mode 100644 index 000000000..606c9b684 Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewQuoted_singleFileAttachment_snapshot.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewQuoted_singleImageAttachment_snapshot.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewQuoted_singleImageAttachment_snapshot.default-light.png new file mode 100644 index 000000000..68f9aff29 Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewQuoted_singleImageAttachment_snapshot.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewQuoted_singleImageAttachment_snapshot.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewQuoted_singleImageAttachment_snapshot.extraExtraExtraLarge-light.png new file mode 100644 index 000000000..c35caa185 Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewQuoted_singleImageAttachment_snapshot.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewQuoted_singleImageAttachment_snapshot.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewQuoted_singleImageAttachment_snapshot.rightToLeftLayout-default.png new file mode 100644 index 000000000..1f062513e Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewQuoted_singleImageAttachment_snapshot.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewQuoted_singleImageAttachment_snapshot.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewQuoted_singleImageAttachment_snapshot.small-dark.png new file mode 100644 index 000000000..42e64fb45 Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewQuoted_singleImageAttachment_snapshot.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewText_sendingFailed_multiLine_snapshot.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewText_sendingFailed_multiLine_snapshot.1.png new file mode 100644 index 000000000..47f3e225f Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewText_sendingFailed_multiLine_snapshot.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewText_sendingFailed_singleLine_snapshot.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewText_sendingFailed_singleLine_snapshot.1.png new file mode 100644 index 000000000..71811cdee Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewText_sendingFailed_singleLine_snapshot.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVideo_snapshot.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVideo_snapshot.1.png index 9848e8a8a..e1f7f1d63 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVideo_snapshot.1.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVideo_snapshot.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingFromMeTheming_snapshot.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingFromMeTheming_snapshot.default-light.png index 96e2ba4c1..2f2c9a281 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingFromMeTheming_snapshot.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingFromMeTheming_snapshot.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingFromMe_snapshot.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingFromMe_snapshot.default-light.png index 73b548ff7..b6347be7a 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingFromMe_snapshot.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingFromMe_snapshot.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingFromMe_snapshot.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingFromMe_snapshot.extraExtraExtraLarge-light.png index fbdba4458..bd9e6d657 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingFromMe_snapshot.extraExtraExtraLarge-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingFromMe_snapshot.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingFromMe_snapshot.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingFromMe_snapshot.rightToLeftLayout-default.png index e12d986c9..69b6d09fa 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingFromMe_snapshot.rightToLeftLayout-default.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingFromMe_snapshot.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingFromMe_snapshot.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingFromMe_snapshot.small-dark.png index 8f966ca50..72c2eeebb 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingFromMe_snapshot.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingFromMe_snapshot.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingFromParticipant_snapshot.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingFromParticipant_snapshot.default-light.png index bc02c7d6e..e09d07570 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingFromParticipant_snapshot.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingFromParticipant_snapshot.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingFromParticipant_snapshot.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingFromParticipant_snapshot.extraExtraExtraLarge-light.png index fc714210a..03894d9f2 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingFromParticipant_snapshot.extraExtraExtraLarge-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingFromParticipant_snapshot.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingFromParticipant_snapshot.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingFromParticipant_snapshot.rightToLeftLayout-default.png index 25ff39697..7cf5a9aec 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingFromParticipant_snapshot.rightToLeftLayout-default.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingFromParticipant_snapshot.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingFromParticipant_snapshot.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingFromParticipant_snapshot.small-dark.png index 5633a1675..3399ed665 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingFromParticipant_snapshot.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingFromParticipant_snapshot.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingQuotedFromMe_snapshot.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingQuotedFromMe_snapshot.default-light.png new file mode 100644 index 000000000..82bff5653 Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingQuotedFromMe_snapshot.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingQuotedFromMe_snapshot.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingQuotedFromMe_snapshot.extraExtraExtraLarge-light.png new file mode 100644 index 000000000..79f62e6b4 Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingQuotedFromMe_snapshot.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingQuotedFromMe_snapshot.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingQuotedFromMe_snapshot.rightToLeftLayout-default.png new file mode 100644 index 000000000..63f614270 Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingQuotedFromMe_snapshot.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingQuotedFromMe_snapshot.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingQuotedFromMe_snapshot.small-dark.png new file mode 100644 index 000000000..40d4e962b Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingQuotedFromMe_snapshot.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingQuotedFromParticipant_snapshot.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingQuotedFromParticipant_snapshot.default-light.png new file mode 100644 index 000000000..e48833b87 Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingQuotedFromParticipant_snapshot.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingQuotedFromParticipant_snapshot.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingQuotedFromParticipant_snapshot.extraExtraExtraLarge-light.png new file mode 100644 index 000000000..9326d4cc8 Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingQuotedFromParticipant_snapshot.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingQuotedFromParticipant_snapshot.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingQuotedFromParticipant_snapshot.rightToLeftLayout-default.png new file mode 100644 index 000000000..ebd991409 Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingQuotedFromParticipant_snapshot.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingQuotedFromParticipant_snapshot.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingQuotedFromParticipant_snapshot.small-dark.png new file mode 100644 index 000000000..21bf42bd3 Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingQuotedFromParticipant_snapshot.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingQuotedWithTextFromMe_snapshot.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingQuotedWithTextFromMe_snapshot.default-light.png new file mode 100644 index 000000000..45c3c7802 Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingQuotedWithTextFromMe_snapshot.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingQuotedWithTextFromMe_snapshot.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingQuotedWithTextFromMe_snapshot.extraExtraExtraLarge-light.png new file mode 100644 index 000000000..7c9781bdc Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingQuotedWithTextFromMe_snapshot.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingQuotedWithTextFromMe_snapshot.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingQuotedWithTextFromMe_snapshot.rightToLeftLayout-default.png new file mode 100644 index 000000000..371f516df Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingQuotedWithTextFromMe_snapshot.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingQuotedWithTextFromMe_snapshot.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingQuotedWithTextFromMe_snapshot.small-dark.png new file mode 100644 index 000000000..7f99c8cfb Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingQuotedWithTextFromMe_snapshot.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingQuotedWithTextFromParticipant_snapshot.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingQuotedWithTextFromParticipant_snapshot.default-light.png new file mode 100644 index 000000000..a713b668d Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingQuotedWithTextFromParticipant_snapshot.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingQuotedWithTextFromParticipant_snapshot.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingQuotedWithTextFromParticipant_snapshot.extraExtraExtraLarge-light.png new file mode 100644 index 000000000..15ba39d69 Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingQuotedWithTextFromParticipant_snapshot.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingQuotedWithTextFromParticipant_snapshot.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingQuotedWithTextFromParticipant_snapshot.rightToLeftLayout-default.png new file mode 100644 index 000000000..cf1531264 Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingQuotedWithTextFromParticipant_snapshot.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingQuotedWithTextFromParticipant_snapshot.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingQuotedWithTextFromParticipant_snapshot.small-dark.png new file mode 100644 index 000000000..bfa762dfc Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingQuotedWithTextFromParticipant_snapshot.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingWithTextFromMeMultiple_snapshot.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingWithTextFromMeMultiple_snapshot.default-light.png index 21997a1c9..4af21bbf5 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingWithTextFromMeMultiple_snapshot.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingWithTextFromMeMultiple_snapshot.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingWithTextFromMeMultiple_snapshot.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingWithTextFromMeMultiple_snapshot.extraExtraExtraLarge-light.png index 6a932de01..ff2eab4e8 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingWithTextFromMeMultiple_snapshot.extraExtraExtraLarge-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingWithTextFromMeMultiple_snapshot.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingWithTextFromMeMultiple_snapshot.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingWithTextFromMeMultiple_snapshot.rightToLeftLayout-default.png index 9847dc9f2..9ccf2a143 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingWithTextFromMeMultiple_snapshot.rightToLeftLayout-default.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingWithTextFromMeMultiple_snapshot.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingWithTextFromMeMultiple_snapshot.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingWithTextFromMeMultiple_snapshot.small-dark.png index 5dbf0fcb0..1d806b54a 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingWithTextFromMeMultiple_snapshot.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingWithTextFromMeMultiple_snapshot.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingWithTextFromMe_snapshot.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingWithTextFromMe_snapshot.default-light.png index b5d49d7ec..ee05e7d31 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingWithTextFromMe_snapshot.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingWithTextFromMe_snapshot.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingWithTextFromMe_snapshot.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingWithTextFromMe_snapshot.extraExtraExtraLarge-light.png index c0b53b4d4..053ca78ff 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingWithTextFromMe_snapshot.extraExtraExtraLarge-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingWithTextFromMe_snapshot.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingWithTextFromMe_snapshot.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingWithTextFromMe_snapshot.rightToLeftLayout-default.png index a2048c950..450e3fcf0 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingWithTextFromMe_snapshot.rightToLeftLayout-default.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingWithTextFromMe_snapshot.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingWithTextFromMe_snapshot.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingWithTextFromMe_snapshot.small-dark.png index 263327755..ba8b73e69 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingWithTextFromMe_snapshot.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingWithTextFromMe_snapshot.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingWithTextFromParticipantMultiple_snapshot.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingWithTextFromParticipantMultiple_snapshot.default-light.png index c47ab13cc..fd9200545 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingWithTextFromParticipantMultiple_snapshot.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingWithTextFromParticipantMultiple_snapshot.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingWithTextFromParticipantMultiple_snapshot.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingWithTextFromParticipantMultiple_snapshot.extraExtraExtraLarge-light.png index 818f5bec8..a944c7143 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingWithTextFromParticipantMultiple_snapshot.extraExtraExtraLarge-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingWithTextFromParticipantMultiple_snapshot.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingWithTextFromParticipantMultiple_snapshot.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingWithTextFromParticipantMultiple_snapshot.rightToLeftLayout-default.png index 6188912be..16dc24207 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingWithTextFromParticipantMultiple_snapshot.rightToLeftLayout-default.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingWithTextFromParticipantMultiple_snapshot.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingWithTextFromParticipantMultiple_snapshot.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingWithTextFromParticipantMultiple_snapshot.small-dark.png index dd3998b35..7537451a6 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingWithTextFromParticipantMultiple_snapshot.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingWithTextFromParticipantMultiple_snapshot.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingWithTextFromParticipant_snapshot.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingWithTextFromParticipant_snapshot.default-light.png index 09e97a874..2ebb36ab9 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingWithTextFromParticipant_snapshot.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingWithTextFromParticipant_snapshot.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingWithTextFromParticipant_snapshot.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingWithTextFromParticipant_snapshot.extraExtraExtraLarge-light.png index 76f52b261..2c96cb22d 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingWithTextFromParticipant_snapshot.extraExtraExtraLarge-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingWithTextFromParticipant_snapshot.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingWithTextFromParticipant_snapshot.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingWithTextFromParticipant_snapshot.rightToLeftLayout-default.png index dc594bb89..59781ec51 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingWithTextFromParticipant_snapshot.rightToLeftLayout-default.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingWithTextFromParticipant_snapshot.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingWithTextFromParticipant_snapshot.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingWithTextFromParticipant_snapshot.small-dark.png index 9f0aa3156..4b619e332 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingWithTextFromParticipant_snapshot.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_messageViewVoiceRecordingWithTextFromParticipant_snapshot.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_text_withMultiline.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_text_withMultiline.small-dark.png index b2429b042..8964ca805 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_text_withMultiline.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_text_withMultiline.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_voiceRecordingViewPlaying_snapshot.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_voiceRecordingViewPlaying_snapshot.default-light.png index cc61ad6d3..02b74b4e1 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_voiceRecordingViewPlaying_snapshot.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/MessageView_Tests/test_voiceRecordingViewPlaying_snapshot.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAllOptionsView_Tests/test_pollAllOptionsView_closedPoll.default-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAllOptionsView_Tests/test_pollAllOptionsView_closedPoll.default-dark.png index 64691b6b9..7b67bb892 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAllOptionsView_Tests/test_pollAllOptionsView_closedPoll.default-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAllOptionsView_Tests/test_pollAllOptionsView_closedPoll.default-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAllOptionsView_Tests/test_pollAllOptionsView_closedPoll.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAllOptionsView_Tests/test_pollAllOptionsView_closedPoll.default-light.png index 49fe9dc57..77dc7a60e 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAllOptionsView_Tests/test_pollAllOptionsView_closedPoll.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAllOptionsView_Tests/test_pollAllOptionsView_closedPoll.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAllOptionsView_Tests/test_pollAllOptionsView_defaultPoll.default-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAllOptionsView_Tests/test_pollAllOptionsView_defaultPoll.default-dark.png index b988da09f..dda5f46d8 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAllOptionsView_Tests/test_pollAllOptionsView_defaultPoll.default-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAllOptionsView_Tests/test_pollAllOptionsView_defaultPoll.default-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAllOptionsView_Tests/test_pollAllOptionsView_defaultPoll.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAllOptionsView_Tests/test_pollAllOptionsView_defaultPoll.default-light.png index 4169d6045..99c17559a 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAllOptionsView_Tests/test_pollAllOptionsView_defaultPoll.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAllOptionsView_Tests/test_pollAllOptionsView_defaultPoll.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAllOptionsView_Tests/test_pollAllOptionsView_manyOptions.default-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAllOptionsView_Tests/test_pollAllOptionsView_manyOptions.default-dark.png index b91e3b6ce..cb135a2f4 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAllOptionsView_Tests/test_pollAllOptionsView_manyOptions.default-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAllOptionsView_Tests/test_pollAllOptionsView_manyOptions.default-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAllOptionsView_Tests/test_pollAllOptionsView_manyOptions.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAllOptionsView_Tests/test_pollAllOptionsView_manyOptions.default-light.png index 3c0a0cadf..2f686ce3d 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAllOptionsView_Tests/test_pollAllOptionsView_manyOptions.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAllOptionsView_Tests/test_pollAllOptionsView_manyOptions.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAllOptionsView_Tests/test_pollAllOptionsView_multipleOptionsWithVotes.default-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAllOptionsView_Tests/test_pollAllOptionsView_multipleOptionsWithVotes.default-dark.png index 2700d41a1..73dedbcf1 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAllOptionsView_Tests/test_pollAllOptionsView_multipleOptionsWithVotes.default-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAllOptionsView_Tests/test_pollAllOptionsView_multipleOptionsWithVotes.default-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAllOptionsView_Tests/test_pollAllOptionsView_multipleOptionsWithVotes.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAllOptionsView_Tests/test_pollAllOptionsView_multipleOptionsWithVotes.default-light.png index 4c58a65c6..6cb158b62 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAllOptionsView_Tests/test_pollAllOptionsView_multipleOptionsWithVotes.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAllOptionsView_Tests/test_pollAllOptionsView_multipleOptionsWithVotes.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAllOptionsView_Tests/test_pollAllOptionsView_optionWithZeroVotes.default-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAllOptionsView_Tests/test_pollAllOptionsView_optionWithZeroVotes.default-dark.png index 48235a983..30a286ea6 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAllOptionsView_Tests/test_pollAllOptionsView_optionWithZeroVotes.default-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAllOptionsView_Tests/test_pollAllOptionsView_optionWithZeroVotes.default-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAllOptionsView_Tests/test_pollAllOptionsView_optionWithZeroVotes.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAllOptionsView_Tests/test_pollAllOptionsView_optionWithZeroVotes.default-light.png index 34175d643..7ea5a010e 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAllOptionsView_Tests/test_pollAllOptionsView_optionWithZeroVotes.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAllOptionsView_Tests/test_pollAllOptionsView_optionWithZeroVotes.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAllOptionsView_Tests/test_pollAllOptionsView_uniqueVote.default-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAllOptionsView_Tests/test_pollAllOptionsView_uniqueVote.default-dark.png index b988da09f..dda5f46d8 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAllOptionsView_Tests/test_pollAllOptionsView_uniqueVote.default-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAllOptionsView_Tests/test_pollAllOptionsView_uniqueVote.default-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAllOptionsView_Tests/test_pollAllOptionsView_uniqueVote.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAllOptionsView_Tests/test_pollAllOptionsView_uniqueVote.default-light.png index 4169d6045..99c17559a 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAllOptionsView_Tests/test_pollAllOptionsView_uniqueVote.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAllOptionsView_Tests/test_pollAllOptionsView_uniqueVote.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAttachmentView_Tests/test_pollAttachmentView_allComments.default-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAttachmentView_Tests/test_pollAttachmentView_allComments.default-dark.png index ced827dd0..e1b539acd 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAttachmentView_Tests/test_pollAttachmentView_allComments.default-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAttachmentView_Tests/test_pollAttachmentView_allComments.default-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAttachmentView_Tests/test_pollAttachmentView_allComments.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAttachmentView_Tests/test_pollAttachmentView_allComments.default-light.png index b850e832a..6abb66970 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAttachmentView_Tests/test_pollAttachmentView_allComments.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAttachmentView_Tests/test_pollAttachmentView_allComments.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAttachmentView_Tests/test_pollAttachmentView_allOptions.default-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAttachmentView_Tests/test_pollAttachmentView_allOptions.default-dark.png index b988da09f..dda5f46d8 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAttachmentView_Tests/test_pollAttachmentView_allOptions.default-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAttachmentView_Tests/test_pollAttachmentView_allOptions.default-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAttachmentView_Tests/test_pollAttachmentView_allOptions.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAttachmentView_Tests/test_pollAttachmentView_allOptions.default-light.png index 4169d6045..99c17559a 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAttachmentView_Tests/test_pollAttachmentView_allOptions.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAttachmentView_Tests/test_pollAttachmentView_allOptions.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAttachmentView_Tests/test_pollAttachmentView_allVotes.default-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAttachmentView_Tests/test_pollAttachmentView_allVotes.default-dark.png index dc7b87c02..669aba45e 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAttachmentView_Tests/test_pollAttachmentView_allVotes.default-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAttachmentView_Tests/test_pollAttachmentView_allVotes.default-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAttachmentView_Tests/test_pollAttachmentView_closedPoll.default-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAttachmentView_Tests/test_pollAttachmentView_closedPoll.default-dark.png index b15559188..3aeab1b28 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAttachmentView_Tests/test_pollAttachmentView_closedPoll.default-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAttachmentView_Tests/test_pollAttachmentView_closedPoll.default-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAttachmentView_Tests/test_pollAttachmentView_closedPoll.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAttachmentView_Tests/test_pollAttachmentView_closedPoll.default-light.png index bca597d8b..d2eccbfd7 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAttachmentView_Tests/test_pollAttachmentView_closedPoll.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAttachmentView_Tests/test_pollAttachmentView_closedPoll.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAttachmentView_Tests/test_pollAttachmentView_resultsSnapshot.default-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAttachmentView_Tests/test_pollAttachmentView_resultsSnapshot.default-dark.png index 229c64b97..274d3675d 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAttachmentView_Tests/test_pollAttachmentView_resultsSnapshot.default-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAttachmentView_Tests/test_pollAttachmentView_resultsSnapshot.default-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAttachmentView_Tests/test_pollAttachmentView_resultsSnapshot.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAttachmentView_Tests/test_pollAttachmentView_resultsSnapshot.default-light.png index 81d85da76..df78e117e 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAttachmentView_Tests/test_pollAttachmentView_resultsSnapshot.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAttachmentView_Tests/test_pollAttachmentView_resultsSnapshot.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAttachmentView_Tests/test_pollAttachmentView_snapshotCommentsAndSuggestions.default-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAttachmentView_Tests/test_pollAttachmentView_snapshotCommentsAndSuggestions.default-dark.png index 34c4eac49..fdae15364 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAttachmentView_Tests/test_pollAttachmentView_snapshotCommentsAndSuggestions.default-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAttachmentView_Tests/test_pollAttachmentView_snapshotCommentsAndSuggestions.default-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAttachmentView_Tests/test_pollAttachmentView_snapshotCommentsAndSuggestions.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAttachmentView_Tests/test_pollAttachmentView_snapshotCommentsAndSuggestions.default-light.png index f2b20ae09..d4a1deac0 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAttachmentView_Tests/test_pollAttachmentView_snapshotCommentsAndSuggestions.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAttachmentView_Tests/test_pollAttachmentView_snapshotCommentsAndSuggestions.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAttachmentView_Tests/test_pollAttachmentView_snapshotCreatedByCurrentUser.default-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAttachmentView_Tests/test_pollAttachmentView_snapshotCreatedByCurrentUser.default-dark.png index 069352fb3..6b22fb759 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAttachmentView_Tests/test_pollAttachmentView_snapshotCreatedByCurrentUser.default-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAttachmentView_Tests/test_pollAttachmentView_snapshotCreatedByCurrentUser.default-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAttachmentView_Tests/test_pollAttachmentView_snapshotCreatedByCurrentUser.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAttachmentView_Tests/test_pollAttachmentView_snapshotCreatedByCurrentUser.default-light.png index d080c9bc5..191f17f5e 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAttachmentView_Tests/test_pollAttachmentView_snapshotCreatedByCurrentUser.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAttachmentView_Tests/test_pollAttachmentView_snapshotCreatedByCurrentUser.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAttachmentView_Tests/test_pollAttachmentView_snapshotSixOptionsShowsFiveVisibleAndSeeMore.default-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAttachmentView_Tests/test_pollAttachmentView_snapshotSixOptionsShowsFiveVisibleAndSeeMore.default-dark.png index 14eb64ced..b2ad38539 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAttachmentView_Tests/test_pollAttachmentView_snapshotSixOptionsShowsFiveVisibleAndSeeMore.default-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAttachmentView_Tests/test_pollAttachmentView_snapshotSixOptionsShowsFiveVisibleAndSeeMore.default-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAttachmentView_Tests/test_pollAttachmentView_snapshotSixOptionsShowsFiveVisibleAndSeeMore.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAttachmentView_Tests/test_pollAttachmentView_snapshotSixOptionsShowsFiveVisibleAndSeeMore.default-light.png index d589f8acb..66d00aa5c 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAttachmentView_Tests/test_pollAttachmentView_snapshotSixOptionsShowsFiveVisibleAndSeeMore.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAttachmentView_Tests/test_pollAttachmentView_snapshotSixOptionsShowsFiveVisibleAndSeeMore.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAttachmentView_Tests/test_pollAttachmentView_snapshotUniqueVotes.default-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAttachmentView_Tests/test_pollAttachmentView_snapshotUniqueVotes.default-dark.png index 162355bb9..bc95afecf 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAttachmentView_Tests/test_pollAttachmentView_snapshotUniqueVotes.default-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAttachmentView_Tests/test_pollAttachmentView_snapshotUniqueVotes.default-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAttachmentView_Tests/test_pollAttachmentView_snapshotUniqueVotes.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAttachmentView_Tests/test_pollAttachmentView_snapshotUniqueVotes.default-light.png index 9fbf4d852..449b85989 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAttachmentView_Tests/test_pollAttachmentView_snapshotUniqueVotes.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollAttachmentView_Tests/test_pollAttachmentView_snapshotUniqueVotes.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollCommentsView_Tests/test_pollCommentsView_addCommentButtonVisible.default-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollCommentsView_Tests/test_pollCommentsView_addCommentButtonVisible.default-dark.png index a67601d8a..be9fa065f 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollCommentsView_Tests/test_pollCommentsView_addCommentButtonVisible.default-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollCommentsView_Tests/test_pollCommentsView_addCommentButtonVisible.default-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollCommentsView_Tests/test_pollCommentsView_addCommentButtonVisible.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollCommentsView_Tests/test_pollCommentsView_addCommentButtonVisible.default-light.png index 604d4a13d..88e1e0593 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollCommentsView_Tests/test_pollCommentsView_addCommentButtonVisible.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollCommentsView_Tests/test_pollCommentsView_addCommentButtonVisible.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollCommentsView_Tests/test_pollCommentsView_anonymousVoting.default-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollCommentsView_Tests/test_pollCommentsView_anonymousVoting.default-dark.png index cc299c9cb..5917a985a 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollCommentsView_Tests/test_pollCommentsView_anonymousVoting.default-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollCommentsView_Tests/test_pollCommentsView_anonymousVoting.default-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollCommentsView_Tests/test_pollCommentsView_anonymousVoting.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollCommentsView_Tests/test_pollCommentsView_anonymousVoting.default-light.png index 4a0ce1a3b..2977ef712 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollCommentsView_Tests/test_pollCommentsView_anonymousVoting.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollCommentsView_Tests/test_pollCommentsView_anonymousVoting.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollCommentsView_Tests/test_pollCommentsView_closedPoll.default-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollCommentsView_Tests/test_pollCommentsView_closedPoll.default-dark.png index ba093914d..d6b75be9d 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollCommentsView_Tests/test_pollCommentsView_closedPoll.default-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollCommentsView_Tests/test_pollCommentsView_closedPoll.default-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollCommentsView_Tests/test_pollCommentsView_closedPoll.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollCommentsView_Tests/test_pollCommentsView_closedPoll.default-light.png index 048acf5ff..328ce3c9f 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollCommentsView_Tests/test_pollCommentsView_closedPoll.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollCommentsView_Tests/test_pollCommentsView_closedPoll.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollCommentsView_Tests/test_pollCommentsView_longComment.default-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollCommentsView_Tests/test_pollCommentsView_longComment.default-dark.png index 45dda716a..f64b5cc11 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollCommentsView_Tests/test_pollCommentsView_longComment.default-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollCommentsView_Tests/test_pollCommentsView_longComment.default-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollCommentsView_Tests/test_pollCommentsView_longComment.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollCommentsView_Tests/test_pollCommentsView_longComment.default-light.png index 15279f678..3740c47d1 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollCommentsView_Tests/test_pollCommentsView_longComment.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollCommentsView_Tests/test_pollCommentsView_longComment.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollCommentsView_Tests/test_pollCommentsView_multipleComments.default-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollCommentsView_Tests/test_pollCommentsView_multipleComments.default-dark.png index ba093914d..d6b75be9d 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollCommentsView_Tests/test_pollCommentsView_multipleComments.default-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollCommentsView_Tests/test_pollCommentsView_multipleComments.default-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollCommentsView_Tests/test_pollCommentsView_multipleComments.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollCommentsView_Tests/test_pollCommentsView_multipleComments.default-light.png index 048acf5ff..328ce3c9f 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollCommentsView_Tests/test_pollCommentsView_multipleComments.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollCommentsView_Tests/test_pollCommentsView_multipleComments.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollCommentsView_Tests/test_pollCommentsView_ownCommentAnonymous.default-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollCommentsView_Tests/test_pollCommentsView_ownCommentAnonymous.default-dark.png index 1af7af147..6a74e6b85 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollCommentsView_Tests/test_pollCommentsView_ownCommentAnonymous.default-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollCommentsView_Tests/test_pollCommentsView_ownCommentAnonymous.default-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollCommentsView_Tests/test_pollCommentsView_ownCommentAnonymous.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollCommentsView_Tests/test_pollCommentsView_ownCommentAnonymous.default-light.png index 92fea9517..8c9feb9df 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollCommentsView_Tests/test_pollCommentsView_ownCommentAnonymous.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollCommentsView_Tests/test_pollCommentsView_ownCommentAnonymous.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollCommentsView_Tests/test_pollCommentsView_ownCommentWithUpdateButton.default-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollCommentsView_Tests/test_pollCommentsView_ownCommentWithUpdateButton.default-dark.png index 68e39e981..7595356cf 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollCommentsView_Tests/test_pollCommentsView_ownCommentWithUpdateButton.default-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollCommentsView_Tests/test_pollCommentsView_ownCommentWithUpdateButton.default-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollCommentsView_Tests/test_pollCommentsView_ownCommentWithUpdateButton.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollCommentsView_Tests/test_pollCommentsView_ownCommentWithUpdateButton.default-light.png index ad3bd7c7d..afa8378b3 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollCommentsView_Tests/test_pollCommentsView_ownCommentWithUpdateButton.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollCommentsView_Tests/test_pollCommentsView_ownCommentWithUpdateButton.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollCommentsView_Tests/test_pollCommentsView_singleComment.default-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollCommentsView_Tests/test_pollCommentsView_singleComment.default-dark.png index 80aacd5d1..bfd60a3ba 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollCommentsView_Tests/test_pollCommentsView_singleComment.default-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollCommentsView_Tests/test_pollCommentsView_singleComment.default-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollCommentsView_Tests/test_pollCommentsView_singleComment.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollCommentsView_Tests/test_pollCommentsView_singleComment.default-light.png index 5ebd9e1be..251e38801 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollCommentsView_Tests/test_pollCommentsView_singleComment.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollCommentsView_Tests/test_pollCommentsView_singleComment.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollResultsView_Tests/test_pollOptionResultsView_withOptionIndex.default-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollResultsView_Tests/test_pollOptionResultsView_withOptionIndex.default-dark.png index 633fcd952..2efe695b1 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollResultsView_Tests/test_pollOptionResultsView_withOptionIndex.default-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollResultsView_Tests/test_pollOptionResultsView_withOptionIndex.default-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollResultsView_Tests/test_pollOptionResultsView_withTrophy.default-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollResultsView_Tests/test_pollOptionResultsView_withTrophy.default-dark.png index 6c1348504..1ffe760d4 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollResultsView_Tests/test_pollOptionResultsView_withTrophy.default-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollResultsView_Tests/test_pollOptionResultsView_withTrophy.default-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollResultsView_Tests/test_pollOptionResultsView_withViewAllButton.default-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollResultsView_Tests/test_pollOptionResultsView_withViewAllButton.default-dark.png index d5ed1dd33..2c9c9b984 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollResultsView_Tests/test_pollOptionResultsView_withViewAllButton.default-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollResultsView_Tests/test_pollOptionResultsView_withViewAllButton.default-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollResultsView_Tests/test_pollOptionResultsView_withoutOptionIndex.default-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollResultsView_Tests/test_pollOptionResultsView_withoutOptionIndex.default-dark.png index d0a02f804..6eae0a8d7 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollResultsView_Tests/test_pollOptionResultsView_withoutOptionIndex.default-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollResultsView_Tests/test_pollOptionResultsView_withoutOptionIndex.default-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollResultsView_Tests/test_pollOptionResultsView_zeroVotes.default-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollResultsView_Tests/test_pollOptionResultsView_zeroVotes.default-dark.png index deffd2724..e52d72079 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollResultsView_Tests/test_pollOptionResultsView_zeroVotes.default-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollResultsView_Tests/test_pollOptionResultsView_zeroVotes.default-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollResultsView_Tests/test_pollResultsView_anonymousVoting.default-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollResultsView_Tests/test_pollResultsView_anonymousVoting.default-dark.png index 39d3bb5e4..3a84e0629 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollResultsView_Tests/test_pollResultsView_anonymousVoting.default-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollResultsView_Tests/test_pollResultsView_anonymousVoting.default-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollResultsView_Tests/test_pollResultsView_anonymousVoting.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollResultsView_Tests/test_pollResultsView_anonymousVoting.default-light.png index 4abf044c7..51eee94a2 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollResultsView_Tests/test_pollResultsView_anonymousVoting.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollResultsView_Tests/test_pollResultsView_anonymousVoting.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollResultsView_Tests/test_pollResultsView_defaultPoll.default-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollResultsView_Tests/test_pollResultsView_defaultPoll.default-dark.png index 229c64b97..274d3675d 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollResultsView_Tests/test_pollResultsView_defaultPoll.default-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollResultsView_Tests/test_pollResultsView_defaultPoll.default-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollResultsView_Tests/test_pollResultsView_defaultPoll.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollResultsView_Tests/test_pollResultsView_defaultPoll.default-light.png index 81d85da76..df78e117e 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollResultsView_Tests/test_pollResultsView_defaultPoll.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollResultsView_Tests/test_pollResultsView_defaultPoll.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollResultsView_Tests/test_pollResultsView_multipleOptionsWithVotes.default-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollResultsView_Tests/test_pollResultsView_multipleOptionsWithVotes.default-dark.png index de400bc11..5195b13b5 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollResultsView_Tests/test_pollResultsView_multipleOptionsWithVotes.default-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollResultsView_Tests/test_pollResultsView_multipleOptionsWithVotes.default-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollResultsView_Tests/test_pollResultsView_multipleOptionsWithVotes.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollResultsView_Tests/test_pollResultsView_multipleOptionsWithVotes.default-light.png index 68945fe0e..af005c8b3 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollResultsView_Tests/test_pollResultsView_multipleOptionsWithVotes.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollResultsView_Tests/test_pollResultsView_multipleOptionsWithVotes.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollResultsView_Tests/test_pollResultsView_optionWithMostVotesShowsTrophy.default-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollResultsView_Tests/test_pollResultsView_optionWithMostVotesShowsTrophy.default-dark.png index ef056c3d0..052438299 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollResultsView_Tests/test_pollResultsView_optionWithMostVotesShowsTrophy.default-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollResultsView_Tests/test_pollResultsView_optionWithMostVotesShowsTrophy.default-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollResultsView_Tests/test_pollResultsView_optionWithMostVotesShowsTrophy.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollResultsView_Tests/test_pollResultsView_optionWithMostVotesShowsTrophy.default-light.png index 0bdb3a2bb..60522020f 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollResultsView_Tests/test_pollResultsView_optionWithMostVotesShowsTrophy.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollResultsView_Tests/test_pollResultsView_optionWithMostVotesShowsTrophy.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollResultsView_Tests/test_pollResultsView_optionWithViewAllButton.default-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollResultsView_Tests/test_pollResultsView_optionWithViewAllButton.default-dark.png index 1a56e5160..8763bc20e 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollResultsView_Tests/test_pollResultsView_optionWithViewAllButton.default-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollResultsView_Tests/test_pollResultsView_optionWithViewAllButton.default-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollResultsView_Tests/test_pollResultsView_optionWithViewAllButton.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollResultsView_Tests/test_pollResultsView_optionWithViewAllButton.default-light.png index ec298101f..2ae229a91 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollResultsView_Tests/test_pollResultsView_optionWithViewAllButton.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollResultsView_Tests/test_pollResultsView_optionWithViewAllButton.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollResultsView_Tests/test_pollResultsView_optionWithZeroVotes.default-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollResultsView_Tests/test_pollResultsView_optionWithZeroVotes.default-dark.png index cd6d74e9f..e43acbfc1 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollResultsView_Tests/test_pollResultsView_optionWithZeroVotes.default-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollResultsView_Tests/test_pollResultsView_optionWithZeroVotes.default-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollResultsView_Tests/test_pollResultsView_optionWithZeroVotes.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollResultsView_Tests/test_pollResultsView_optionWithZeroVotes.default-light.png index f8be2260c..733f85e08 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollResultsView_Tests/test_pollResultsView_optionWithZeroVotes.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollResultsView_Tests/test_pollResultsView_optionWithZeroVotes.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollResultsView_Tests/test_pollResultsView_singleVote.default-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollResultsView_Tests/test_pollResultsView_singleVote.default-dark.png index dc91fc679..d477b6c30 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollResultsView_Tests/test_pollResultsView_singleVote.default-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollResultsView_Tests/test_pollResultsView_singleVote.default-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollResultsView_Tests/test_pollResultsView_singleVote.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollResultsView_Tests/test_pollResultsView_singleVote.default-light.png index ad36db6d2..12cb80b98 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollResultsView_Tests/test_pollResultsView_singleVote.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/PollResultsView_Tests/test_pollResultsView_singleVote.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_deletedMessage.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_deletedMessage.small-dark.png index 919ca498a..93bb1362f 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_deletedMessage.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_deletedMessage.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_fileSingleNoCaption.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_fileSingleNoCaption.small-dark.png index 35c28068d..27d498bfc 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_fileSingleNoCaption.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_fileSingleNoCaption.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_fileSingleWithCaption.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_fileSingleWithCaption.small-dark.png index f345a9ab9..e46274224 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_fileSingleWithCaption.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_fileSingleWithCaption.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_giphy.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_giphy.default-light.png new file mode 100644 index 000000000..120cab7a9 Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_giphy.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_giphy.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_giphy.extraExtraExtraLarge-light.png new file mode 100644 index 000000000..70c446c39 Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_giphy.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_giphy.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_giphy.rightToLeftLayout-default.png new file mode 100644 index 000000000..13230983b Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_giphy.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_giphy.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_giphy.small-dark.png new file mode 100644 index 000000000..27bf5f288 Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_giphy.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_link.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_link.default-light.png index eafc55ed9..7c00f3aa6 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_link.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_link.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_link.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_link.extraExtraExtraLarge-light.png index 9f601f1a5..44b140d14 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_link.extraExtraExtraLarge-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_link.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_link.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_link.rightToLeftLayout-default.png index 7e52b2548..60d4a351f 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_link.rightToLeftLayout-default.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_link.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_link.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_link.small-dark.png index bc4110256..9821a291e 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_link.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_link.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_mixedContentNoCaption.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_mixedContentNoCaption.small-dark.png index b3ab25130..c1d5d9832 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_mixedContentNoCaption.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_mixedContentNoCaption.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_mixedContentWithCaption.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_mixedContentWithCaption.small-dark.png index 9b9e45b01..5573fbc82 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_mixedContentWithCaption.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_mixedContentWithCaption.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_photoMultipleNoCaption.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_photoMultipleNoCaption.small-dark.png index 89bfa8531..bf123d82f 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_photoMultipleNoCaption.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_photoMultipleNoCaption.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_photoMultipleWithCaption.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_photoMultipleWithCaption.small-dark.png index de42c27e6..270c82efd 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_photoMultipleWithCaption.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_photoMultipleWithCaption.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_photoSingleNoCaption.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_photoSingleNoCaption.default-light.png index 10ca62c8e..5ee7cf880 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_photoSingleNoCaption.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_photoSingleNoCaption.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_photoSingleNoCaption.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_photoSingleNoCaption.extraExtraExtraLarge-light.png index c22c454e1..0340e1897 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_photoSingleNoCaption.extraExtraExtraLarge-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_photoSingleNoCaption.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_photoSingleNoCaption.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_photoSingleNoCaption.rightToLeftLayout-default.png index 7a5dac9a7..5631042ba 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_photoSingleNoCaption.rightToLeftLayout-default.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_photoSingleNoCaption.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_photoSingleNoCaption.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_photoSingleNoCaption.small-dark.png index 65e5932c3..57256c3a6 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_photoSingleNoCaption.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_photoSingleNoCaption.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_photoSingleWithCaption.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_photoSingleWithCaption.default-light.png index ae0c4364c..e94369297 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_photoSingleWithCaption.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_photoSingleWithCaption.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_photoSingleWithCaption.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_photoSingleWithCaption.extraExtraExtraLarge-light.png index c1fd65fca..aeb25d3c9 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_photoSingleWithCaption.extraExtraExtraLarge-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_photoSingleWithCaption.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_photoSingleWithCaption.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_photoSingleWithCaption.rightToLeftLayout-default.png index 5b623f98f..02d5a06d8 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_photoSingleWithCaption.rightToLeftLayout-default.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_photoSingleWithCaption.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_photoSingleWithCaption.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_photoSingleWithCaption.small-dark.png index 66609ba80..e7c5bb06e 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_photoSingleWithCaption.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_photoSingleWithCaption.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_poll.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_poll.default-light.png index a62e2ea3f..bab21015b 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_poll.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_poll.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_poll.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_poll.extraExtraExtraLarge-light.png index 13de3279a..7fb468f0f 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_poll.extraExtraExtraLarge-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_poll.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_poll.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_poll.rightToLeftLayout-default.png index e7ca5668f..40f44910c 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_poll.rightToLeftLayout-default.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_poll.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_poll.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_poll.small-dark.png index 9e751162e..5ab8cc597 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_poll.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_poll.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_textLong.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_textLong.small-dark.png index 8cf232d3b..36d36b247 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_textLong.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_textLong.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_textShort_incoming.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_textShort_incoming.small-dark.png index 3ecba937b..2430a193e 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_textShort_incoming.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_textShort_incoming.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_textShort_outgoing.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_textShort_outgoing.small-dark.png index 3ecba937b..2430a193e 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_textShort_outgoing.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_textShort_outgoing.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_videoMultipleNoCaption.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_videoMultipleNoCaption.small-dark.png index f3c0bc497..58c730c7f 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_videoMultipleNoCaption.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_videoMultipleNoCaption.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_videoMultipleWithCaption.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_videoMultipleWithCaption.small-dark.png index 571fd4ab7..29e5b8c2e 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_videoMultipleWithCaption.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_videoMultipleWithCaption.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_videoSingleNoCaption.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_videoSingleNoCaption.default-light.png index 5862e6db5..0b7ae7dee 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_videoSingleNoCaption.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_videoSingleNoCaption.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_videoSingleNoCaption.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_videoSingleNoCaption.extraExtraExtraLarge-light.png index f0d9c897c..877c77d06 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_videoSingleNoCaption.extraExtraExtraLarge-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_videoSingleNoCaption.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_videoSingleNoCaption.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_videoSingleNoCaption.rightToLeftLayout-default.png index 34f7a54bd..87dd9b59f 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_videoSingleNoCaption.rightToLeftLayout-default.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_videoSingleNoCaption.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_videoSingleNoCaption.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_videoSingleNoCaption.small-dark.png index 7421ab58c..f5b99d9a8 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_videoSingleNoCaption.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_videoSingleNoCaption.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_videoSingleWithCaption.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_videoSingleWithCaption.default-light.png index 0c883eab1..d252c17ae 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_videoSingleWithCaption.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_videoSingleWithCaption.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_videoSingleWithCaption.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_videoSingleWithCaption.extraExtraExtraLarge-light.png index 237708f07..6c67a80e7 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_videoSingleWithCaption.extraExtraExtraLarge-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_videoSingleWithCaption.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_videoSingleWithCaption.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_videoSingleWithCaption.rightToLeftLayout-default.png index 327f1649e..a74dd6295 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_videoSingleWithCaption.rightToLeftLayout-default.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_videoSingleWithCaption.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_videoSingleWithCaption.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_videoSingleWithCaption.small-dark.png index 6a66f3e63..0ba15e8b3 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_videoSingleWithCaption.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_videoSingleWithCaption.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_voiceMessageNoCaption.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_voiceMessageNoCaption.small-dark.png index a83a7b0d2..b602cc1f5 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_voiceMessageNoCaption.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_voiceMessageNoCaption.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_voiceMessageWithCaption.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_voiceMessageWithCaption.small-dark.png index 5c9785e71..55c90ce3a 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_voiceMessageWithCaption.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/QuotedMessageView_Tests/test_quotedMessageView_voiceMessageWithCaption.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsDetailView_Tests/test_reactionsDetailView_empty_snapshot.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsDetailView_Tests/test_reactionsDetailView_empty_snapshot.default-light.png index 2e03ee387..5ea84d26f 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsDetailView_Tests/test_reactionsDetailView_empty_snapshot.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsDetailView_Tests/test_reactionsDetailView_empty_snapshot.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsDetailView_Tests/test_reactionsDetailView_empty_snapshot.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsDetailView_Tests/test_reactionsDetailView_empty_snapshot.extraExtraExtraLarge-light.png index 10aaec94d..b0603c27c 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsDetailView_Tests/test_reactionsDetailView_empty_snapshot.extraExtraExtraLarge-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsDetailView_Tests/test_reactionsDetailView_empty_snapshot.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsDetailView_Tests/test_reactionsDetailView_empty_snapshot.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsDetailView_Tests/test_reactionsDetailView_empty_snapshot.rightToLeftLayout-default.png index 3d3f7cf42..7801ba6c2 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsDetailView_Tests/test_reactionsDetailView_empty_snapshot.rightToLeftLayout-default.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsDetailView_Tests/test_reactionsDetailView_empty_snapshot.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsDetailView_Tests/test_reactionsDetailView_empty_snapshot.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsDetailView_Tests/test_reactionsDetailView_empty_snapshot.small-dark.png index 78bef2691..b24fb290e 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsDetailView_Tests/test_reactionsDetailView_empty_snapshot.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsDetailView_Tests/test_reactionsDetailView_empty_snapshot.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsDetailView_Tests/test_reactionsDetailView_filteredByType_snapshot.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsDetailView_Tests/test_reactionsDetailView_filteredByType_snapshot.default-light.png index 64765d7f0..6f304aaf5 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsDetailView_Tests/test_reactionsDetailView_filteredByType_snapshot.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsDetailView_Tests/test_reactionsDetailView_filteredByType_snapshot.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsDetailView_Tests/test_reactionsDetailView_filteredByType_snapshot.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsDetailView_Tests/test_reactionsDetailView_filteredByType_snapshot.extraExtraExtraLarge-light.png index 02c557cc0..473bb73f4 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsDetailView_Tests/test_reactionsDetailView_filteredByType_snapshot.extraExtraExtraLarge-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsDetailView_Tests/test_reactionsDetailView_filteredByType_snapshot.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsDetailView_Tests/test_reactionsDetailView_filteredByType_snapshot.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsDetailView_Tests/test_reactionsDetailView_filteredByType_snapshot.rightToLeftLayout-default.png index 2118cc985..fa9c4c58e 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsDetailView_Tests/test_reactionsDetailView_filteredByType_snapshot.rightToLeftLayout-default.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsDetailView_Tests/test_reactionsDetailView_filteredByType_snapshot.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsDetailView_Tests/test_reactionsDetailView_filteredByType_snapshot.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsDetailView_Tests/test_reactionsDetailView_filteredByType_snapshot.small-dark.png index 1a6c4a1ae..5a1a70753 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsDetailView_Tests/test_reactionsDetailView_filteredByType_snapshot.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsDetailView_Tests/test_reactionsDetailView_filteredByType_snapshot.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsDetailView_Tests/test_reactionsDetailView_manyReactions_snapshot.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsDetailView_Tests/test_reactionsDetailView_manyReactions_snapshot.default-light.png index 54b325a1c..599382a73 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsDetailView_Tests/test_reactionsDetailView_manyReactions_snapshot.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsDetailView_Tests/test_reactionsDetailView_manyReactions_snapshot.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsDetailView_Tests/test_reactionsDetailView_manyReactions_snapshot.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsDetailView_Tests/test_reactionsDetailView_manyReactions_snapshot.extraExtraExtraLarge-light.png index 8f24a6c76..5ed4a655b 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsDetailView_Tests/test_reactionsDetailView_manyReactions_snapshot.extraExtraExtraLarge-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsDetailView_Tests/test_reactionsDetailView_manyReactions_snapshot.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsDetailView_Tests/test_reactionsDetailView_manyReactions_snapshot.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsDetailView_Tests/test_reactionsDetailView_manyReactions_snapshot.rightToLeftLayout-default.png index 040fb2477..8459b6153 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsDetailView_Tests/test_reactionsDetailView_manyReactions_snapshot.rightToLeftLayout-default.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsDetailView_Tests/test_reactionsDetailView_manyReactions_snapshot.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsDetailView_Tests/test_reactionsDetailView_manyReactions_snapshot.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsDetailView_Tests/test_reactionsDetailView_manyReactions_snapshot.small-dark.png index 92716dcf2..e14aefd76 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsDetailView_Tests/test_reactionsDetailView_manyReactions_snapshot.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsDetailView_Tests/test_reactionsDetailView_manyReactions_snapshot.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsDetailView_Tests/test_reactionsDetailView_multipleReactionTypes_snapshot.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsDetailView_Tests/test_reactionsDetailView_multipleReactionTypes_snapshot.default-light.png index c42f07e06..c606910cd 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsDetailView_Tests/test_reactionsDetailView_multipleReactionTypes_snapshot.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsDetailView_Tests/test_reactionsDetailView_multipleReactionTypes_snapshot.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsDetailView_Tests/test_reactionsDetailView_multipleReactionTypes_snapshot.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsDetailView_Tests/test_reactionsDetailView_multipleReactionTypes_snapshot.extraExtraExtraLarge-light.png index 0aa71b23a..7e0127a02 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsDetailView_Tests/test_reactionsDetailView_multipleReactionTypes_snapshot.extraExtraExtraLarge-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsDetailView_Tests/test_reactionsDetailView_multipleReactionTypes_snapshot.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsDetailView_Tests/test_reactionsDetailView_multipleReactionTypes_snapshot.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsDetailView_Tests/test_reactionsDetailView_multipleReactionTypes_snapshot.rightToLeftLayout-default.png index 612c944f7..f43b038a9 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsDetailView_Tests/test_reactionsDetailView_multipleReactionTypes_snapshot.rightToLeftLayout-default.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsDetailView_Tests/test_reactionsDetailView_multipleReactionTypes_snapshot.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsDetailView_Tests/test_reactionsDetailView_multipleReactionTypes_snapshot.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsDetailView_Tests/test_reactionsDetailView_multipleReactionTypes_snapshot.small-dark.png index faeb577b9..c71ea7e97 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsDetailView_Tests/test_reactionsDetailView_multipleReactionTypes_snapshot.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsDetailView_Tests/test_reactionsDetailView_multipleReactionTypes_snapshot.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsDetailView_Tests/test_reactionsDetailView_singleReactionType_snapshot.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsDetailView_Tests/test_reactionsDetailView_singleReactionType_snapshot.default-light.png index fbf60831b..5d18b710f 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsDetailView_Tests/test_reactionsDetailView_singleReactionType_snapshot.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsDetailView_Tests/test_reactionsDetailView_singleReactionType_snapshot.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsDetailView_Tests/test_reactionsDetailView_singleReactionType_snapshot.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsDetailView_Tests/test_reactionsDetailView_singleReactionType_snapshot.extraExtraExtraLarge-light.png index 76408e756..8a64bc26a 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsDetailView_Tests/test_reactionsDetailView_singleReactionType_snapshot.extraExtraExtraLarge-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsDetailView_Tests/test_reactionsDetailView_singleReactionType_snapshot.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsDetailView_Tests/test_reactionsDetailView_singleReactionType_snapshot.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsDetailView_Tests/test_reactionsDetailView_singleReactionType_snapshot.rightToLeftLayout-default.png index 2f3236de9..35f119894 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsDetailView_Tests/test_reactionsDetailView_singleReactionType_snapshot.rightToLeftLayout-default.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsDetailView_Tests/test_reactionsDetailView_singleReactionType_snapshot.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsDetailView_Tests/test_reactionsDetailView_singleReactionType_snapshot.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsDetailView_Tests/test_reactionsDetailView_singleReactionType_snapshot.small-dark.png index 445b5ce5f..d5006cfb0 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsDetailView_Tests/test_reactionsDetailView_singleReactionType_snapshot.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsDetailView_Tests/test_reactionsDetailView_singleReactionType_snapshot.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsDetailView_Tests/test_reactionsDetailView_withCurrentUser_snapshot.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsDetailView_Tests/test_reactionsDetailView_withCurrentUser_snapshot.default-light.png index 18bb96a15..f402b5687 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsDetailView_Tests/test_reactionsDetailView_withCurrentUser_snapshot.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsDetailView_Tests/test_reactionsDetailView_withCurrentUser_snapshot.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsDetailView_Tests/test_reactionsDetailView_withCurrentUser_snapshot.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsDetailView_Tests/test_reactionsDetailView_withCurrentUser_snapshot.extraExtraExtraLarge-light.png index 776c35e6b..666f66f11 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsDetailView_Tests/test_reactionsDetailView_withCurrentUser_snapshot.extraExtraExtraLarge-light.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsDetailView_Tests/test_reactionsDetailView_withCurrentUser_snapshot.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsDetailView_Tests/test_reactionsDetailView_withCurrentUser_snapshot.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsDetailView_Tests/test_reactionsDetailView_withCurrentUser_snapshot.rightToLeftLayout-default.png index 3c1688523..b456382ba 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsDetailView_Tests/test_reactionsDetailView_withCurrentUser_snapshot.rightToLeftLayout-default.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsDetailView_Tests/test_reactionsDetailView_withCurrentUser_snapshot.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsDetailView_Tests/test_reactionsDetailView_withCurrentUser_snapshot.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsDetailView_Tests/test_reactionsDetailView_withCurrentUser_snapshot.small-dark.png index 886acacfa..30f568d5e 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsDetailView_Tests/test_reactionsDetailView_withCurrentUser_snapshot.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsDetailView_Tests/test_reactionsDetailView_withCurrentUser_snapshot.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsOverlayView_Tests/test_reactionsOverlayView_allAnnotations.default-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsOverlayView_Tests/test_reactionsOverlayView_allAnnotations.default-dark.png new file mode 100644 index 000000000..4ac605d07 Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsOverlayView_Tests/test_reactionsOverlayView_allAnnotations.default-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsOverlayView_Tests/test_reactionsOverlayView_allAnnotations.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsOverlayView_Tests/test_reactionsOverlayView_allAnnotations.default-light.png new file mode 100644 index 000000000..ed61f0812 Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsOverlayView_Tests/test_reactionsOverlayView_allAnnotations.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsOverlayView_Tests/test_reactionsOverlayView_noReactions.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsOverlayView_Tests/test_reactionsOverlayView_noReactions.1.png index 0e85df8ea..a58f45055 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsOverlayView_Tests/test_reactionsOverlayView_noReactions.1.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsOverlayView_Tests/test_reactionsOverlayView_noReactions.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsOverlayView_Tests/test_reactionsOverlayView_snapshot.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsOverlayView_Tests/test_reactionsOverlayView_snapshot.1.png index 3e8d7515d..b7d3c73e2 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsOverlayView_Tests/test_reactionsOverlayView_snapshot.1.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsOverlayView_Tests/test_reactionsOverlayView_snapshot.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsOverlayView_Tests/test_reactionsOverlayView_translated.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsOverlayView_Tests/test_reactionsOverlayView_translated.1.png index 1f6f9c35d..e7b1418e3 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsOverlayView_Tests/test_reactionsOverlayView_translated.1.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsOverlayView_Tests/test_reactionsOverlayView_translated.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsOverlayView_Tests/test_reactionsOverlayView_usersReactions.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsOverlayView_Tests/test_reactionsOverlayView_usersReactions.1.png index 1d6a27ccb..f4bba509a 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsOverlayView_Tests/test_reactionsOverlayView_usersReactions.1.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsOverlayView_Tests/test_reactionsOverlayView_usersReactions.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsOverlayView_Tests/test_reactionsOverlay_veryLongMessage.1.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsOverlayView_Tests/test_reactionsOverlay_veryLongMessage.1.png index 0dfa2c611..b0c852f49 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsOverlayView_Tests/test_reactionsOverlay_veryLongMessage.1.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsOverlayView_Tests/test_reactionsOverlay_veryLongMessage.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsView_Tests/test_reactionsView_clustered_multipleScores_snapshot.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsView_Tests/test_reactionsView_clustered_multipleScores_snapshot.small-dark.png index 427379500..3a59ab005 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsView_Tests/test_reactionsView_clustered_multipleScores_snapshot.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsView_Tests/test_reactionsView_clustered_multipleScores_snapshot.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsView_Tests/test_reactionsView_clustered_overflow_snapshot.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsView_Tests/test_reactionsView_clustered_overflow_snapshot.small-dark.png index afce7f0e1..739f807db 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsView_Tests/test_reactionsView_clustered_overflow_snapshot.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsView_Tests/test_reactionsView_clustered_overflow_snapshot.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsView_Tests/test_reactionsView_clustered_snapshot.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsView_Tests/test_reactionsView_clustered_snapshot.small-dark.png index d5509d26e..d2de88e43 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsView_Tests/test_reactionsView_clustered_snapshot.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsView_Tests/test_reactionsView_clustered_snapshot.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsView_Tests/test_reactionsView_segmented_multipleScores_snapshot.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsView_Tests/test_reactionsView_segmented_multipleScores_snapshot.small-dark.png index b433e9eb9..f4cdafaf8 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsView_Tests/test_reactionsView_segmented_multipleScores_snapshot.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsView_Tests/test_reactionsView_segmented_multipleScores_snapshot.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsView_Tests/test_reactionsView_segmented_overflow_snapshot.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsView_Tests/test_reactionsView_segmented_overflow_snapshot.small-dark.png index 9a69c566e..fb49b40a7 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsView_Tests/test_reactionsView_segmented_overflow_snapshot.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsView_Tests/test_reactionsView_segmented_overflow_snapshot.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsView_Tests/test_reactionsView_segmented_snapshot.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsView_Tests/test_reactionsView_segmented_snapshot.small-dark.png index c4c723efd..968bedb07 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsView_Tests/test_reactionsView_segmented_snapshot.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/ReactionsView_Tests/test_reactionsView_segmented_snapshot.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/SystemMessageView_Tests/test_systemMessageView_longMessage.default-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/SystemMessageView_Tests/test_systemMessageView_longMessage.default-dark.png index 23f242f19..d97e81467 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/SystemMessageView_Tests/test_systemMessageView_longMessage.default-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/SystemMessageView_Tests/test_systemMessageView_longMessage.default-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/SystemMessageView_Tests/test_systemMessageView_memberAdded.default-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/SystemMessageView_Tests/test_systemMessageView_memberAdded.default-dark.png index df5e47a98..b7d365d1f 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/SystemMessageView_Tests/test_systemMessageView_memberAdded.default-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/SystemMessageView_Tests/test_systemMessageView_memberAdded.default-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/SystemMessageView_Tests/test_systemMessageView_memberRemoved.default-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/SystemMessageView_Tests/test_systemMessageView_memberRemoved.default-dark.png index f381cc8c4..0027ecd32 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/SystemMessageView_Tests/test_systemMessageView_memberRemoved.default-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/SystemMessageView_Tests/test_systemMessageView_memberRemoved.default-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/SystemMessageView_Tests/test_systemMessageView_shortMessage.default-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/SystemMessageView_Tests/test_systemMessageView_shortMessage.default-dark.png index 0eaa4d06d..e44ddddd7 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/SystemMessageView_Tests/test_systemMessageView_shortMessage.default-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/SystemMessageView_Tests/test_systemMessageView_shortMessage.default-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/SystemMessageView_Tests/test_systemMessageView_veryLongMessage.default-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/SystemMessageView_Tests/test_systemMessageView_veryLongMessage.default-dark.png index ce6eebccc..26bdf11b8 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/SystemMessageView_Tests/test_systemMessageView_veryLongMessage.default-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/SystemMessageView_Tests/test_systemMessageView_veryLongMessage.default-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/TypingIndicatorView_Tests/test_typingIndicatorDotsView_snapshot.default-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/TypingIndicatorView_Tests/test_typingIndicatorDotsView_snapshot.default-dark.png index 040f4c386..d9dfb114d 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/TypingIndicatorView_Tests/test_typingIndicatorDotsView_snapshot.default-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/TypingIndicatorView_Tests/test_typingIndicatorDotsView_snapshot.default-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/TypingIndicatorView_Tests/test_typingIndicatorView_overflow.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/TypingIndicatorView_Tests/test_typingIndicatorView_overflow.small-dark.png index 85d55260d..7db7522e1 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/TypingIndicatorView_Tests/test_typingIndicatorView_overflow.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/TypingIndicatorView_Tests/test_typingIndicatorView_overflow.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/TypingIndicatorView_Tests/test_typingIndicatorView_singleUser.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/TypingIndicatorView_Tests/test_typingIndicatorView_singleUser.small-dark.png index 1b88f33b0..daa8b9d72 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/TypingIndicatorView_Tests/test_typingIndicatorView_singleUser.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/TypingIndicatorView_Tests/test_typingIndicatorView_singleUser.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/TypingIndicatorView_Tests/test_typingIndicatorView_threeUsers.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/TypingIndicatorView_Tests/test_typingIndicatorView_threeUsers.small-dark.png index 697a93b7c..2371b6170 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/TypingIndicatorView_Tests/test_typingIndicatorView_threeUsers.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/TypingIndicatorView_Tests/test_typingIndicatorView_threeUsers.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/TypingIndicatorView_Tests/test_typingIndicatorView_twoUsers.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/TypingIndicatorView_Tests/test_typingIndicatorView_twoUsers.small-dark.png index 118cdfeb5..b973130ed 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/TypingIndicatorView_Tests/test_typingIndicatorView_twoUsers.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannel/__Snapshots__/TypingIndicatorView_Tests/test_typingIndicatorView_twoUsers.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannelList/ChatChannelListItemView_Tests.swift b/StreamChatSwiftUITests/Tests/ChatChannelList/ChatChannelListItemView_Tests.swift index ce95d1376..5f1ef7e86 100644 --- a/StreamChatSwiftUITests/Tests/ChatChannelList/ChatChannelListItemView_Tests.swift +++ b/StreamChatSwiftUITests/Tests/ChatChannelList/ChatChannelListItemView_Tests.swift @@ -19,7 +19,7 @@ import XCTest func test_channelListItem_audioMessage() throws { // Given let message = try mockAudioMessage(text: "Audio", isSentByCurrentUser: true) - let channel = ChatChannel.mock(cid: .unique, latestMessages: [message], previewMessage: message) + let channel = ChatChannel.mock(cid: .unique, latestMessages: [message]) // When let view = ChatChannelListItem( @@ -36,7 +36,7 @@ import XCTest func test_channelListItem_imageMessage() throws { // Given let message = try mockImageMessage(text: "Image", isSentByCurrentUser: true) - let channel = ChatChannel.mock(cid: .unique, latestMessages: [message], previewMessage: message) + let channel = ChatChannel.mock(cid: .unique, latestMessages: [message]) // When let view = ChatChannelListItem( @@ -53,7 +53,7 @@ import XCTest func test_channelListItem_videoMessage() throws { // Given let message = try mockVideoMessage(text: "Video", isSentByCurrentUser: true) - let channel = ChatChannel.mock(cid: .unique, latestMessages: [message], previewMessage: message) + let channel = ChatChannel.mock(cid: .unique, latestMessages: [message]) // When let view = ChatChannelListItem( @@ -70,7 +70,7 @@ import XCTest func test_channelListItem_fileMessage() throws { // Given let message = try mockFileMessage(title: "Filename", text: "File", isSentByCurrentUser: true) - let channel = ChatChannel.mock(cid: .unique, latestMessages: [message], previewMessage: message) + let channel = ChatChannel.mock(cid: .unique, latestMessages: [message]) // When let view = ChatChannelListItem( @@ -90,8 +90,7 @@ import XCTest let channel = ChatChannel.mock( cid: .unique, latestMessages: [message], - muteDetails: .init(createdAt: .unique, updatedAt: .unique, expiresAt: nil), - previewMessage: message + muteDetails: .init(createdAt: .unique, updatedAt: .unique, expiresAt: nil) ) // When @@ -114,8 +113,7 @@ import XCTest cid: .unique, unreadCount: .mock(messages: 4), latestMessages: [message], - muteDetails: .init(createdAt: .unique, updatedAt: .unique, expiresAt: nil), - previewMessage: message + muteDetails: .init(createdAt: .unique, updatedAt: .unique, expiresAt: nil) ) // When @@ -138,8 +136,7 @@ import XCTest cid: .unique, unreadCount: .mock(messages: 4), latestMessages: [message], - muteDetails: .init(createdAt: .unique, updatedAt: .unique, expiresAt: nil), - previewMessage: message + muteDetails: .init(createdAt: .unique, updatedAt: .unique, expiresAt: nil) ) // When @@ -154,11 +151,10 @@ import XCTest assertSnapshot(matching: view, as: .image(perceptualPrecision: precision)) } - func test_channelListItem_giphyMessageLatestButPreviewIsAnotherMessage() throws { + func test_channelListItem_giphyMessage() throws { // Given - let previewMessage = try mockImageMessage(text: "Hi!", isSentByCurrentUser: true) - let latestMessage = try mockGiphyMessage(text: "Giphy", isSentByCurrentUser: true) - let channel = ChatChannel.mock(cid: .unique, latestMessages: [latestMessage], previewMessage: previewMessage) + let message = try mockGiphyMessage(text: "", isSentByCurrentUser: true) + let channel = ChatChannel.mock(cid: .unique, latestMessages: [message]) // When let view = ChatChannelListItem( @@ -172,10 +168,67 @@ import XCTest assertSnapshot(matching: view, as: .image(perceptualPrecision: precision)) } + func test_channelListItem_giphyMessage_groupChannel() throws { + // Given + let message = try mockGiphyMessage(text: "", isSentByCurrentUser: false) + let channel = ChatChannel.mockNonDMChannel( + name: "Group Chat", + latestMessages: [message] + ) + + // When + let view = ChatChannelListItem( + channel: channel, + channelName: "Group Chat", + onItemTap: { _ in } + ) + .frame(width: defaultScreenSize.width) + + // Then + assertSnapshot(matching: view, as: .image(perceptualPrecision: precision)) + } + + func test_channelListItem_ephemeralMessageSkipped_showsPreviousMessage() throws { + // Given + let regularMessage = ChatMessage.mock( + id: .unique, + cid: .unique, + text: "Hello there", + type: .regular, + author: .mock(id: "user", name: "User"), + createdAt: Date(timeIntervalSince1970: 100), + isSentByCurrentUser: false + ) + let ephemeralMessage = ChatMessage.mock( + id: .unique, + cid: .unique, + text: "/giphy cats", + type: .ephemeral, + author: .mock(id: Self.currentUserId, name: "Me"), + createdAt: Date(timeIntervalSince1970: 200), + isSentByCurrentUser: true + ) + let channel = ChatChannel.mockDMChannel( + memberCount: 2, + latestMessages: [ephemeralMessage, regularMessage] + ) + + // When + let view = ChatChannelListItem( + channel: channel, + channelName: "User", + onItemTap: { _ in } + ) + .frame(width: defaultScreenSize.width) + + // Then + AssertSnapshot(view) + } + func test_channelListItem_pollMessage_youCreated() throws { // Given let message = try mockPollMessage(isSentByCurrentUser: true) - let channel = ChatChannel.mock(cid: .unique, latestMessages: [message], previewMessage: message) + let channel = ChatChannel.mock(cid: .unique, latestMessages: [message]) // When let view = ChatChannelListItem( @@ -192,7 +245,7 @@ import XCTest func test_channelListItem_pollMessage_someoneCreated() throws { // Given let message = try mockPollMessage(isSentByCurrentUser: false) - let channel = ChatChannel.mock(cid: .unique, latestMessages: [message], previewMessage: message) + let channel = ChatChannel.mock(cid: .unique, latestMessages: [message]) // When let view = ChatChannelListItem( @@ -214,7 +267,7 @@ import XCTest .unique, .unique ]) - let channel = ChatChannel.mock(cid: .unique, membership: .mock(id: currentUserId), previewMessage: message) + let channel = ChatChannel.mock(cid: .unique, membership: .mock(id: currentUserId), latestMessages: [message]) // When let view = ChatChannelListItem( @@ -236,7 +289,7 @@ import XCTest .unique, .mock(pollId: .unique, optionId: .unique, user: .mock(id: currentUserId)) ]) - let channel = ChatChannel.mock(cid: .unique, membership: .mock(id: currentUserId), previewMessage: message) + let channel = ChatChannel.mock(cid: .unique, membership: .mock(id: currentUserId), latestMessages: [message]) // When let view = ChatChannelListItem( @@ -260,8 +313,7 @@ import XCTest let channel = ChatChannel.mock( cid: .unique, membership: .mock(id: .unique, language: .spanish), - latestMessages: [message], - previewMessage: message + latestMessages: [message] ) // When @@ -286,8 +338,7 @@ import XCTest let channel = ChatChannel.mock( cid: .unique, membership: .mock(id: .unique, language: .spanish), - latestMessages: [message], - previewMessage: message + latestMessages: [message] ) // When @@ -305,7 +356,7 @@ import XCTest func test_channelListItem_draftMessage() throws { // Given let message = DraftMessage.mock(text: "Draft message") - let channel = ChatChannel.mock(cid: .unique, previewMessage: .mock(), draftMessage: message) + let channel = ChatChannel.mock(cid: .unique, latestMessages: [.mock()], draftMessage: message) // When let view = ChatChannelListItem( @@ -328,7 +379,7 @@ import XCTest file: .init(url: .localYodaQuote) ) ))]) - let channel = ChatChannel.mock(cid: .unique, previewMessage: .mock(), draftMessage: message) + let channel = ChatChannel.mock(cid: .unique, latestMessages: [.mock()], draftMessage: message) // When let view = ChatChannelListItem( @@ -367,8 +418,7 @@ import XCTest lastDeliveredMessageId: message.id ) ], - latestMessages: [message], - previewMessage: message + latestMessages: [message] ) // When @@ -408,8 +458,7 @@ import XCTest lastDeliveredMessageId: message.id ) ], - latestMessages: [message], - previewMessage: message + latestMessages: [message] ) // When @@ -437,9 +486,53 @@ import XCTest ) let channel = ChatChannel.mock( cid: .unique, - latestMessages: [message], - previewMessage: message + latestMessages: [message] + ) + + // When + let view = ChatChannelListItem( + channel: channel, + channelName: "Test", + onItemTap: { _ in } + ) + .frame(width: defaultScreenSize.width) + + // Then + AssertSnapshot(view) + } + + func test_channelListItem_messagePending() throws { + // Given + let message = ChatMessage.mock( + id: .unique, + cid: .unique, + text: "Hey, how are you?", + author: .mock(id: Self.currentUserId, name: "You"), + createdAt: Date(timeIntervalSince1970: 100), + localState: .pendingSend, + isSentByCurrentUser: true + ) + let channel = ChatChannel.mock( + cid: .unique, + config: .mock(readEventsEnabled: true), + latestMessages: [message] + ) + + // When + let view = ChatChannelListItem( + channel: channel, + channelName: "Test", + onItemTap: { _ in } ) + .frame(width: defaultScreenSize.width) + + // Then + AssertSnapshot(view) + } + + func test_channelListItem_emptyMessages() throws { + // Given + let channel = ChatChannel.mock(cid: .unique) // When let view = ChatChannelListItem( @@ -456,7 +549,7 @@ import XCTest func test_channelListItem_voiceRecordingMessage() throws { // Given let message = try mockVoiceRecordingMessage(text: "", isSentByCurrentUser: true) - let channel = ChatChannel.mock(cid: .unique, latestMessages: [message], previewMessage: message) + let channel = ChatChannel.mock(cid: .unique, latestMessages: [message]) // When let view = ChatChannelListItem( @@ -484,8 +577,7 @@ import XCTest ) let channel = ChatChannel.mockNonDMChannel( name: "Group Chat", - latestMessages: [message], - previewMessage: message + latestMessages: [message] ) // When @@ -514,8 +606,7 @@ import XCTest ) let channel = ChatChannel.mockNonDMChannel( name: "Group Chat", - latestMessages: [message], - previewMessage: message + latestMessages: [message] ) // When @@ -544,8 +635,7 @@ import XCTest ) let channel = ChatChannel.mockDMChannel( memberCount: 2, - latestMessages: [message], - previewMessage: message + latestMessages: [message] ) // When @@ -565,8 +655,7 @@ import XCTest let message = try mockImageMessage(text: "Check this out", isSentByCurrentUser: false) let channel = ChatChannel.mockNonDMChannel( name: "Group Chat", - latestMessages: [message], - previewMessage: message + latestMessages: [message] ) // When @@ -581,6 +670,102 @@ import XCTest AssertSnapshot(view) } + func test_channelListItem_deletedMessage_dmChannel() throws { + // Given + let message = ChatMessage.mock( + id: .unique, + cid: .unique, + text: "This was the original message", + author: .mock(id: "other-user", name: "John"), + createdAt: Date(timeIntervalSince1970: 100), + deletedAt: Date(timeIntervalSince1970: 200), + isSentByCurrentUser: false + ) + let channel = ChatChannel.mockDMChannel( + memberCount: 2, + latestMessages: [message] + ) + + // When + let view = ChatChannelListItem( + channel: channel, + channelName: "John", + onItemTap: { _ in } + ) + .frame(width: defaultScreenSize.width) + + // Then + AssertSnapshot(view) + } + + func test_channelListItem_deletedMessage_groupChannel() throws { + // Given + let message = ChatMessage.mock( + id: .unique, + cid: .unique, + text: "This was the original message", + author: .mock(id: "other-user", name: "John"), + createdAt: Date(timeIntervalSince1970: 100), + deletedAt: Date(timeIntervalSince1970: 200), + isSentByCurrentUser: false + ) + let channel = ChatChannel.mockNonDMChannel( + name: "Group Chat", + latestMessages: [message] + ) + + // When + let view = ChatChannelListItem( + channel: channel, + channelName: "Group Chat", + onItemTap: { _ in } + ) + .frame(width: defaultScreenSize.width) + + // Then + AssertSnapshot(view) + } + + func test_channelListItem_deletedMessage_sentByCurrentUser() throws { + // Given + let date = Date(timeIntervalSince1970: 100) + let message = ChatMessage.mock( + id: .unique, + cid: .unique, + text: "Deleted message", + author: .mock(id: Self.currentUserId, name: "Me"), + createdAt: date.addingTimeInterval(-100), + deletedAt: date, + isSentByCurrentUser: true + ) + let channel = ChatChannel.mock( + cid: .unique, + config: .mock(readEventsEnabled: true), + reads: [ + .init( + lastReadAt: date.addingTimeInterval(10), + lastReadMessageId: message.id, + unreadMessagesCount: 0, + user: .unique, + lastDeliveredAt: date, + lastDeliveredMessageId: message.id + ) + ], + latestMessages: [message] + ) + + // When + let view = ChatChannelListItem( + channel: channel, + channelName: "Test", + onItemTap: { _ in } + ) + .frame(width: defaultScreenSize.width) + + // Then + AssertSnapshot(view) + } + // MARK: - private private func mockVoiceRecordingMessage(text: String, isSentByCurrentUser: Bool) throws -> ChatMessage { diff --git a/StreamChatSwiftUITests/Tests/ChatChannelList/ChatChannelListViewModel_Tests.swift b/StreamChatSwiftUITests/Tests/ChatChannelList/ChatChannelListViewModel_Tests.swift index e4bb1b5dd..77cc42950 100644 --- a/StreamChatSwiftUITests/Tests/ChatChannelList/ChatChannelListViewModel_Tests.swift +++ b/StreamChatSwiftUITests/Tests/ChatChannelList/ChatChannelListViewModel_Tests.swift @@ -3,7 +3,6 @@ // @testable import StreamChat -@testable import StreamChatCommonUI @testable import StreamChatSwiftUI @testable import StreamChatTestTools import XCTest @@ -136,6 +135,57 @@ import XCTest XCTAssert(name == expectedName) } + func test_channelListVM_onMuteTapped() { + // Given + let viewModel = makeDefaultChannelListVM() + let channel = ChatChannel.mockDMChannel() + + // When + viewModel.onMuteTapped(channel: channel) + + // Then + XCTAssert(viewModel.channelAlertType == .muteChannel(channel)) + XCTAssert(viewModel.alertShown == true) + } + + func test_channelListVM_mute_resetsSwipedChannelId() { + // Given + let channel = ChatChannel.mockDMChannel() + let channelListController = makeChannelListController(channels: [channel]) + let viewModel = ChatChannelListViewModel( + channelListController: channelListController, + selectedChannelId: nil + ) + viewModel.swipedChannelId = channel.id + + // When + viewModel.mute(channel: channel) + + // Then + XCTAssertNil(viewModel.swipedChannelId) + } + + func test_channelListVM_muteChannel_onError_showsErrorAlert() { + // Given + let channel = ChatChannel.mockDMChannel() + let channelListController = makeChannelListController(channels: [channel]) + let viewModel = ChatChannelListViewModel( + channelListController: channelListController, + selectedChannelId: nil + ) + let error = NSError(domain: "test", code: 1, userInfo: nil) + + // When + viewModel.mute(channel: channel) + chatClient.mockAPIClient.test_simulateResponse( + Result.failure(error) + ) + + // Then + XCTAssert(viewModel.channelAlertType == .error) + XCTAssert(viewModel.alertShown == true) + } + func test_channelListVM_onMoreTapped() { // Given let channel = ChatChannel.mockDMChannel() @@ -200,33 +250,8 @@ import XCTest viewModel.checkForChannels(index: 0) // Then - let injectedChannelInfo = viewModel.selectedChannel?.injectedChannelInfo! - let presentedSubtitle = injectedChannelInfo!.subtitle! - let unreadCount = injectedChannelInfo!.unreadCount - XCTAssert(presentedSubtitle == channel.subtitleText) - XCTAssert(viewModel.channels[0].subtitleText == "No messages") - XCTAssert(unreadCount == 0) - XCTAssert(channel.shouldShowTypingIndicator == false) - } - - func test_channelListVM_badgeCountUpdate() { - // Given - let channelId = ChannelId.unique - let channel = ChatChannel.mock(cid: channelId, unreadCount: .mock(messages: 1)) - let channelListController = makeChannelListController(channels: [channel]) - let viewModel = ChatChannelListViewModel( - channelListController: channelListController, - selectedChannelId: nil - ) - viewModel.selectedChannel = ChannelSelectionInfo(channel: channel, message: nil) - - // When - viewModel.checkForChannels(index: 0) - - // Then - let injectedChannelInfo = viewModel.selectedChannel?.injectedChannelInfo! - let unreadCount = injectedChannelInfo!.unreadCount - XCTAssert(unreadCount == 0) + XCTAssertEqual(viewModel.channels.count, 1) + XCTAssertEqual(viewModel.channels.first?.latestMessages.first?.text, "Test message") } func test_channelListVM_channelDismiss() { diff --git a/StreamChatSwiftUITests/Tests/ChatChannelList/ChatChannelListView_Tests.swift b/StreamChatSwiftUITests/Tests/ChatChannelList/ChatChannelListView_Tests.swift index 525d46e5c..fb88f53e5 100644 --- a/StreamChatSwiftUITests/Tests/ChatChannelList/ChatChannelListView_Tests.swift +++ b/StreamChatSwiftUITests/Tests/ChatChannelList/ChatChannelListView_Tests.swift @@ -94,6 +94,46 @@ import XCTest assertSnapshot(matching: view, as: .image(perceptualPrecision: precision)) } + func test_trailingSwipeActionsView_unmuted_snapshot() { + // Given - channel is not muted, swipe action shows mute (speaker.slash) icon + let channel = ChatChannel.mockDMChannel() + let view = TrailingSwipeActionsView( + channel: channel, + offsetX: -160, + buttonWidth: 80, + leftButtonTapped: { _ in }, + rightButtonTapped: { _ in } + ) + .frame( + width: defaultScreenSize.width, + height: 64 + ) + + // Then + assertSnapshot(matching: view, as: .image(perceptualPrecision: precision)) + } + + func test_trailingSwipeActionsView_muted_snapshot() { + // Given - channel is muted, swipe action shows unmute (speaker.wave.2) icon + let channel = ChatChannel.mockDMChannel( + muteDetails: .init(createdAt: .unique, updatedAt: .unique, expiresAt: nil) + ) + let view = TrailingSwipeActionsView( + channel: channel, + offsetX: -160, + buttonWidth: 80, + leftButtonTapped: { _ in }, + rightButtonTapped: { _ in } + ) + .frame( + width: defaultScreenSize.width, + height: 64 + ) + + // Then + assertSnapshot(matching: view, as: .image(perceptualPrecision: precision)) + } + func test_channelListView_channelAvatarUpdated() { // Given let controller = makeChannelListController() diff --git a/StreamChatSwiftUITests/Tests/ChatChannelList/NoChannelsView_Tests.swift b/StreamChatSwiftUITests/Tests/ChatChannelList/EmptyChannelsView_Tests.swift similarity index 70% rename from StreamChatSwiftUITests/Tests/ChatChannelList/NoChannelsView_Tests.swift rename to StreamChatSwiftUITests/Tests/ChatChannelList/EmptyChannelsView_Tests.swift index 95766d926..b81a995bf 100644 --- a/StreamChatSwiftUITests/Tests/ChatChannelList/NoChannelsView_Tests.swift +++ b/StreamChatSwiftUITests/Tests/ChatChannelList/EmptyChannelsView_Tests.swift @@ -7,10 +7,10 @@ import SnapshotTesting @testable import StreamChatSwiftUI import XCTest -class NoChannelsView_Tests: StreamChatTestCase { - func test_noChannelsView_snapshot() { +class EmptyChannelsView_Tests: StreamChatTestCase { + func test_emptyChannelsView_snapshot() { // Given - let view = NoChannelsView() + let view = EmptyChannelsView() .frame(width: 375, height: 600) // Then diff --git a/StreamChatSwiftUITests/Tests/ChatChannelList/MoreChannelActionsViewModel_Tests.swift b/StreamChatSwiftUITests/Tests/ChatChannelList/MoreChannelActionsViewModel_Tests.swift index 066b21561..09d7be653 100644 --- a/StreamChatSwiftUITests/Tests/ChatChannelList/MoreChannelActionsViewModel_Tests.swift +++ b/StreamChatSwiftUITests/Tests/ChatChannelList/MoreChannelActionsViewModel_Tests.swift @@ -50,11 +50,10 @@ import XCTest // When let actions = makeActions(for: channel) - // Then - viewInfo, muteUser (mutesEnabled=true by default), archiveConversation - XCTAssertEqual(actions.count, 3) + // Then - viewInfo, muteUser (mutesEnabled=true by default) + XCTAssertEqual(actions.count, 2) XCTAssertEqual(actions[0].title, L10n.Alert.Actions.viewInfoTitle) XCTAssertEqual(actions[1].title, L10n.Alert.Actions.muteUser) - XCTAssertEqual(actions[2].title, L10n.Alert.Actions.archiveConversation) } func test_defaultActions_dmChannel_withDeleteCapability_hasDeleteAction() { @@ -108,8 +107,8 @@ import XCTest // When let actions = makeActions(for: channel) - // Then - XCTAssertTrue(actions.contains(where: { $0.title == L10n.Alert.Actions.unarchiveConversation })) + // Then - archive action removed; neither archive nor unarchive should appear + XCTAssertFalse(actions.contains(where: { $0.title == L10n.Alert.Actions.unarchiveConversation })) XCTAssertFalse(actions.contains(where: { $0.title == L10n.Alert.Actions.archiveConversation })) } @@ -122,11 +121,10 @@ import XCTest // When let actions = makeActions(for: channel) - // Then - viewInfo, muteChannel (mutesEnabled=true by default), archiveChannel - XCTAssertEqual(actions.count, 3) + // Then - viewInfo, muteChannel (mutesEnabled=true by default) + XCTAssertEqual(actions.count, 2) XCTAssertEqual(actions[0].title, L10n.Alert.Actions.viewInfoTitle) XCTAssertEqual(actions[1].title, L10n.Alert.Actions.muteChannel) - XCTAssertEqual(actions[2].title, L10n.Alert.Actions.archiveChannel) } func test_defaultActions_groupChannel_withDeleteCapability_hasDeleteAction() { diff --git a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_audioMessage.1.png b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_audioMessage.1.png index 34fe30e69..2d665e4f9 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_audioMessage.1.png and b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_audioMessage.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_deletedMessage_dmChannel.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_deletedMessage_dmChannel.default-light.png new file mode 100644 index 000000000..e39b152d1 Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_deletedMessage_dmChannel.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_deletedMessage_dmChannel.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_deletedMessage_dmChannel.extraExtraExtraLarge-light.png new file mode 100644 index 000000000..e2d575ec2 Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_deletedMessage_dmChannel.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_deletedMessage_dmChannel.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_deletedMessage_dmChannel.rightToLeftLayout-default.png new file mode 100644 index 000000000..e638b87ed Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_deletedMessage_dmChannel.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_deletedMessage_dmChannel.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_deletedMessage_dmChannel.small-dark.png new file mode 100644 index 000000000..218f1357c Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_deletedMessage_dmChannel.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_deletedMessage_groupChannel.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_deletedMessage_groupChannel.default-light.png new file mode 100644 index 000000000..cd33a2868 Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_deletedMessage_groupChannel.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_deletedMessage_groupChannel.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_deletedMessage_groupChannel.extraExtraExtraLarge-light.png new file mode 100644 index 000000000..3a8c6abbc Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_deletedMessage_groupChannel.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_deletedMessage_groupChannel.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_deletedMessage_groupChannel.rightToLeftLayout-default.png new file mode 100644 index 000000000..84fcc91e1 Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_deletedMessage_groupChannel.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_deletedMessage_groupChannel.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_deletedMessage_groupChannel.small-dark.png new file mode 100644 index 000000000..ac2feedfd Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_deletedMessage_groupChannel.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_deletedMessage_sentByCurrentUser.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_deletedMessage_sentByCurrentUser.default-light.png new file mode 100644 index 000000000..362ff2a11 Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_deletedMessage_sentByCurrentUser.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_deletedMessage_sentByCurrentUser.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_deletedMessage_sentByCurrentUser.extraExtraExtraLarge-light.png new file mode 100644 index 000000000..79a1ad212 Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_deletedMessage_sentByCurrentUser.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_deletedMessage_sentByCurrentUser.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_deletedMessage_sentByCurrentUser.rightToLeftLayout-default.png new file mode 100644 index 000000000..f68bad782 Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_deletedMessage_sentByCurrentUser.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_deletedMessage_sentByCurrentUser.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_deletedMessage_sentByCurrentUser.small-dark.png new file mode 100644 index 000000000..468b88c28 Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_deletedMessage_sentByCurrentUser.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_dmChannel_noAuthorPrefix.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_dmChannel_noAuthorPrefix.small-dark.png index a29900f41..48ba3b5ba 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_dmChannel_noAuthorPrefix.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_dmChannel_noAuthorPrefix.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_emptyMessages.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_emptyMessages.default-light.png new file mode 100644 index 000000000..a0cc65a8e Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_emptyMessages.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_emptyMessages.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_emptyMessages.extraExtraExtraLarge-light.png new file mode 100644 index 000000000..c488dd95a Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_emptyMessages.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_emptyMessages.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_emptyMessages.rightToLeftLayout-default.png new file mode 100644 index 000000000..f78e3e76a Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_emptyMessages.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_emptyMessages.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_emptyMessages.small-dark.png new file mode 100644 index 000000000..56b1d291f Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_emptyMessages.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_ephemeralMessageSkipped_showsPreviousMessage.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_ephemeralMessageSkipped_showsPreviousMessage.default-light.png new file mode 100644 index 000000000..c043b2677 Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_ephemeralMessageSkipped_showsPreviousMessage.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_ephemeralMessageSkipped_showsPreviousMessage.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_ephemeralMessageSkipped_showsPreviousMessage.extraExtraExtraLarge-light.png new file mode 100644 index 000000000..0be3d8180 Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_ephemeralMessageSkipped_showsPreviousMessage.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_ephemeralMessageSkipped_showsPreviousMessage.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_ephemeralMessageSkipped_showsPreviousMessage.rightToLeftLayout-default.png new file mode 100644 index 000000000..dae44c82e Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_ephemeralMessageSkipped_showsPreviousMessage.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_ephemeralMessageSkipped_showsPreviousMessage.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_ephemeralMessageSkipped_showsPreviousMessage.small-dark.png new file mode 100644 index 000000000..232b0e964 Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_ephemeralMessageSkipped_showsPreviousMessage.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_fileMessage.1.png b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_fileMessage.1.png index 2e8d36dc3..e1d4ffbc8 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_fileMessage.1.png and b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_fileMessage.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_giphyMessage.1.png b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_giphyMessage.1.png new file mode 100644 index 000000000..ed08b7648 Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_giphyMessage.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_giphyMessageLatestButPreviewIsAnotherMessage.1.png b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_giphyMessageLatestButPreviewIsAnotherMessage.1.png deleted file mode 100644 index 0cfa8e6c0..000000000 Binary files a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_giphyMessageLatestButPreviewIsAnotherMessage.1.png and /dev/null differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_giphyMessage_groupChannel.1.png b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_giphyMessage_groupChannel.1.png new file mode 100644 index 000000000..5cde25fe5 Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_giphyMessage_groupChannel.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_groupChannel_authorNamePrefix.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_groupChannel_authorNamePrefix.small-dark.png index e00870d4b..2b5c1ec1b 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_groupChannel_authorNamePrefix.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_groupChannel_authorNamePrefix.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_groupChannel_imageAttachmentPreview.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_groupChannel_imageAttachmentPreview.default-light.png index 2bce59d34..103a57cd9 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_groupChannel_imageAttachmentPreview.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_groupChannel_imageAttachmentPreview.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_groupChannel_imageAttachmentPreview.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_groupChannel_imageAttachmentPreview.extraExtraExtraLarge-light.png index acf844392..f34156b71 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_groupChannel_imageAttachmentPreview.extraExtraExtraLarge-light.png and b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_groupChannel_imageAttachmentPreview.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_groupChannel_imageAttachmentPreview.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_groupChannel_imageAttachmentPreview.rightToLeftLayout-default.png index 7d124a89e..33156e618 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_groupChannel_imageAttachmentPreview.rightToLeftLayout-default.png and b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_groupChannel_imageAttachmentPreview.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_groupChannel_imageAttachmentPreview.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_groupChannel_imageAttachmentPreview.small-dark.png index 00b2bfc75..f034150e3 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_groupChannel_imageAttachmentPreview.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_groupChannel_imageAttachmentPreview.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_groupChannel_youPrefix.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_groupChannel_youPrefix.small-dark.png index 0a0eb2c5f..b14546072 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_groupChannel_youPrefix.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_groupChannel_youPrefix.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_imageMessage.1.png b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_imageMessage.1.png index 58b7752df..1e79c82ff 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_imageMessage.1.png and b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_imageMessage.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_messageFailedToSend.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_messageFailedToSend.default-light.png index 78823889a..dfa522526 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_messageFailedToSend.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_messageFailedToSend.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_messageFailedToSend.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_messageFailedToSend.extraExtraExtraLarge-light.png index c4b004ac9..459249fcf 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_messageFailedToSend.extraExtraExtraLarge-light.png and b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_messageFailedToSend.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_messageFailedToSend.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_messageFailedToSend.rightToLeftLayout-default.png index 81a456ace..960baa2ac 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_messageFailedToSend.rightToLeftLayout-default.png and b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_messageFailedToSend.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_messageFailedToSend.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_messageFailedToSend.small-dark.png index 2fd441b46..4f54e7fc3 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_messageFailedToSend.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_messageFailedToSend.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_messagePending.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_messagePending.default-light.png new file mode 100644 index 000000000..a0dac8fa7 Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_messagePending.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_messagePending.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_messagePending.extraExtraExtraLarge-light.png new file mode 100644 index 000000000..9767112b0 Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_messagePending.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_messagePending.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_messagePending.rightToLeftLayout-default.png new file mode 100644 index 000000000..fccd28fa1 Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_messagePending.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_messagePending.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_messagePending.small-dark.png new file mode 100644 index 000000000..4793a9e02 Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_messagePending.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_muted_bottomRightCornerStyle.1.png b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_muted_bottomRightCornerStyle.1.png index d1e5a0a8a..152c0d182 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_muted_bottomRightCornerStyle.1.png and b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_muted_bottomRightCornerStyle.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_muted_channelNameStyle.1.png b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_muted_channelNameStyle.1.png index 57fe10de9..ae6b401dc 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_muted_channelNameStyle.1.png and b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_muted_channelNameStyle.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_muted_defaultStyle.1.png b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_muted_defaultStyle.1.png index 38e1a2e37..34db1efcb 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_muted_defaultStyle.1.png and b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_muted_defaultStyle.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_pollMessage_someoneCreated.1.png b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_pollMessage_someoneCreated.1.png index 79c2e72a4..e2f20e9a4 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_pollMessage_someoneCreated.1.png and b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_pollMessage_someoneCreated.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_pollMessage_someoneVoted.1.png b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_pollMessage_someoneVoted.1.png index c87640414..534f61a48 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_pollMessage_someoneVoted.1.png and b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_pollMessage_someoneVoted.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_pollMessage_youCreated.1.png b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_pollMessage_youCreated.1.png index 680a7b139..be4799b9a 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_pollMessage_youCreated.1.png and b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_pollMessage_youCreated.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_pollMessage_youVoted.1.png b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_pollMessage_youVoted.1.png index 7cfbcb334..e1932268a 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_pollMessage_youVoted.1.png and b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_pollMessage_youVoted.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_videoMessage.1.png b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_videoMessage.1.png index 003a28214..5254f0f8f 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_videoMessage.1.png and b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_videoMessage.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_voiceRecordingMessage.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_voiceRecordingMessage.default-light.png index 4d94079e0..b26d12194 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_voiceRecordingMessage.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_voiceRecordingMessage.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_voiceRecordingMessage.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_voiceRecordingMessage.extraExtraExtraLarge-light.png index e0491e4c4..30d1fe772 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_voiceRecordingMessage.extraExtraExtraLarge-light.png and b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_voiceRecordingMessage.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_voiceRecordingMessage.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_voiceRecordingMessage.rightToLeftLayout-default.png index 987c0a282..733b55172 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_voiceRecordingMessage.rightToLeftLayout-default.png and b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_voiceRecordingMessage.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_voiceRecordingMessage.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_voiceRecordingMessage.small-dark.png index 10e96d855..f66c53ef7 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_voiceRecordingMessage.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListItemView_Tests/test_channelListItem_voiceRecordingMessage.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListView_Tests/test_channelListView_channelAvatarUpdated.1.png b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListView_Tests/test_channelListView_channelAvatarUpdated.1.png index 6a57b0e06..b743cc6eb 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListView_Tests/test_channelListView_channelAvatarUpdated.1.png and b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListView_Tests/test_channelListView_channelAvatarUpdated.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListView_Tests/test_channelListView_themedNavigationBar.1.png b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListView_Tests/test_channelListView_themedNavigationBar.1.png index e20c6e68a..7a52cbd88 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListView_Tests/test_channelListView_themedNavigationBar.1.png and b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListView_Tests/test_channelListView_themedNavigationBar.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListView_Tests/test_chatChannelListViewSansNavigation_snapshot.1.png b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListView_Tests/test_chatChannelListViewSansNavigation_snapshot.1.png index 17a7c8805..8bd038c45 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListView_Tests/test_chatChannelListViewSansNavigation_snapshot.1.png and b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListView_Tests/test_chatChannelListViewSansNavigation_snapshot.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListView_Tests/test_chatChannelListView_showChannelListDividerOnLastItem_snapshot.disabled.png b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListView_Tests/test_chatChannelListView_showChannelListDividerOnLastItem_snapshot.disabled.png index 3c556f920..6907e3363 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListView_Tests/test_chatChannelListView_showChannelListDividerOnLastItem_snapshot.disabled.png and b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListView_Tests/test_chatChannelListView_showChannelListDividerOnLastItem_snapshot.disabled.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListView_Tests/test_chatChannelListView_showChannelListDividerOnLastItem_snapshot.enabled.png b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListView_Tests/test_chatChannelListView_showChannelListDividerOnLastItem_snapshot.enabled.png index c50e502f1..3652ade0f 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListView_Tests/test_chatChannelListView_showChannelListDividerOnLastItem_snapshot.enabled.png and b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListView_Tests/test_chatChannelListView_showChannelListDividerOnLastItem_snapshot.enabled.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListView_Tests/test_chatChannelListView_snapshot.1.png b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListView_Tests/test_chatChannelListView_snapshot.1.png index 17a7c8805..8bd038c45 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListView_Tests/test_chatChannelListView_snapshot.1.png and b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListView_Tests/test_chatChannelListView_snapshot.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListView_Tests/test_trailingSwipeActionsView_muted_snapshot.1.png b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListView_Tests/test_trailingSwipeActionsView_muted_snapshot.1.png new file mode 100644 index 000000000..0c721ec3e Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListView_Tests/test_trailingSwipeActionsView_muted_snapshot.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListView_Tests/test_trailingSwipeActionsView_unmuted_snapshot.1.png b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListView_Tests/test_trailingSwipeActionsView_unmuted_snapshot.1.png new file mode 100644 index 000000000..41de2c630 Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/ChatChannelListView_Tests/test_trailingSwipeActionsView_unmuted_snapshot.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/NoChannelsView_Tests/test_noChannelsView_snapshot.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/EmptyChannelsView_Tests/test_emptyChannelsView_snapshot.default-light.png similarity index 100% rename from StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/NoChannelsView_Tests/test_noChannelsView_snapshot.default-light.png rename to StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/EmptyChannelsView_Tests/test_emptyChannelsView_snapshot.default-light.png diff --git a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/NoChannelsView_Tests/test_noChannelsView_snapshot.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/EmptyChannelsView_Tests/test_emptyChannelsView_snapshot.extraExtraExtraLarge-light.png similarity index 100% rename from StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/NoChannelsView_Tests/test_noChannelsView_snapshot.extraExtraExtraLarge-light.png rename to StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/EmptyChannelsView_Tests/test_emptyChannelsView_snapshot.extraExtraExtraLarge-light.png diff --git a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/NoChannelsView_Tests/test_noChannelsView_snapshot.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/EmptyChannelsView_Tests/test_emptyChannelsView_snapshot.rightToLeftLayout-default.png similarity index 100% rename from StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/NoChannelsView_Tests/test_noChannelsView_snapshot.rightToLeftLayout-default.png rename to StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/EmptyChannelsView_Tests/test_emptyChannelsView_snapshot.rightToLeftLayout-default.png diff --git a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/EmptyChannelsView_Tests/test_emptyChannelsView_snapshot.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/EmptyChannelsView_Tests/test_emptyChannelsView_snapshot.small-dark.png new file mode 100644 index 000000000..c302dfd69 Binary files /dev/null and b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/EmptyChannelsView_Tests/test_emptyChannelsView_snapshot.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/LoadingView_Tests/test_redactedLoadingView_snapshot.1.png b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/LoadingView_Tests/test_redactedLoadingView_snapshot.1.png index ea918f1e2..e3192a4e1 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/LoadingView_Tests/test_redactedLoadingView_snapshot.1.png and b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/LoadingView_Tests/test_redactedLoadingView_snapshot.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/MoreChannelActionsView_Tests/test_moreChannelActionsView_archivedDMChannel_snapshot.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/MoreChannelActionsView_Tests/test_moreChannelActionsView_archivedDMChannel_snapshot.default-light.png index b63fa3cb2..bdb08d890 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/MoreChannelActionsView_Tests/test_moreChannelActionsView_archivedDMChannel_snapshot.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/MoreChannelActionsView_Tests/test_moreChannelActionsView_archivedDMChannel_snapshot.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/MoreChannelActionsView_Tests/test_moreChannelActionsView_archivedDMChannel_snapshot.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/MoreChannelActionsView_Tests/test_moreChannelActionsView_archivedDMChannel_snapshot.extraExtraExtraLarge-light.png index 48b362af2..c84a9d766 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/MoreChannelActionsView_Tests/test_moreChannelActionsView_archivedDMChannel_snapshot.extraExtraExtraLarge-light.png and b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/MoreChannelActionsView_Tests/test_moreChannelActionsView_archivedDMChannel_snapshot.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/MoreChannelActionsView_Tests/test_moreChannelActionsView_archivedDMChannel_snapshot.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/MoreChannelActionsView_Tests/test_moreChannelActionsView_archivedDMChannel_snapshot.rightToLeftLayout-default.png index 07d05c49d..04d767a0d 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/MoreChannelActionsView_Tests/test_moreChannelActionsView_archivedDMChannel_snapshot.rightToLeftLayout-default.png and b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/MoreChannelActionsView_Tests/test_moreChannelActionsView_archivedDMChannel_snapshot.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/MoreChannelActionsView_Tests/test_moreChannelActionsView_archivedDMChannel_snapshot.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/MoreChannelActionsView_Tests/test_moreChannelActionsView_archivedDMChannel_snapshot.small-dark.png index 99bf5def3..d74ce1c23 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/MoreChannelActionsView_Tests/test_moreChannelActionsView_archivedDMChannel_snapshot.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/MoreChannelActionsView_Tests/test_moreChannelActionsView_archivedDMChannel_snapshot.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/MoreChannelActionsView_Tests/test_moreChannelActionsView_groupChannel_snapshot.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/MoreChannelActionsView_Tests/test_moreChannelActionsView_groupChannel_snapshot.default-light.png index 05bfc569e..80cfd1800 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/MoreChannelActionsView_Tests/test_moreChannelActionsView_groupChannel_snapshot.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/MoreChannelActionsView_Tests/test_moreChannelActionsView_groupChannel_snapshot.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/MoreChannelActionsView_Tests/test_moreChannelActionsView_groupChannel_snapshot.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/MoreChannelActionsView_Tests/test_moreChannelActionsView_groupChannel_snapshot.extraExtraExtraLarge-light.png index a2a23d5c2..d9032fbd9 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/MoreChannelActionsView_Tests/test_moreChannelActionsView_groupChannel_snapshot.extraExtraExtraLarge-light.png and b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/MoreChannelActionsView_Tests/test_moreChannelActionsView_groupChannel_snapshot.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/MoreChannelActionsView_Tests/test_moreChannelActionsView_groupChannel_snapshot.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/MoreChannelActionsView_Tests/test_moreChannelActionsView_groupChannel_snapshot.rightToLeftLayout-default.png index b9f67f150..33991c38a 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/MoreChannelActionsView_Tests/test_moreChannelActionsView_groupChannel_snapshot.rightToLeftLayout-default.png and b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/MoreChannelActionsView_Tests/test_moreChannelActionsView_groupChannel_snapshot.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/MoreChannelActionsView_Tests/test_moreChannelActionsView_groupChannel_snapshot.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/MoreChannelActionsView_Tests/test_moreChannelActionsView_groupChannel_snapshot.small-dark.png index 19599da54..9bbe5b6df 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/MoreChannelActionsView_Tests/test_moreChannelActionsView_groupChannel_snapshot.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/MoreChannelActionsView_Tests/test_moreChannelActionsView_groupChannel_snapshot.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/MoreChannelActionsView_Tests/test_moreChannelActionsView_groupWithLeaveConversation_snapshot.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/MoreChannelActionsView_Tests/test_moreChannelActionsView_groupWithLeaveConversation_snapshot.default-light.png index b2fc92091..4958ab4f4 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/MoreChannelActionsView_Tests/test_moreChannelActionsView_groupWithLeaveConversation_snapshot.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/MoreChannelActionsView_Tests/test_moreChannelActionsView_groupWithLeaveConversation_snapshot.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/MoreChannelActionsView_Tests/test_moreChannelActionsView_groupWithLeaveConversation_snapshot.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/MoreChannelActionsView_Tests/test_moreChannelActionsView_groupWithLeaveConversation_snapshot.extraExtraExtraLarge-light.png index b739ab16b..de7552825 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/MoreChannelActionsView_Tests/test_moreChannelActionsView_groupWithLeaveConversation_snapshot.extraExtraExtraLarge-light.png and b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/MoreChannelActionsView_Tests/test_moreChannelActionsView_groupWithLeaveConversation_snapshot.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/MoreChannelActionsView_Tests/test_moreChannelActionsView_groupWithLeaveConversation_snapshot.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/MoreChannelActionsView_Tests/test_moreChannelActionsView_groupWithLeaveConversation_snapshot.rightToLeftLayout-default.png index 6ec2852fe..fd4f52104 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/MoreChannelActionsView_Tests/test_moreChannelActionsView_groupWithLeaveConversation_snapshot.rightToLeftLayout-default.png and b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/MoreChannelActionsView_Tests/test_moreChannelActionsView_groupWithLeaveConversation_snapshot.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/MoreChannelActionsView_Tests/test_moreChannelActionsView_groupWithLeaveConversation_snapshot.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/MoreChannelActionsView_Tests/test_moreChannelActionsView_groupWithLeaveConversation_snapshot.small-dark.png index 798a5a6c7..72a55967c 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/MoreChannelActionsView_Tests/test_moreChannelActionsView_groupWithLeaveConversation_snapshot.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/MoreChannelActionsView_Tests/test_moreChannelActionsView_groupWithLeaveConversation_snapshot.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/MoreChannelActionsView_Tests/test_moreChannelActionsView_mutedDMChannel_snapshot.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/MoreChannelActionsView_Tests/test_moreChannelActionsView_mutedDMChannel_snapshot.default-light.png index b3f78c51e..3e30d9cd3 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/MoreChannelActionsView_Tests/test_moreChannelActionsView_mutedDMChannel_snapshot.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/MoreChannelActionsView_Tests/test_moreChannelActionsView_mutedDMChannel_snapshot.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/MoreChannelActionsView_Tests/test_moreChannelActionsView_mutedDMChannel_snapshot.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/MoreChannelActionsView_Tests/test_moreChannelActionsView_mutedDMChannel_snapshot.extraExtraExtraLarge-light.png index 94246ffaf..dfc87aaa9 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/MoreChannelActionsView_Tests/test_moreChannelActionsView_mutedDMChannel_snapshot.extraExtraExtraLarge-light.png and b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/MoreChannelActionsView_Tests/test_moreChannelActionsView_mutedDMChannel_snapshot.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/MoreChannelActionsView_Tests/test_moreChannelActionsView_mutedDMChannel_snapshot.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/MoreChannelActionsView_Tests/test_moreChannelActionsView_mutedDMChannel_snapshot.rightToLeftLayout-default.png index 730b24fb3..905f08878 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/MoreChannelActionsView_Tests/test_moreChannelActionsView_mutedDMChannel_snapshot.rightToLeftLayout-default.png and b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/MoreChannelActionsView_Tests/test_moreChannelActionsView_mutedDMChannel_snapshot.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/MoreChannelActionsView_Tests/test_moreChannelActionsView_mutedDMChannel_snapshot.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/MoreChannelActionsView_Tests/test_moreChannelActionsView_mutedDMChannel_snapshot.small-dark.png index 64d86b179..7b4a2be28 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/MoreChannelActionsView_Tests/test_moreChannelActionsView_mutedDMChannel_snapshot.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/MoreChannelActionsView_Tests/test_moreChannelActionsView_mutedDMChannel_snapshot.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/MoreChannelActionsView_Tests/test_moreChannelActionsView_snapshot.default-light.png b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/MoreChannelActionsView_Tests/test_moreChannelActionsView_snapshot.default-light.png index 7af9896b1..bdb08d890 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/MoreChannelActionsView_Tests/test_moreChannelActionsView_snapshot.default-light.png and b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/MoreChannelActionsView_Tests/test_moreChannelActionsView_snapshot.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/MoreChannelActionsView_Tests/test_moreChannelActionsView_snapshot.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/MoreChannelActionsView_Tests/test_moreChannelActionsView_snapshot.extraExtraExtraLarge-light.png index 6001c0709..c84a9d766 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/MoreChannelActionsView_Tests/test_moreChannelActionsView_snapshot.extraExtraExtraLarge-light.png and b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/MoreChannelActionsView_Tests/test_moreChannelActionsView_snapshot.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/MoreChannelActionsView_Tests/test_moreChannelActionsView_snapshot.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/MoreChannelActionsView_Tests/test_moreChannelActionsView_snapshot.rightToLeftLayout-default.png index 23a887f9b..04d767a0d 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/MoreChannelActionsView_Tests/test_moreChannelActionsView_snapshot.rightToLeftLayout-default.png and b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/MoreChannelActionsView_Tests/test_moreChannelActionsView_snapshot.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/MoreChannelActionsView_Tests/test_moreChannelActionsView_snapshot.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/MoreChannelActionsView_Tests/test_moreChannelActionsView_snapshot.small-dark.png index 2e19c8317..d74ce1c23 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/MoreChannelActionsView_Tests/test_moreChannelActionsView_snapshot.small-dark.png and b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/MoreChannelActionsView_Tests/test_moreChannelActionsView_snapshot.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/NoChannelsView_Tests/test_noChannelsView_snapshot.small-dark.png b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/NoChannelsView_Tests/test_noChannelsView_snapshot.small-dark.png deleted file mode 100644 index a26085cc4..000000000 Binary files a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/NoChannelsView_Tests/test_noChannelsView_snapshot.small-dark.png and /dev/null differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/SearchResultsView_Tests/test_searchResultsView_channelAvatarUpdated.1.png b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/SearchResultsView_Tests/test_searchResultsView_channelAvatarUpdated.1.png index aa40f475a..fcc2d4b36 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/SearchResultsView_Tests/test_searchResultsView_channelAvatarUpdated.1.png and b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/SearchResultsView_Tests/test_searchResultsView_channelAvatarUpdated.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/SearchResultsView_Tests/test_searchResultsView_snapshotLoading.1.png b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/SearchResultsView_Tests/test_searchResultsView_snapshotLoading.1.png index bc923b8d4..921dc0930 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/SearchResultsView_Tests/test_searchResultsView_snapshotLoading.1.png and b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/SearchResultsView_Tests/test_searchResultsView_snapshotLoading.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/SearchResultsView_Tests/test_searchResultsView_snapshotNoResults.1.png b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/SearchResultsView_Tests/test_searchResultsView_snapshotNoResults.1.png index f76467930..eafb68517 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/SearchResultsView_Tests/test_searchResultsView_snapshotNoResults.1.png and b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/SearchResultsView_Tests/test_searchResultsView_snapshotNoResults.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/SearchResultsView_Tests/test_searchResultsView_snapshotResults.1.png b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/SearchResultsView_Tests/test_searchResultsView_snapshotResults.1.png index 66b1eb17a..50e017bdc 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/SearchResultsView_Tests/test_searchResultsView_snapshotResults.1.png and b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/SearchResultsView_Tests/test_searchResultsView_snapshotResults.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/SearchResultsView_Tests/test_searchResultsView_snapshotResults_whenChannelSearch.1.png b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/SearchResultsView_Tests/test_searchResultsView_snapshotResults_whenChannelSearch.1.png index a9687f142..b693ee952 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/SearchResultsView_Tests/test_searchResultsView_snapshotResults_whenChannelSearch.1.png and b/StreamChatSwiftUITests/Tests/ChatChannelList/__Snapshots__/SearchResultsView_Tests/test_searchResultsView_snapshotResults_whenChannelSearch.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatThreadList/__Snapshots__/ChatThreadListItemView_Tests/test_threadListItem_whenAttachments.1.png b/StreamChatSwiftUITests/Tests/ChatThreadList/__Snapshots__/ChatThreadListItemView_Tests/test_threadListItem_whenAttachments.1.png index 98668cfe3..1fabcaa8c 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatThreadList/__Snapshots__/ChatThreadListItemView_Tests/test_threadListItem_whenAttachments.1.png and b/StreamChatSwiftUITests/Tests/ChatThreadList/__Snapshots__/ChatThreadListItemView_Tests/test_threadListItem_whenAttachments.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatThreadList/__Snapshots__/ChatThreadListView_Tests/test_chatThreadListView_empty.1.png b/StreamChatSwiftUITests/Tests/ChatThreadList/__Snapshots__/ChatThreadListView_Tests/test_chatThreadListView_empty.1.png index 919101b10..13cb5a7a4 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatThreadList/__Snapshots__/ChatThreadListView_Tests/test_chatThreadListView_empty.1.png and b/StreamChatSwiftUITests/Tests/ChatThreadList/__Snapshots__/ChatThreadListView_Tests/test_chatThreadListView_empty.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatThreadList/__Snapshots__/ChatThreadListView_Tests/test_chatThreadListView_errorLoadingMoreThreads.1.png b/StreamChatSwiftUITests/Tests/ChatThreadList/__Snapshots__/ChatThreadListView_Tests/test_chatThreadListView_errorLoadingMoreThreads.1.png index 9f1be484a..f41e5d95c 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatThreadList/__Snapshots__/ChatThreadListView_Tests/test_chatThreadListView_errorLoadingMoreThreads.1.png and b/StreamChatSwiftUITests/Tests/ChatThreadList/__Snapshots__/ChatThreadListView_Tests/test_chatThreadListView_errorLoadingMoreThreads.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatThreadList/__Snapshots__/ChatThreadListView_Tests/test_chatThreadListView_errorLoadingThreads.1.png b/StreamChatSwiftUITests/Tests/ChatThreadList/__Snapshots__/ChatThreadListView_Tests/test_chatThreadListView_errorLoadingThreads.1.png index 919101b10..13cb5a7a4 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatThreadList/__Snapshots__/ChatThreadListView_Tests/test_chatThreadListView_errorLoadingThreads.1.png and b/StreamChatSwiftUITests/Tests/ChatThreadList/__Snapshots__/ChatThreadListView_Tests/test_chatThreadListView_errorLoadingThreads.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatThreadList/__Snapshots__/ChatThreadListView_Tests/test_chatThreadListView_loading.1.png b/StreamChatSwiftUITests/Tests/ChatThreadList/__Snapshots__/ChatThreadListView_Tests/test_chatThreadListView_loading.1.png index 9f387c6cb..78940ae00 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatThreadList/__Snapshots__/ChatThreadListView_Tests/test_chatThreadListView_loading.1.png and b/StreamChatSwiftUITests/Tests/ChatThreadList/__Snapshots__/ChatThreadListView_Tests/test_chatThreadListView_loading.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatThreadList/__Snapshots__/ChatThreadListView_Tests/test_chatThreadListView_loadingMoreThreads.1.png b/StreamChatSwiftUITests/Tests/ChatThreadList/__Snapshots__/ChatThreadListView_Tests/test_chatThreadListView_loadingMoreThreads.1.png index f041bf17e..1eacd619f 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatThreadList/__Snapshots__/ChatThreadListView_Tests/test_chatThreadListView_loadingMoreThreads.1.png and b/StreamChatSwiftUITests/Tests/ChatThreadList/__Snapshots__/ChatThreadListView_Tests/test_chatThreadListView_loadingMoreThreads.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatThreadList/__Snapshots__/ChatThreadListView_Tests/test_chatThreadListView_reloadingThreads.1.png b/StreamChatSwiftUITests/Tests/ChatThreadList/__Snapshots__/ChatThreadListView_Tests/test_chatThreadListView_reloadingThreads.1.png index a6d16b616..98cfd2114 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatThreadList/__Snapshots__/ChatThreadListView_Tests/test_chatThreadListView_reloadingThreads.1.png and b/StreamChatSwiftUITests/Tests/ChatThreadList/__Snapshots__/ChatThreadListView_Tests/test_chatThreadListView_reloadingThreads.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatThreadList/__Snapshots__/ChatThreadListView_Tests/test_chatThreadListView_whenNewThreadsAvailable.1.png b/StreamChatSwiftUITests/Tests/ChatThreadList/__Snapshots__/ChatThreadListView_Tests/test_chatThreadListView_whenNewThreadsAvailable.1.png index 2a734960f..08a120195 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatThreadList/__Snapshots__/ChatThreadListView_Tests/test_chatThreadListView_whenNewThreadsAvailable.1.png and b/StreamChatSwiftUITests/Tests/ChatThreadList/__Snapshots__/ChatThreadListView_Tests/test_chatThreadListView_whenNewThreadsAvailable.1.png differ diff --git a/StreamChatSwiftUITests/Tests/ChatThreadList/__Snapshots__/ChatThreadListView_Tests/test_chatThreadListView_withThreads.1.png b/StreamChatSwiftUITests/Tests/ChatThreadList/__Snapshots__/ChatThreadListView_Tests/test_chatThreadListView_withThreads.1.png index 4055c3a75..8b5b9191c 100644 Binary files a/StreamChatSwiftUITests/Tests/ChatThreadList/__Snapshots__/ChatThreadListView_Tests/test_chatThreadListView_withThreads.1.png and b/StreamChatSwiftUITests/Tests/ChatThreadList/__Snapshots__/ChatThreadListView_Tests/test_chatThreadListView_withThreads.1.png differ diff --git a/StreamChatSwiftUITests/Tests/CommonViews/Avatars/ChannelAvatar_Tests.swift b/StreamChatSwiftUITests/Tests/CommonViews/Avatars/ChannelAvatar_Tests.swift index 91aad1091..d50965958 100644 --- a/StreamChatSwiftUITests/Tests/CommonViews/Avatars/ChannelAvatar_Tests.swift +++ b/StreamChatSwiftUITests/Tests/CommonViews/Avatars/ChannelAvatar_Tests.swift @@ -12,179 +12,206 @@ import XCTest final class ChannelAvatar_Tests: StreamChatTestCase { func test_channelAvatar_placeholders() async throws { - // Given + // Given — group channel with no image and no members shows placeholder at every size + let channel = ChatChannel.mock( + cid: .unique, + memberCount: 0 + ) let size = CGSize(width: 320, height: 320) let view = HStack(spacing: 2) { VStack(spacing: 2) { ForEach(AvatarSize.standardSizes, id: \.self) { size in - ChannelAvatar( - url: nil, - size: size, - stackedPlaceholders: [], - memberCount: 0 - ) + ChannelAvatar(channel: channel, size: size) } } VStack(spacing: 2) { ForEach(AvatarSize.standardSizes, id: \.self) { size in - ChannelAvatar( - url: nil, - size: size, - stackedPlaceholders: [], - memberCount: 0 - ) + ChannelAvatar(channel: channel, size: size) } } VStack(spacing: 2) { ForEach(AvatarSize.standardSizes, id: \.self) { size in - ChannelAvatar( - url: nil, - size: size, - stackedPlaceholders: [], - memberCount: 0, - indicator: .online - ) + ChannelAvatar(channel: channel, size: size, indicator: .online) } } VStack(spacing: 2) { ForEach(AvatarSize.standardSizes, id: \.self) { size in - ChannelAvatar( - url: nil, - size: size, - stackedPlaceholders: [], - memberCount: 0, - indicator: .online - ) - .redacted(reason: .placeholder) + ChannelAvatar(channel: channel, size: size, indicator: .online) + .redacted(reason: .placeholder) } } } .frame(width: size.width, height: size.height) - + // Then AssertSnapshot(view, size: size) } - + // MARK: - Stacked Placeholders - + func test_channelAvatar_stackedPlaceholders_singleMember() { // Given — 1 member shows diagonal layout (avatar + generic placeholder) + let channel = mockGroupChannel(memberCount: 1, activeMembers: 1) let size = CGSize(width: 240, height: 100) - let view = stackedRow(placeholderCount: 1, memberCount: 1) + let view = avatarRow(channel: channel) .frame(width: size.width, height: size.height) - + // Then AssertSnapshot(view, size: size) } - + func test_channelAvatar_stackedPlaceholders_twoMembers() { // Given — 2 members shows diagonal layout + let channel = mockGroupChannel(memberCount: 2, activeMembers: 2) let size = CGSize(width: 240, height: 100) - let view = stackedRow(placeholderCount: 2, memberCount: 2) + let view = avatarRow(channel: channel) .frame(width: size.width, height: size.height) - + // Then AssertSnapshot(view, size: size) } - + func test_channelAvatar_stackedPlaceholders_threeMembers() { // Given — 3 members shows triangle layout + let channel = mockGroupChannel(memberCount: 3, activeMembers: 3) let size = CGSize(width: 240, height: 100) - let view = stackedRow(placeholderCount: 3, memberCount: 3) + let view = avatarRow(channel: channel) .frame(width: size.width, height: size.height) - + // Then AssertSnapshot(view, size: size) } - + func test_channelAvatar_stackedPlaceholders_fourMembers() { // Given — 4 members shows 2×2 grid + let channel = mockGroupChannel(memberCount: 4, activeMembers: 4) let size = CGSize(width: 240, height: 100) - let view = stackedRow(placeholderCount: 4, memberCount: 4) + let view = avatarRow(channel: channel) .frame(width: size.width, height: size.height) - + // Then AssertSnapshot(view, size: size) } - + func test_channelAvatar_stackedPlaceholders_overflow() { - // Given — 5+ members shows two avatars + count badge + // Given — 7 members (4 active) shows two avatars + count badge + let channel = mockGroupChannel(memberCount: 7, activeMembers: 4) let size = CGSize(width: 240, height: 100) - let view = stackedRow(placeholderCount: 4, memberCount: 7) + let view = avatarRow(channel: channel) .frame(width: size.width, height: size.height) - + // Then AssertSnapshot(view, size: size) } - + func test_channelAvatar_stackedPlaceholders_overflowClamped() { // Given — overflow badge clamps at +99 + let channel = mockGroupChannel(memberCount: 200, activeMembers: 4) let size = CGSize(width: 240, height: 100) - let view = stackedRow(placeholderCount: 4, memberCount: 200) + let view = avatarRow(channel: channel) .frame(width: size.width, height: size.height) - + // Then AssertSnapshot(view, size: size) } - + func test_channelAvatar_stackedPlaceholders_withOnlineIndicator() { - // Given — stacked layout with presence indicator + // Given — DM channel with online member shows indicator + let channel = mockGroupChannel(memberCount: 2, activeMembers: 2) let size = CGSize(width: 240, height: 100) - let view = stackedRow(placeholderCount: 2, memberCount: 2, indicator: .online) + let view = avatarRow(channel: channel, indicator: .online) .frame(width: size.width, height: size.height) - + // Then AssertSnapshot(view, size: size) } - + func test_channelAvatar_stackedPlaceholders_brokenDataZeroMemberCount() { - // Given — memberCount is 0 (broken data) but 2 members are present + // Given — memberCount is 0 (broken data) but 2 active members are present + let channel = mockGroupChannel(memberCount: 0, activeMembers: 2) let size = CGSize(width: 240, height: 100) - let view = stackedRow(placeholderCount: 2, memberCount: 0) + let view = avatarRow(channel: channel) .frame(width: size.width, height: size.height) - + // Then AssertSnapshot(view, size: size) } - + func test_channelAvatar_stackedPlaceholders_overflowInsufficientUsers() { - // Given — memberCount triggers overflow but too few placeholders to render it; + // Given — memberCount triggers overflow but too few active members to render it; // should fall back to generic PlaceholderView instead of crashing. + let channelNoMembers = mockGroupChannel(memberCount: 5, activeMembers: 0) + let channelOneMember = mockGroupChannel(memberCount: 5, activeMembers: 1) let size = CGSize(width: 240, height: 220) let view = VStack(spacing: 8) { - // 0 placeholders - stackedRow(placeholderCount: 0, memberCount: 5) - // 1 placeholder - stackedRow(placeholderCount: 1, memberCount: 5) + // 0 active members + avatarRow(channel: channelNoMembers) + // 1 active member + avatarRow(channel: channelOneMember) } .frame(width: size.width, height: size.height) - + // Then AssertSnapshot(view, size: size) } - + + func test_channelAvatar_directMessageChannel_twoMembers() { + // Given — DM channel with 2 members should show a single UserAvatar + let channel = mockDMChannel(isOtherMemberOnline: true) + let size = CGSize(width: 240, height: 100) + let view = avatarRow(channel: channel) + .frame(width: size.width, height: size.height) + + // Then + AssertSnapshot(view, size: size) + } + // MARK: - Helpers - - /// Creates a horizontal row of stacked channel avatars at lg, xl, and 2xl sizes. - private func stackedRow( - placeholderCount: Int, - memberCount: Int, - indicator: AvatarIndicator = .none - ) -> some View { - let initials = ["AB", "CD", "EF", "GH"] - let placeholders: [(url: URL?, initials: String)] = (0.. ChatChannel { + let members: [ChatChannelMember] = (0.. ChatChannel { + let otherMember = ChatChannelMember.mock( + id: "other-user", + name: "Alice Baker", + isOnline: isOtherMemberOnline, + memberCreatedAt: Date(timeIntervalSinceReferenceDate: 0) + ) + let currentMember = ChatChannelMember.mock( + id: Self.currentUserId, + name: "Current User", + isOnline: true, + memberCreatedAt: Date(timeIntervalSinceReferenceDate: 1) + ) + return .mockDMChannel( + lastActiveMembers: [otherMember, currentMember], + memberCount: 2 + ) + } + + /// Creates a horizontal row of channel avatars at lg, xl, and 2xl sizes. + private func avatarRow(channel: ChatChannel, indicator: AvatarIndicator = .none) -> some View { let sizes: [CGFloat] = [AvatarSize.large, AvatarSize.extraLarge, AvatarSize.extraExtraLarge] return HStack(spacing: 8) { ForEach(sizes, id: \.self) { size in - ChannelAvatar( - url: nil, - size: size, - stackedPlaceholders: placeholders, - memberCount: memberCount, - indicator: indicator - ) + ChannelAvatar(channel: channel, size: size, indicator: indicator) } } } diff --git a/StreamChatSwiftUITests/Tests/CommonViews/Avatars/__Snapshots__/AvatarStack_Tests/test_avatarStack_overflow.small-dark.png b/StreamChatSwiftUITests/Tests/CommonViews/Avatars/__Snapshots__/AvatarStack_Tests/test_avatarStack_overflow.small-dark.png index cbdb4a86b..f791e5f0b 100644 Binary files a/StreamChatSwiftUITests/Tests/CommonViews/Avatars/__Snapshots__/AvatarStack_Tests/test_avatarStack_overflow.small-dark.png and b/StreamChatSwiftUITests/Tests/CommonViews/Avatars/__Snapshots__/AvatarStack_Tests/test_avatarStack_overflow.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/CommonViews/Avatars/__Snapshots__/AvatarStack_Tests/test_avatarStack_threeAvatars.small-dark.png b/StreamChatSwiftUITests/Tests/CommonViews/Avatars/__Snapshots__/AvatarStack_Tests/test_avatarStack_threeAvatars.small-dark.png index 1cc507746..d44fbf416 100644 Binary files a/StreamChatSwiftUITests/Tests/CommonViews/Avatars/__Snapshots__/AvatarStack_Tests/test_avatarStack_threeAvatars.small-dark.png and b/StreamChatSwiftUITests/Tests/CommonViews/Avatars/__Snapshots__/AvatarStack_Tests/test_avatarStack_threeAvatars.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/CommonViews/Avatars/__Snapshots__/AvatarStack_Tests/test_avatarStack_twoAvatars.small-dark.png b/StreamChatSwiftUITests/Tests/CommonViews/Avatars/__Snapshots__/AvatarStack_Tests/test_avatarStack_twoAvatars.small-dark.png index 3efafda35..16adc7e5f 100644 Binary files a/StreamChatSwiftUITests/Tests/CommonViews/Avatars/__Snapshots__/AvatarStack_Tests/test_avatarStack_twoAvatars.small-dark.png and b/StreamChatSwiftUITests/Tests/CommonViews/Avatars/__Snapshots__/AvatarStack_Tests/test_avatarStack_twoAvatars.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/CommonViews/Avatars/__Snapshots__/ChannelAvatar_Tests/test_channelAvatar_directMessageChannel_twoMembers.default-light.png b/StreamChatSwiftUITests/Tests/CommonViews/Avatars/__Snapshots__/ChannelAvatar_Tests/test_channelAvatar_directMessageChannel_twoMembers.default-light.png new file mode 100644 index 000000000..cd807c982 Binary files /dev/null and b/StreamChatSwiftUITests/Tests/CommonViews/Avatars/__Snapshots__/ChannelAvatar_Tests/test_channelAvatar_directMessageChannel_twoMembers.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/CommonViews/Avatars/__Snapshots__/ChannelAvatar_Tests/test_channelAvatar_directMessageChannel_twoMembers.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/CommonViews/Avatars/__Snapshots__/ChannelAvatar_Tests/test_channelAvatar_directMessageChannel_twoMembers.extraExtraExtraLarge-light.png new file mode 100644 index 000000000..cd807c982 Binary files /dev/null and b/StreamChatSwiftUITests/Tests/CommonViews/Avatars/__Snapshots__/ChannelAvatar_Tests/test_channelAvatar_directMessageChannel_twoMembers.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/CommonViews/Avatars/__Snapshots__/ChannelAvatar_Tests/test_channelAvatar_directMessageChannel_twoMembers.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/CommonViews/Avatars/__Snapshots__/ChannelAvatar_Tests/test_channelAvatar_directMessageChannel_twoMembers.rightToLeftLayout-default.png new file mode 100644 index 000000000..373d78674 Binary files /dev/null and b/StreamChatSwiftUITests/Tests/CommonViews/Avatars/__Snapshots__/ChannelAvatar_Tests/test_channelAvatar_directMessageChannel_twoMembers.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/CommonViews/Avatars/__Snapshots__/ChannelAvatar_Tests/test_channelAvatar_directMessageChannel_twoMembers.small-dark.png b/StreamChatSwiftUITests/Tests/CommonViews/Avatars/__Snapshots__/ChannelAvatar_Tests/test_channelAvatar_directMessageChannel_twoMembers.small-dark.png new file mode 100644 index 000000000..b8b0080a0 Binary files /dev/null and b/StreamChatSwiftUITests/Tests/CommonViews/Avatars/__Snapshots__/ChannelAvatar_Tests/test_channelAvatar_directMessageChannel_twoMembers.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/CommonViews/Avatars/__Snapshots__/ChannelAvatar_Tests/test_channelAvatar_placeholders.small-dark.png b/StreamChatSwiftUITests/Tests/CommonViews/Avatars/__Snapshots__/ChannelAvatar_Tests/test_channelAvatar_placeholders.small-dark.png index f260cbfc4..f41e5db35 100644 Binary files a/StreamChatSwiftUITests/Tests/CommonViews/Avatars/__Snapshots__/ChannelAvatar_Tests/test_channelAvatar_placeholders.small-dark.png and b/StreamChatSwiftUITests/Tests/CommonViews/Avatars/__Snapshots__/ChannelAvatar_Tests/test_channelAvatar_placeholders.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/CommonViews/Avatars/__Snapshots__/ChannelAvatar_Tests/test_channelAvatar_stackedPlaceholders_fourMembers.small-dark.png b/StreamChatSwiftUITests/Tests/CommonViews/Avatars/__Snapshots__/ChannelAvatar_Tests/test_channelAvatar_stackedPlaceholders_fourMembers.small-dark.png index 6a196ab12..6813e195d 100644 Binary files a/StreamChatSwiftUITests/Tests/CommonViews/Avatars/__Snapshots__/ChannelAvatar_Tests/test_channelAvatar_stackedPlaceholders_fourMembers.small-dark.png and b/StreamChatSwiftUITests/Tests/CommonViews/Avatars/__Snapshots__/ChannelAvatar_Tests/test_channelAvatar_stackedPlaceholders_fourMembers.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/CommonViews/Avatars/__Snapshots__/ChannelAvatar_Tests/test_channelAvatar_stackedPlaceholders_overflow.small-dark.png b/StreamChatSwiftUITests/Tests/CommonViews/Avatars/__Snapshots__/ChannelAvatar_Tests/test_channelAvatar_stackedPlaceholders_overflow.small-dark.png index 8fd80525f..6d3af985b 100644 Binary files a/StreamChatSwiftUITests/Tests/CommonViews/Avatars/__Snapshots__/ChannelAvatar_Tests/test_channelAvatar_stackedPlaceholders_overflow.small-dark.png and b/StreamChatSwiftUITests/Tests/CommonViews/Avatars/__Snapshots__/ChannelAvatar_Tests/test_channelAvatar_stackedPlaceholders_overflow.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/CommonViews/Avatars/__Snapshots__/ChannelAvatar_Tests/test_channelAvatar_stackedPlaceholders_overflowClamped.small-dark.png b/StreamChatSwiftUITests/Tests/CommonViews/Avatars/__Snapshots__/ChannelAvatar_Tests/test_channelAvatar_stackedPlaceholders_overflowClamped.small-dark.png index a1aa2db74..8b17efa3e 100644 Binary files a/StreamChatSwiftUITests/Tests/CommonViews/Avatars/__Snapshots__/ChannelAvatar_Tests/test_channelAvatar_stackedPlaceholders_overflowClamped.small-dark.png and b/StreamChatSwiftUITests/Tests/CommonViews/Avatars/__Snapshots__/ChannelAvatar_Tests/test_channelAvatar_stackedPlaceholders_overflowClamped.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/CommonViews/Avatars/__Snapshots__/ChannelAvatar_Tests/test_channelAvatar_stackedPlaceholders_singleMember.small-dark.png b/StreamChatSwiftUITests/Tests/CommonViews/Avatars/__Snapshots__/ChannelAvatar_Tests/test_channelAvatar_stackedPlaceholders_singleMember.small-dark.png index 664a9d428..a3c18e0eb 100644 Binary files a/StreamChatSwiftUITests/Tests/CommonViews/Avatars/__Snapshots__/ChannelAvatar_Tests/test_channelAvatar_stackedPlaceholders_singleMember.small-dark.png and b/StreamChatSwiftUITests/Tests/CommonViews/Avatars/__Snapshots__/ChannelAvatar_Tests/test_channelAvatar_stackedPlaceholders_singleMember.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/CommonViews/Avatars/__Snapshots__/ChannelAvatar_Tests/test_channelAvatar_stackedPlaceholders_threeMembers.small-dark.png b/StreamChatSwiftUITests/Tests/CommonViews/Avatars/__Snapshots__/ChannelAvatar_Tests/test_channelAvatar_stackedPlaceholders_threeMembers.small-dark.png index 7bc283796..60bae6ccb 100644 Binary files a/StreamChatSwiftUITests/Tests/CommonViews/Avatars/__Snapshots__/ChannelAvatar_Tests/test_channelAvatar_stackedPlaceholders_threeMembers.small-dark.png and b/StreamChatSwiftUITests/Tests/CommonViews/Avatars/__Snapshots__/ChannelAvatar_Tests/test_channelAvatar_stackedPlaceholders_threeMembers.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/CommonViews/Avatars/__Snapshots__/ChannelAvatar_Tests/test_channelAvatar_stackedPlaceholders_twoMembers.small-dark.png b/StreamChatSwiftUITests/Tests/CommonViews/Avatars/__Snapshots__/ChannelAvatar_Tests/test_channelAvatar_stackedPlaceholders_twoMembers.small-dark.png index c65293d2d..42392d98d 100644 Binary files a/StreamChatSwiftUITests/Tests/CommonViews/Avatars/__Snapshots__/ChannelAvatar_Tests/test_channelAvatar_stackedPlaceholders_twoMembers.small-dark.png and b/StreamChatSwiftUITests/Tests/CommonViews/Avatars/__Snapshots__/ChannelAvatar_Tests/test_channelAvatar_stackedPlaceholders_twoMembers.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/CommonViews/Avatars/__Snapshots__/ChannelAvatar_Tests/test_channelAvatar_stackedPlaceholders_withOnlineIndicator.small-dark.png b/StreamChatSwiftUITests/Tests/CommonViews/Avatars/__Snapshots__/ChannelAvatar_Tests/test_channelAvatar_stackedPlaceholders_withOnlineIndicator.small-dark.png index bf802a8fb..5a4038e56 100644 Binary files a/StreamChatSwiftUITests/Tests/CommonViews/Avatars/__Snapshots__/ChannelAvatar_Tests/test_channelAvatar_stackedPlaceholders_withOnlineIndicator.small-dark.png and b/StreamChatSwiftUITests/Tests/CommonViews/Avatars/__Snapshots__/ChannelAvatar_Tests/test_channelAvatar_stackedPlaceholders_withOnlineIndicator.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/CommonViews/Avatars/__Snapshots__/UserAvatar_Tests/test_userAvatar_placeholders.default-light.png b/StreamChatSwiftUITests/Tests/CommonViews/Avatars/__Snapshots__/UserAvatar_Tests/test_userAvatar_placeholders.default-light.png index 3f2170dd0..0f6918884 100644 Binary files a/StreamChatSwiftUITests/Tests/CommonViews/Avatars/__Snapshots__/UserAvatar_Tests/test_userAvatar_placeholders.default-light.png and b/StreamChatSwiftUITests/Tests/CommonViews/Avatars/__Snapshots__/UserAvatar_Tests/test_userAvatar_placeholders.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/CommonViews/Avatars/__Snapshots__/UserAvatar_Tests/test_userAvatar_placeholders.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/CommonViews/Avatars/__Snapshots__/UserAvatar_Tests/test_userAvatar_placeholders.extraExtraExtraLarge-light.png index 3f2170dd0..0f6918884 100644 Binary files a/StreamChatSwiftUITests/Tests/CommonViews/Avatars/__Snapshots__/UserAvatar_Tests/test_userAvatar_placeholders.extraExtraExtraLarge-light.png and b/StreamChatSwiftUITests/Tests/CommonViews/Avatars/__Snapshots__/UserAvatar_Tests/test_userAvatar_placeholders.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/CommonViews/Avatars/__Snapshots__/UserAvatar_Tests/test_userAvatar_placeholders.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/CommonViews/Avatars/__Snapshots__/UserAvatar_Tests/test_userAvatar_placeholders.rightToLeftLayout-default.png index fb85bbae2..c4369b0cd 100644 Binary files a/StreamChatSwiftUITests/Tests/CommonViews/Avatars/__Snapshots__/UserAvatar_Tests/test_userAvatar_placeholders.rightToLeftLayout-default.png and b/StreamChatSwiftUITests/Tests/CommonViews/Avatars/__Snapshots__/UserAvatar_Tests/test_userAvatar_placeholders.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/CommonViews/Avatars/__Snapshots__/UserAvatar_Tests/test_userAvatar_placeholders.small-dark.png b/StreamChatSwiftUITests/Tests/CommonViews/Avatars/__Snapshots__/UserAvatar_Tests/test_userAvatar_placeholders.small-dark.png index 813f885b5..62c788b8b 100644 Binary files a/StreamChatSwiftUITests/Tests/CommonViews/Avatars/__Snapshots__/UserAvatar_Tests/test_userAvatar_placeholders.small-dark.png and b/StreamChatSwiftUITests/Tests/CommonViews/Avatars/__Snapshots__/UserAvatar_Tests/test_userAvatar_placeholders.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/CommonViews/NukeImageLoader_Tests.swift b/StreamChatSwiftUITests/Tests/CommonViews/NukeImageLoader_Tests.swift new file mode 100644 index 000000000..d4836cced --- /dev/null +++ b/StreamChatSwiftUITests/Tests/CommonViews/NukeImageLoader_Tests.swift @@ -0,0 +1,153 @@ +// +// Copyright © 2026 Stream.io Inc. All rights reserved. +// + +@testable import StreamChat +@testable import StreamChatSwiftUI +import XCTest + +@MainActor +final class NukeImageLoader_Tests: StreamChatTestCase { + // MARK: - cachedResult + + func test_cachedResult_returnsNil_whenNoKeyStored() { + let url = URL(string: "https://example.com/never-loaded.jpg")! + let result = NukeImageLoader.cachedResult(url: url, resize: nil) + XCTAssertNil(result) + } + + func test_cachedResult_returnsNil_withResize_whenNoKeyStored() { + let url = URL(string: "https://example.com/never-loaded.jpg")! + let resize = ImageResize(CGSize(width: 100, height: 100)) + let result = NukeImageLoader.cachedResult(url: url, resize: resize) + XCTAssertNil(result) + } + + // MARK: - loadImage (cache miss path) + + func test_loadImage_callsOnCacheMiss_whenImageNotCached() async throws { + let url = URL(string: "https://example.com/test-miss-\(UUID().uuidString).jpg")! + let cdnRequester = CDNRequester_Mock() + var cacheMissCalled = false + + do { + _ = try await NukeImageLoader.loadImage( + url: url, + resize: nil, + cdnRequester: cdnRequester, + onCacheMiss: { cacheMissCalled = true } + ) + } catch { + // Network error is expected in tests — we only care about the cache miss callback + } + + XCTAssertTrue(cacheMissCalled) + XCTAssertEqual(cdnRequester.imageRequestCallCount, 1) + XCTAssertEqual(cdnRequester.imageRequestCalledWithURLs, [url]) + } + + func test_loadImage_callsCDNRequester_withCorrectURL() async { + let url = URL(string: "https://example.com/cdn-check-\(UUID().uuidString).jpg")! + let cdnRequester = CDNRequester_Mock() + + do { + _ = try await NukeImageLoader.loadImage( + url: url, + resize: nil, + cdnRequester: cdnRequester + ) + } catch { + // Expected + } + + XCTAssertEqual(cdnRequester.imageRequestCallCount, 1) + XCTAssertEqual(cdnRequester.imageRequestCalledWithURLs.first, url) + } + + // MARK: - loadImage with resize + + func test_loadImage_passesCDNRequester_withResize() async { + let url = URL(string: "https://example.com/resize-\(UUID().uuidString).jpg")! + let cdnRequester = CDNRequester_Mock() + let resize = ImageResize(CGSize(width: 200, height: 150)) + + do { + _ = try await NukeImageLoader.loadImage( + url: url, + resize: resize, + cdnRequester: cdnRequester + ) + } catch { + // Expected + } + + XCTAssertEqual(cdnRequester.imageRequestCallCount, 1) + } + + // MARK: - loadImage (cache hit after CDN transform) + + func test_loadImage_skipsOnCacheMiss_whenCacheHitAfterTransform() async throws { + let testImage = UIImage(systemName: "star.fill")! + let uniqueKey = "cached-key-\(UUID().uuidString)" + let cdnURL = URL(string: "https://cdn.example.com/\(uniqueKey)")! + + let request = ImageRequest( + url: cdnURL, + userInfo: [.imageIdKey: uniqueKey] + ) + ImagePipeline.shared.cache[request] = ImageContainer(image: testImage) + + let cdnRequester = CDNRequester_Mock() + cdnRequester.imageRequestResult = .success( + CDNRequest(url: cdnURL, cachingKey: uniqueKey) + ) + + let originalURL = URL(string: "https://example.com/original-\(uniqueKey)")! + var cacheMissCalled = false + + let result = try await NukeImageLoader.loadImage( + url: originalURL, + resize: nil, + cdnRequester: cdnRequester, + onCacheMiss: { cacheMissCalled = true } + ) + + XCTAssertFalse(cacheMissCalled) + XCTAssertNotNil(result.image) + XCTAssertEqual(cdnRequester.imageRequestCallCount, 1) + + ImagePipeline.shared.cache[request] = nil + } + + // MARK: - cachingKeyMap persistence + + func test_cachedResult_returnsImage_afterLoadStoresCachingKey() async throws { + let testImage = UIImage(systemName: "heart.fill")! + let uniqueKey = "persist-key-\(UUID().uuidString)" + let cdnURL = URL(string: "https://cdn.example.com/\(uniqueKey)")! + let originalURL = URL(string: "https://example.com/\(uniqueKey)")! + + let cdnRequester = CDNRequester_Mock() + cdnRequester.imageRequestResult = .success( + CDNRequest(url: cdnURL, cachingKey: uniqueKey) + ) + + let request = ImageRequest( + url: cdnURL, + userInfo: [.imageIdKey: uniqueKey] + ) + ImagePipeline.shared.cache[request] = ImageContainer(image: testImage) + + _ = try await NukeImageLoader.loadImage( + url: originalURL, + resize: nil, + cdnRequester: cdnRequester + ) + + let cached = NukeImageLoader.cachedResult(url: originalURL, resize: nil) + XCTAssertNotNil(cached) + XCTAssertNotNil(cached?.image) + + ImagePipeline.shared.cache[request] = nil + } +} diff --git a/StreamChatSwiftUITests/Tests/CommonViews/__Snapshots__/AlertBannerViewModifier_Tests/test_alertBanner_snapshot.1.png b/StreamChatSwiftUITests/Tests/CommonViews/__Snapshots__/AlertBannerViewModifier_Tests/test_alertBanner_snapshot.1.png index e85b2290d..99ddd34f3 100644 Binary files a/StreamChatSwiftUITests/Tests/CommonViews/__Snapshots__/AlertBannerViewModifier_Tests/test_alertBanner_snapshot.1.png and b/StreamChatSwiftUITests/Tests/CommonViews/__Snapshots__/AlertBannerViewModifier_Tests/test_alertBanner_snapshot.1.png differ diff --git a/StreamChatSwiftUITests/Tests/CommonViews/__Snapshots__/BadgeCountView_Tests/test_badgeCount_clampedAt99.small-dark.png b/StreamChatSwiftUITests/Tests/CommonViews/__Snapshots__/BadgeCountView_Tests/test_badgeCount_clampedAt99.small-dark.png index 7b62d79a9..ffd029fa4 100644 Binary files a/StreamChatSwiftUITests/Tests/CommonViews/__Snapshots__/BadgeCountView_Tests/test_badgeCount_clampedAt99.small-dark.png and b/StreamChatSwiftUITests/Tests/CommonViews/__Snapshots__/BadgeCountView_Tests/test_badgeCount_clampedAt99.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/CommonViews/__Snapshots__/BadgeCountView_Tests/test_badgeCount_doubleDigit.small-dark.png b/StreamChatSwiftUITests/Tests/CommonViews/__Snapshots__/BadgeCountView_Tests/test_badgeCount_doubleDigit.small-dark.png index 4dc8c4b3c..decdb1f6d 100644 Binary files a/StreamChatSwiftUITests/Tests/CommonViews/__Snapshots__/BadgeCountView_Tests/test_badgeCount_doubleDigit.small-dark.png and b/StreamChatSwiftUITests/Tests/CommonViews/__Snapshots__/BadgeCountView_Tests/test_badgeCount_doubleDigit.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/CommonViews/__Snapshots__/BadgeCountView_Tests/test_badgeCount_singleDigit.small-dark.png b/StreamChatSwiftUITests/Tests/CommonViews/__Snapshots__/BadgeCountView_Tests/test_badgeCount_singleDigit.small-dark.png index 18b0db94d..cd8b1454a 100644 Binary files a/StreamChatSwiftUITests/Tests/CommonViews/__Snapshots__/BadgeCountView_Tests/test_badgeCount_singleDigit.small-dark.png and b/StreamChatSwiftUITests/Tests/CommonViews/__Snapshots__/BadgeCountView_Tests/test_badgeCount_singleDigit.small-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/CommonViews/__Snapshots__/BadgeNotificationView_Tests/test_badgeNotification_allVariations_snapshot.default-dark.png b/StreamChatSwiftUITests/Tests/CommonViews/__Snapshots__/BadgeNotificationView_Tests/test_badgeNotification_allVariations_snapshot.default-dark.png index 77c645f96..de2c44ed6 100644 Binary files a/StreamChatSwiftUITests/Tests/CommonViews/__Snapshots__/BadgeNotificationView_Tests/test_badgeNotification_allVariations_snapshot.default-dark.png and b/StreamChatSwiftUITests/Tests/CommonViews/__Snapshots__/BadgeNotificationView_Tests/test_badgeNotification_allVariations_snapshot.default-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/CommonViews/__Snapshots__/BadgeNotificationView_Tests/test_badgeNotification_allVariations_snapshot.default-light.png b/StreamChatSwiftUITests/Tests/CommonViews/__Snapshots__/BadgeNotificationView_Tests/test_badgeNotification_allVariations_snapshot.default-light.png index 91b86ffcc..34a80d342 100644 Binary files a/StreamChatSwiftUITests/Tests/CommonViews/__Snapshots__/BadgeNotificationView_Tests/test_badgeNotification_allVariations_snapshot.default-light.png and b/StreamChatSwiftUITests/Tests/CommonViews/__Snapshots__/BadgeNotificationView_Tests/test_badgeNotification_allVariations_snapshot.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/CommonViews/__Snapshots__/GalleryHeaderView_Tests/test_customized_snapshot.default-light.png b/StreamChatSwiftUITests/Tests/CommonViews/__Snapshots__/GalleryHeaderView_Tests/test_customized_snapshot.default-light.png index 82defcc4c..81ad1f49f 100644 Binary files a/StreamChatSwiftUITests/Tests/CommonViews/__Snapshots__/GalleryHeaderView_Tests/test_customized_snapshot.default-light.png and b/StreamChatSwiftUITests/Tests/CommonViews/__Snapshots__/GalleryHeaderView_Tests/test_customized_snapshot.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/CommonViews/__Snapshots__/GalleryHeaderView_Tests/test_default_snapshot.default-light.png b/StreamChatSwiftUITests/Tests/CommonViews/__Snapshots__/GalleryHeaderView_Tests/test_default_snapshot.default-light.png index 137f5061d..03784e2fb 100644 Binary files a/StreamChatSwiftUITests/Tests/CommonViews/__Snapshots__/GalleryHeaderView_Tests/test_default_snapshot.default-light.png and b/StreamChatSwiftUITests/Tests/CommonViews/__Snapshots__/GalleryHeaderView_Tests/test_default_snapshot.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/CommonViews/__Snapshots__/SearchBar_Tests/test_searchBar_withText_snapshot.default-dark.png b/StreamChatSwiftUITests/Tests/CommonViews/__Snapshots__/SearchBar_Tests/test_searchBar_withText_snapshot.default-dark.png index a8b68148a..c67644e54 100644 Binary files a/StreamChatSwiftUITests/Tests/CommonViews/__Snapshots__/SearchBar_Tests/test_searchBar_withText_snapshot.default-dark.png and b/StreamChatSwiftUITests/Tests/CommonViews/__Snapshots__/SearchBar_Tests/test_searchBar_withText_snapshot.default-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/CommonViews/__Snapshots__/SnackBarView_Tests/test_snackBarView_default.default-dark.png b/StreamChatSwiftUITests/Tests/CommonViews/__Snapshots__/SnackBarView_Tests/test_snackBarView_default.default-dark.png index d1b42e0af..4254f3930 100644 Binary files a/StreamChatSwiftUITests/Tests/CommonViews/__Snapshots__/SnackBarView_Tests/test_snackBarView_default.default-dark.png and b/StreamChatSwiftUITests/Tests/CommonViews/__Snapshots__/SnackBarView_Tests/test_snackBarView_default.default-dark.png differ diff --git a/StreamChatSwiftUITests/Tests/CommonViews/__Snapshots__/SnackBarView_Tests/test_snackBarView_default.default-light.png b/StreamChatSwiftUITests/Tests/CommonViews/__Snapshots__/SnackBarView_Tests/test_snackBarView_default.default-light.png index defd81ef6..a188495fa 100644 Binary files a/StreamChatSwiftUITests/Tests/CommonViews/__Snapshots__/SnackBarView_Tests/test_snackBarView_default.default-light.png and b/StreamChatSwiftUITests/Tests/CommonViews/__Snapshots__/SnackBarView_Tests/test_snackBarView_default.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/CommonViews/__Snapshots__/SnackBarView_Tests/test_snackBarView_longText.default-light.png b/StreamChatSwiftUITests/Tests/CommonViews/__Snapshots__/SnackBarView_Tests/test_snackBarView_longText.default-light.png index 898ca7b1e..f67a5dd72 100644 Binary files a/StreamChatSwiftUITests/Tests/CommonViews/__Snapshots__/SnackBarView_Tests/test_snackBarView_longText.default-light.png and b/StreamChatSwiftUITests/Tests/CommonViews/__Snapshots__/SnackBarView_Tests/test_snackBarView_longText.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/CommonViews/__Snapshots__/SnackBarView_Tests/test_snackBarView_unmute.default-light.png b/StreamChatSwiftUITests/Tests/CommonViews/__Snapshots__/SnackBarView_Tests/test_snackBarView_unmute.default-light.png index ceb005559..6642d2449 100644 Binary files a/StreamChatSwiftUITests/Tests/CommonViews/__Snapshots__/SnackBarView_Tests/test_snackBarView_unmute.default-light.png and b/StreamChatSwiftUITests/Tests/CommonViews/__Snapshots__/SnackBarView_Tests/test_snackBarView_unmute.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/CommonViews/__Snapshots__/VideoPlayIndicatorView_Tests/test_videoPlayIndicator_default.default-light.png b/StreamChatSwiftUITests/Tests/CommonViews/__Snapshots__/VideoPlayIndicatorView_Tests/test_videoPlayIndicator_default.default-light.png index 88c21719c..54d4427c3 100644 Binary files a/StreamChatSwiftUITests/Tests/CommonViews/__Snapshots__/VideoPlayIndicatorView_Tests/test_videoPlayIndicator_default.default-light.png and b/StreamChatSwiftUITests/Tests/CommonViews/__Snapshots__/VideoPlayIndicatorView_Tests/test_videoPlayIndicator_default.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/CommonViews/__Snapshots__/VideoPlayIndicatorView_Tests/test_videoPlayIndicator_default.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/CommonViews/__Snapshots__/VideoPlayIndicatorView_Tests/test_videoPlayIndicator_default.extraExtraExtraLarge-light.png index 88c21719c..54d4427c3 100644 Binary files a/StreamChatSwiftUITests/Tests/CommonViews/__Snapshots__/VideoPlayIndicatorView_Tests/test_videoPlayIndicator_default.extraExtraExtraLarge-light.png and b/StreamChatSwiftUITests/Tests/CommonViews/__Snapshots__/VideoPlayIndicatorView_Tests/test_videoPlayIndicator_default.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/CommonViews/__Snapshots__/VideoPlayIndicatorView_Tests/test_videoPlayIndicator_default.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/CommonViews/__Snapshots__/VideoPlayIndicatorView_Tests/test_videoPlayIndicator_default.rightToLeftLayout-default.png index ee36f6d2e..0df2813dd 100644 Binary files a/StreamChatSwiftUITests/Tests/CommonViews/__Snapshots__/VideoPlayIndicatorView_Tests/test_videoPlayIndicator_default.rightToLeftLayout-default.png and b/StreamChatSwiftUITests/Tests/CommonViews/__Snapshots__/VideoPlayIndicatorView_Tests/test_videoPlayIndicator_default.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/CommonViews/__Snapshots__/VideoPlayIndicatorView_Tests/test_videoPlayIndicator_playing.default-light.png b/StreamChatSwiftUITests/Tests/CommonViews/__Snapshots__/VideoPlayIndicatorView_Tests/test_videoPlayIndicator_playing.default-light.png index f06c2e5ac..400ac0ec5 100644 Binary files a/StreamChatSwiftUITests/Tests/CommonViews/__Snapshots__/VideoPlayIndicatorView_Tests/test_videoPlayIndicator_playing.default-light.png and b/StreamChatSwiftUITests/Tests/CommonViews/__Snapshots__/VideoPlayIndicatorView_Tests/test_videoPlayIndicator_playing.default-light.png differ diff --git a/StreamChatSwiftUITests/Tests/CommonViews/__Snapshots__/VideoPlayIndicatorView_Tests/test_videoPlayIndicator_playing.extraExtraExtraLarge-light.png b/StreamChatSwiftUITests/Tests/CommonViews/__Snapshots__/VideoPlayIndicatorView_Tests/test_videoPlayIndicator_playing.extraExtraExtraLarge-light.png index f06c2e5ac..400ac0ec5 100644 Binary files a/StreamChatSwiftUITests/Tests/CommonViews/__Snapshots__/VideoPlayIndicatorView_Tests/test_videoPlayIndicator_playing.extraExtraExtraLarge-light.png and b/StreamChatSwiftUITests/Tests/CommonViews/__Snapshots__/VideoPlayIndicatorView_Tests/test_videoPlayIndicator_playing.extraExtraExtraLarge-light.png differ diff --git a/StreamChatSwiftUITests/Tests/CommonViews/__Snapshots__/VideoPlayIndicatorView_Tests/test_videoPlayIndicator_playing.rightToLeftLayout-default.png b/StreamChatSwiftUITests/Tests/CommonViews/__Snapshots__/VideoPlayIndicatorView_Tests/test_videoPlayIndicator_playing.rightToLeftLayout-default.png index f1a3528e7..25ae678d2 100644 Binary files a/StreamChatSwiftUITests/Tests/CommonViews/__Snapshots__/VideoPlayIndicatorView_Tests/test_videoPlayIndicator_playing.rightToLeftLayout-default.png and b/StreamChatSwiftUITests/Tests/CommonViews/__Snapshots__/VideoPlayIndicatorView_Tests/test_videoPlayIndicator_playing.rightToLeftLayout-default.png differ diff --git a/StreamChatSwiftUITests/Tests/StreamChatTestCase.swift b/StreamChatSwiftUITests/Tests/StreamChatTestCase.swift index bb660d905..0cdceec2e 100644 --- a/StreamChatSwiftUITests/Tests/StreamChatTestCase.swift +++ b/StreamChatSwiftUITests/Tests/StreamChatTestCase.swift @@ -32,8 +32,7 @@ import XCTest streamChat = StreamChat( chatClient: chatClient, utils: Utils( - videoPreviewLoader: VideoPreviewLoader_Mock(), - imageLoader: ImageLoader_Mock(), + mediaLoader: MediaLoader_Mock(), composerConfig: .init(isVoiceRecordingEnabled: true) ) ) @@ -55,6 +54,28 @@ import XCTest appearance.colorPalette.navigationBarGlyph = .green } } + + // MARK: - View Hosting + + private var testWindow: UIWindow? + + /// Presents a SwiftUI view in a window so lifecycle modifiers (`.onAppear`, `.onChange`) fire. + @discardableResult + func showView(_ view: V) -> UIHostingController { + let hostingController = UIHostingController(rootView: view) + let window = UIWindow(frame: CGRect(origin: .zero, size: CGSize(width: 200, height: 200))) + window.rootViewController = hostingController + window.makeKeyAndVisible() + testWindow = window + hostingController.view.layoutIfNeeded() + return hostingController + } + + override open func tearDown() { + testWindow?.isHidden = true + testWindow = nil + super.tearDown() + } } // Forces the solid primary button style regardless of platform, diff --git a/StreamChatSwiftUITests/Tests/Utils/ChatClientExtensions_Tests.swift b/StreamChatSwiftUITests/Tests/Utils/ChatClientExtensions_Tests.swift index fd2ff7915..530d5e975 100644 --- a/StreamChatSwiftUITests/Tests/Utils/ChatClientExtensions_Tests.swift +++ b/StreamChatSwiftUITests/Tests/Utils/ChatClientExtensions_Tests.swift @@ -8,6 +8,8 @@ import XCTest final class ChatClientExtensions_Tests: StreamChatTestCase { + private let defaultFallback: Int64 = 100 * 1024 * 1024 + func test_maxAttachmentSize_file() { // Given let expectedValue: Int64 = 512 @@ -16,7 +18,7 @@ final class ChatClientExtensions_Tests: StreamChatTestCase { )) // When - let size = chatClient.maxAttachmentSize(for: .localYodaQuote) + let size = chatClient.maxAttachmentSize(for: .localYodaQuote, fallbackSize: defaultFallback) // Then XCTAssertEqual(size, expectedValue) @@ -30,9 +32,48 @@ final class ChatClientExtensions_Tests: StreamChatTestCase { )) // When - let size = chatClient.maxAttachmentSize(for: .localYodaImage) + let size = chatClient.maxAttachmentSize(for: .localYodaImage, fallbackSize: defaultFallback) // Then XCTAssertEqual(size, expectedValue) } + + func test_maxAttachmentSize_returnsFallback_whenAppSettingsNil() { + // Given — appSettings is nil by default on the mock + let fallback: Int64 = 50 * 1024 * 1024 + + // When + let size = chatClient.maxAttachmentSize(for: .localYodaImage, fallbackSize: fallback) + + // Then + XCTAssertEqual(size, fallback) + } + + func test_maxAttachmentSize_returnsFallback_whenServerLimitIsZero() { + // Given + chatClient.mockedAppSettings = .mock(imageUploadConfig: .mock( + sizeLimitInBytes: 0 + )) + let fallback: Int64 = 75 * 1024 * 1024 + + // When + let size = chatClient.maxAttachmentSize(for: .localYodaImage, fallbackSize: fallback) + + // Then + XCTAssertEqual(size, fallback) + } + + func test_maxAttachmentSize_returnsFallback_whenServerLimitIsNegative() { + // Given + chatClient.mockedAppSettings = .mock(fileUploadConfig: .mock( + sizeLimitInBytes: -1 + )) + let fallback: Int64 = 25 * 1024 * 1024 + + // When + let size = chatClient.maxAttachmentSize(for: .localYodaQuote, fallbackSize: fallback) + + // Then + XCTAssertEqual(size, fallback) + } } diff --git a/StreamChatSwiftUITests/Tests/Utils/ImageCDN_Tests.swift b/StreamChatSwiftUITests/Tests/Utils/ImageCDN_Tests.swift deleted file mode 100644 index b6af7fc59..000000000 --- a/StreamChatSwiftUITests/Tests/Utils/ImageCDN_Tests.swift +++ /dev/null @@ -1,126 +0,0 @@ -// -// Copyright © 2026 Stream.io Inc. All rights reserved. -// - -import Foundation -import StreamChat -@testable import StreamChatSwiftUI -import XCTest - -class ImageCDN_Tests: XCTestCase { - func test_cache_validStreamURL_filtered() { - // Given - let provider = StreamImageCDN() - let url = URL(string: "https://wwww.stream-io-cdn.com/image.jpg?name=Luke&father=Anakin")! - let filteredUrl = "https://wwww.stream-io-cdn.com/image.jpg" - - // When - let key = provider.cachingKey(forImage: url) - - // Then - XCTAssertEqual(key, filteredUrl) - } - - func test_cache_validStreamUrl_withSizeParameters() { - // Given - let provider = StreamImageCDN() - let url = URL(string: "https://wwww.stream-io-cdn.com/image.jpg?name=Luke&w=128&h=128&crop=center&resize=fill&ro=0")! - let filteredUrl = "https://wwww.stream-io-cdn.com/image.jpg?w=128&h=128" - - // When - let key = provider.cachingKey(forImage: url) - - // Then - XCTAssertEqual(key, filteredUrl) - } - - func test_cache_validStreamURL_unchanged() { - // Given - let provider = StreamImageCDN() - let url = URL(string: "https://wwww.stream-io-cdn.com/image.jpg")! - - // When - let key = provider.cachingKey(forImage: url) - - // Then - XCTAssertEqual(key, url.absoluteString) - } - - func test_cache_validURL_unchanged() { - // Given - let provider = StreamImageCDN() - let url = URL(string: "https://wwww.stream.io")! - - // When - let key = provider.cachingKey(forImage: url) - - // Then - XCTAssertEqual(key, url.absoluteString) - } - - func test_cache_invalidURL_unchanged() { - // Given - let provider = StreamImageCDN() - - // When - let url1 = URL(string: "https://abc")! - let key1 = provider.cachingKey(forImage: url1) - - let url2 = URL(string: "abc.def")! - let key2 = provider.cachingKey(forImage: url2) - - // Then - XCTAssertEqual(key1, url1.absoluteString) - XCTAssertEqual(key2, url2.absoluteString) - } - - func test_thumbnail_validStreamUrl_withoutParameters() { - // Given - let provider = StreamImageCDN() - let url = URL(string: "https://wwww.stream-io-cdn.com/image.jpg")! - let size = Int(40 * UIScreen.main.scale) - let thumbnailUrl = URL(string: "https://wwww.stream-io-cdn.com/image.jpg?w=\(size)&h=\(size)&crop=center&resize=fill&ro=0")! - - // When - let processedURL = provider.thumbnailURL( - originalURL: url, - preferredSize: CGSize(width: 40, height: 40) - ) - - // Then - XCTAssertEqual(processedURL, thumbnailUrl) - } - - func test_thumbnail_validStreamUrl_withParameters() { - // Given - let provider = StreamImageCDN() - let url = URL(string: "https://wwww.stream-io-cdn.com/image.jpg?name=Luke")! - let size = Int(40 * UIScreen.main.scale) - let thumbnailUrl = - URL(string: "https://wwww.stream-io-cdn.com/image.jpg?name=Luke&w=\(size)&h=\(size)&crop=center&resize=fill&ro=0")! - - // When - let processedURL = provider.thumbnailURL( - originalURL: url, - preferredSize: CGSize(width: 40, height: 40) - ) - - // Then - XCTAssertEqual(processedURL, thumbnailUrl) - } - - func test_thumbnail_validURL_unchanged() { - // Given - let provider = StreamImageCDN() - let url = URL(string: "https://wwww.stream.io")! - - // When - let processedURL = provider.thumbnailURL( - originalURL: url, - preferredSize: CGSize(width: 40, height: 40) - ) - - // Then - XCTAssertEqual(processedURL, url) - } -} diff --git a/StreamChatSwiftUITests/Tests/Utils/MediaLoader_Tests.swift b/StreamChatSwiftUITests/Tests/Utils/MediaLoader_Tests.swift new file mode 100644 index 000000000..3010af98d --- /dev/null +++ b/StreamChatSwiftUITests/Tests/Utils/MediaLoader_Tests.swift @@ -0,0 +1,223 @@ +// +// Copyright © 2026 Stream.io Inc. All rights reserved. +// + +import AVKit +@testable import StreamChat +import StreamChatCommonUI +@testable import StreamChatSwiftUI +import XCTest + +class MediaLoader_Tests: StreamChatTestCase { + private let testURL = URL(string: "https://example.com/video.mp4")! + private let thumbnailURL = URL(string: "https://example.com/thumbnail.jpg")! + private let cdnRequester = CDNRequester_Mock() + + // MARK: - Custom conformer + + func test_loadVideoPreviewWithAttachment_customImplementationCalled() { + let loader = CustomMediaLoader() + let attachment = makeVideoAttachment(thumbnailURL: thumbnailURL) + + let expectation = expectation(description: "Completion called") + var receivedPreview: MediaLoaderVideoPreview? + loader.loadVideoPreview(with: attachment, options: VideoLoadOptions(cdnRequester: cdnRequester)) { result in + receivedPreview = try? result.get() + expectation.fulfill() + } + + waitForExpectations(timeout: 1) + XCTAssertTrue(loader.loadVideoPreviewCalled) + XCTAssertNotNil(receivedPreview?.image) + } + + func test_loadVideoPreviewWithAttachment_receivesCorrectAttachment() { + let loader = CustomMediaLoader() + let attachment = makeVideoAttachment(thumbnailURL: thumbnailURL) + + let expectation = expectation(description: "Completion called") + loader.loadVideoPreview(with: attachment, options: VideoLoadOptions(cdnRequester: cdnRequester)) { _ in + expectation.fulfill() + } + + waitForExpectations(timeout: 1) + XCTAssertEqual(loader.receivedAttachment?.videoURL, attachment.videoURL) + XCTAssertEqual(loader.receivedAttachment?.payload.thumbnailURL, thumbnailURL) + } + + // MARK: - StreamMediaLoader loadImage + + func test_streamMediaLoader_loadImage_callsDownloader() { + let expectedImage = UIImage(systemName: "star.fill")! + let downloader = ConfigurableImageDownloader(result: .success(expectedImage)) + let mediaLoader = StreamMediaLoader(downloader: downloader) + let url = URL(string: "https://example.com/image.jpg")! + + let expectation = expectation(description: "Completion called") + var receivedImage: MediaLoaderImage? + mediaLoader.loadImage(url: url, options: ImageLoadOptions(cdnRequester: cdnRequester)) { result in + receivedImage = try? result.get() + expectation.fulfill() + } + + waitForExpectations(timeout: 1) + XCTAssertTrue(downloader.downloadImageCalled) + XCTAssertEqual(receivedImage?.image, expectedImage) + } + + func test_streamMediaLoader_loadImage_returnsError_whenURLNil() { + let downloader = ConfigurableImageDownloader(result: .success(UIImage())) + let mediaLoader = StreamMediaLoader(downloader: downloader) + + let expectation = expectation(description: "Completion called") + var receivedError: Error? + mediaLoader.loadImage(url: nil, options: ImageLoadOptions(cdnRequester: cdnRequester)) { result in + if case let .failure(error) = result { + receivedError = error + } + expectation.fulfill() + } + + waitForExpectations(timeout: 1) + XCTAssertNotNil(receivedError) + XCTAssertFalse(downloader.downloadImageCalled) + } + + func test_streamMediaLoader_loadImage_propagatesDownloaderError() { + let expectedError = NSError(domain: "test", code: 42) + let downloader = ConfigurableImageDownloader(result: .failure(expectedError)) + let mediaLoader = StreamMediaLoader(downloader: downloader) + let url = URL(string: "https://example.com/fail.jpg")! + + let expectation = expectation(description: "Completion called") + var receivedError: NSError? + mediaLoader.loadImage(url: url, options: ImageLoadOptions(cdnRequester: cdnRequester)) { result in + if case let .failure(error) = result { + receivedError = error as NSError + } + expectation.fulfill() + } + + waitForExpectations(timeout: 1) + XCTAssertEqual(receivedError?.code, 42) + } + + // MARK: - StreamMediaLoader with attachment + + func test_streamMediaLoader_withAttachment_whenThumbnailURLExists_loadsThumbnailImage() { + let thumbnailImage = UIImage(systemName: "star.fill")! + let downloader = ConfigurableImageDownloader(result: .success(thumbnailImage)) + let mediaLoader = StreamMediaLoader(downloader: downloader) + let attachment = makeVideoAttachment(thumbnailURL: thumbnailURL) + + let expectation = expectation(description: "Completion called") + var receivedPreview: MediaLoaderVideoPreview? + mediaLoader.loadVideoPreview(with: attachment, options: VideoLoadOptions(cdnRequester: cdnRequester)) { result in + receivedPreview = try? result.get() + expectation.fulfill() + } + + waitForExpectations(timeout: 1) + XCTAssertTrue(downloader.downloadImageCalled) + XCTAssertEqual(receivedPreview?.image, thumbnailImage) + } + + func test_streamMediaLoader_withAttachment_whenNoThumbnailURL_doesNotCallImageDownloader() { + let downloader = ConfigurableImageDownloader(result: .success(UIImage())) + let mediaLoader = StreamMediaLoader(downloader: downloader) + let attachment = makeVideoAttachment(thumbnailURL: nil) + + let expectation = expectation(description: "Completion called") + mediaLoader.loadVideoPreview(with: attachment, options: VideoLoadOptions(cdnRequester: cdnRequester)) { _ in + expectation.fulfill() + } + + waitForExpectations(timeout: 5) + XCTAssertFalse(downloader.downloadImageCalled) + } + + // MARK: - Helpers + + private func makeVideoAttachment( + thumbnailURL: URL? = nil + ) -> ChatMessageVideoAttachment { + let attachmentFile = AttachmentFile(type: .mp4, size: 0, mimeType: "video/mp4") + return ChatMessageVideoAttachment( + id: .unique, + type: .video, + payload: VideoAttachmentPayload( + title: "test", + videoRemoteURL: testURL, + thumbnailURL: thumbnailURL, + file: attachmentFile, + extraData: nil + ), + downloadingState: nil, + uploadingState: nil + ) + } +} + +// MARK: - Test Doubles + +private class CustomMediaLoader: MediaLoader, @unchecked Sendable { + var loadVideoPreviewCalled = false + var receivedAttachment: ChatMessageVideoAttachment? + + func loadImage( + url: URL?, + options: ImageLoadOptions, + completion: @escaping @MainActor (Result) -> Void + ) { + Task { @MainActor in completion(.failure(NSError(domain: "stub", code: 0))) } + } + + func loadVideoAsset( + at url: URL, + options: VideoLoadOptions, + completion: @escaping @MainActor (Result) -> Void + ) { + Task { @MainActor in completion(.success(MediaLoaderVideoAsset(asset: AVURLAsset(url: url)))) } + } + + func loadVideoPreview( + with attachment: ChatMessageVideoAttachment, + options: VideoLoadOptions, + completion: @escaping @MainActor (Result) -> Void + ) { + loadVideoPreviewCalled = true + receivedAttachment = attachment + Task { @MainActor in completion(.success(MediaLoaderVideoPreview(image: UIImage()))) } + } + + func loadVideoPreview( + at url: URL, + options: VideoLoadOptions, + completion: @escaping @MainActor (Result) -> Void + ) { + Task { @MainActor in completion(.success(MediaLoaderVideoPreview(image: UIImage()))) } + } +} + +private class ConfigurableImageDownloader: ImageDownloading, @unchecked Sendable { + var downloadImageCalled = false + var receivedURL: URL? + private let result: Result + + init(result: Result) { + self.result = result + } + + func downloadImage( + url: URL, + options: ImageDownloadingOptions, + completion: @escaping @MainActor (Result) -> Void + ) { + downloadImageCalled = true + receivedURL = url + let result = self.result + Task { @MainActor in + completion(result.map { DownloadedImage(image: $0) }) + } + } +} diff --git a/StreamChatSwiftUITests/Tests/Utils/MessagePreviewFormatter_Tests.swift b/StreamChatSwiftUITests/Tests/Utils/MessagePreviewFormatter_Tests.swift index 5135d7a7b..061d2a1b5 100644 --- a/StreamChatSwiftUITests/Tests/Utils/MessagePreviewFormatter_Tests.swift +++ b/StreamChatSwiftUITests/Tests/Utils/MessagePreviewFormatter_Tests.swift @@ -23,7 +23,7 @@ import XCTest ) let channel = ChatChannel.mockDMChannel( memberCount: 2, - previewMessage: message + latestMessages: [message] ) // When @@ -43,7 +43,7 @@ import XCTest isSentByCurrentUser: true ) let channel = ChatChannel.mockNonDMChannel( - previewMessage: message + latestMessages: [message] ) // When @@ -63,7 +63,7 @@ import XCTest isSentByCurrentUser: false ) let channel = ChatChannel.mockNonDMChannel( - previewMessage: message + latestMessages: [message] ) // When @@ -84,7 +84,7 @@ import XCTest isSentByCurrentUser: false ) let channel = ChatChannel.mockNonDMChannel( - previewMessage: message + latestMessages: [message] ) // When @@ -94,6 +94,99 @@ import XCTest XCTAssertEqual(result, "\(userId): Hello") } + // MARK: - Deleted Messages + + func test_format_deletedMessage_noAuthorPrefix() { + // Given + let message = ChatMessage.mock( + id: .unique, + cid: .unique, + text: "This was the original message", + author: .mock(id: "other-user", name: "John"), + deletedAt: Date(), + isSentByCurrentUser: false + ) + let channel = ChatChannel.mockNonDMChannel( + latestMessages: [message] + ) + + // When + let result = formatter.format(message, in: channel) + + // Then + XCTAssertEqual(result, L10n.Message.deletedMessagePlaceholder) + } + + func test_format_deletedMessage_dmChannel() { + // Given + let message = ChatMessage.mock( + id: .unique, + cid: .unique, + text: "This was the original message", + author: .mock(id: "other-user", name: "John"), + deletedAt: Date(), + isSentByCurrentUser: false + ) + let channel = ChatChannel.mockDMChannel( + memberCount: 2, + latestMessages: [message] + ) + + // When + let result = formatter.format(message, in: channel) + + // Then + XCTAssertEqual(result, L10n.Message.deletedMessagePlaceholder) + } + + func test_formatContent_deletedMessage_returnsPlaceholder() { + // Given + let message = ChatMessage.mock( + id: .unique, + cid: .unique, + text: "Original text", + author: .mock(id: "other-user", name: "John"), + deletedAt: Date(), + isSentByCurrentUser: false + ) + let channel = ChatChannel.mock(cid: .unique) + + // When + let result = formatter.formatContent(for: message, in: channel) + + // Then + XCTAssertEqual(result, L10n.Message.deletedMessagePlaceholder) + } + + func test_formatAttachmentContent_deletedMessage_returnsNil() throws { + // Given + let message = try ChatMessage.mock( + id: .unique, + cid: .unique, + text: "", + author: .mock(id: "other-user"), + deletedAt: Date(), + attachments: [ + .dummy( + type: .image, + payload: JSONEncoder().encode(ImageAttachmentPayload( + title: "Test", + imageRemoteURL: URL(string: "https://example.com/image.png")!, + file: .init(type: .png, size: 123, mimeType: nil) + )) + ) + ], + isSentByCurrentUser: false + ) + let channel = ChatChannel.mock(cid: .unique) + + // When + let result = formatter.formatAttachmentContent(for: message, in: channel) + + // Then + XCTAssertNil(result) + } + // MARK: - formatAttachmentContent(for:in:) func test_formatAttachmentContent_poll_noEmoji() { diff --git a/StreamChatSwiftUITests/Tests/Utils/ReactionsIconProvider_Tests.swift b/StreamChatSwiftUITests/Tests/Utils/ReactionsIconProvider_Tests.swift index 1dbbd4084..eb3dcbbe9 100644 --- a/StreamChatSwiftUITests/Tests/Utils/ReactionsIconProvider_Tests.swift +++ b/StreamChatSwiftUITests/Tests/Utils/ReactionsIconProvider_Tests.swift @@ -47,22 +47,22 @@ import XCTest func test_reactionsIconProvider_currentUserColor() { // Given let reaction = MessageReactionType(rawValue: "like") - + // When let color = ReactionsIconProvider.color(for: reaction, userReactionIDs: [reaction]) - + // Then - XCTAssert(color == Color(colors.reactionCurrentUserColor)) + XCTAssert(color == Color(colors.backgroundUtilitySelected)) } - + func test_reactionsIconProvider_otherUserColor() { // Given let reaction = MessageReactionType(rawValue: "like") - + // When let color = ReactionsIconProvider.color(for: reaction, userReactionIDs: []) - + // Then - XCTAssert(color == Color(colors.reactionOtherUserColor)) + XCTAssert(color == Color(colors.backgroundUtilitySelected)) } } diff --git a/StreamChatSwiftUITests/Tests/Utils/StreamChat_Utils_Tests.swift b/StreamChatSwiftUITests/Tests/Utils/StreamChat_Utils_Tests.swift index 9de972b3e..ccb573a9e 100644 --- a/StreamChatSwiftUITests/Tests/Utils/StreamChat_Utils_Tests.swift +++ b/StreamChatSwiftUITests/Tests/Utils/StreamChat_Utils_Tests.swift @@ -4,6 +4,7 @@ import Foundation @testable import StreamChat +import StreamChatCommonUI @testable import StreamChatSwiftUI import XCTest @@ -14,37 +15,72 @@ class StreamChat_Utils_Tests: StreamChatTestCase { override func setUp() { let utils = Utils( - videoPreviewLoader: VideoPreviewLoader_Mock(), - imageLoader: ImageLoader_Mock() + mediaLoader: MediaLoader_Mock() ) streamChat = StreamChat(chatClient: chatClient, utils: utils) } - func test_streamChatUtils_injectVideoPreviewLoader() { + func test_streamChatUtils_injectMediaLoader_videoPreview() { // Given - let videoPreviewLoader = utils.videoPreviewLoader as! VideoPreviewLoader_Mock + let mediaLoader = utils.mediaLoader as! MediaLoader_Mock // When - videoPreviewLoader.loadPreviewForVideo(at: testURL, completion: { _ in }) + let attachment = ChatMessageVideoAttachment( + id: .init(cid: .init(type: .messaging, id: "test"), messageId: "msg", index: 0), + type: .video, + payload: VideoAttachmentPayload( + title: nil, + videoRemoteURL: testURL, + file: .init(type: .mp4, size: 0, mimeType: nil), + extraData: nil + ), + downloadingState: nil, + uploadingState: nil + ) + mediaLoader.loadVideoPreview( + with: attachment, + options: VideoLoadOptions(cdnRequester: CDNRequester_Mock()), + completion: { _ in } + ) // Then - XCTAssert(videoPreviewLoader.loadPreviewVideoCalled == true) + XCTAssert(mediaLoader.loadVideoPreviewWithAttachmentCalled == true) } - func test_streamChatUtils_injectImageLoader() { + func test_streamChatUtils_injectMediaLoader_imageLoading() { // Given - let imageLoader = utils.imageLoader as! ImageLoader_Mock + let mediaLoader = utils.mediaLoader as! MediaLoader_Mock // When - imageLoader.loadImage( + mediaLoader.loadImage( url: testURL, - imageCDN: utils.imageCDN, - resize: true, - preferredSize: nil, + options: ImageLoadOptions(cdnRequester: CDNRequester_Mock()), completion: { _ in } ) // Then - XCTAssert(imageLoader.loadImageCalled == true) + XCTAssert(mediaLoader.loadImageCalled == true) + } + + func test_streamChatUtils_defaultCDNRequester() { + // Given + let utils = Utils(mediaLoader: MediaLoader_Mock()) + streamChat = StreamChat(chatClient: chatClient, utils: utils) + + // Then + XCTAssert(self.utils.cdnRequester is StreamCDNRequester) + } + + func test_streamChatUtils_injectCustomCDNRequester() { + // Given + let customRequester = CDNRequester_Mock() + let utils = Utils( + cdnRequester: customRequester, + mediaLoader: MediaLoader_Mock() + ) + streamChat = StreamChat(chatClient: chatClient, utils: utils) + + // Then + XCTAssert(self.utils.cdnRequester is CDNRequester_Mock) } } diff --git a/StreamChatSwiftUITests/Tests/Utils/VideoPreviewLoader_Tests.swift b/StreamChatSwiftUITests/Tests/Utils/VideoPreviewLoader_Tests.swift deleted file mode 100644 index 447a5d7c4..000000000 --- a/StreamChatSwiftUITests/Tests/Utils/VideoPreviewLoader_Tests.swift +++ /dev/null @@ -1,349 +0,0 @@ -// -// Copyright © 2026 Stream.io Inc. All rights reserved. -// - -@testable import StreamChat -@testable import StreamChatSwiftUI -import XCTest - -class VideoPreviewLoader_Tests: StreamChatTestCase { - private let testURL = URL(string: "https://example.com/video.mp4")! - private let thumbnailURL = URL(string: "https://example.com/thumbnail.jpg")! - - // MARK: - Default Extension (URL-only conformer) - - func test_loadPreviewForVideoWithAttachment_defaultExtensionCallsURLMethod() { - // Given - let loader = URLOnlyVideoPreviewLoader() - let attachment = makeVideoAttachment(thumbnailURL: thumbnailURL) - - // When - let expectation = expectation(description: "Completion called") - var receivedImage: UIImage? - loader.loadPreviewForVideo(with: attachment) { result in - receivedImage = try? result.get() - expectation.fulfill() - } - - // Then - waitForExpectations(timeout: 1) - XCTAssertTrue(loader.loadPreviewAtURLCalled) - XCTAssertNotNil(receivedImage) - } - - func test_loadPreviewForVideoWithAttachment_defaultExtensionPassesCorrectURL() { - // Given - let loader = URLOnlyVideoPreviewLoader() - let attachment = makeVideoAttachment(thumbnailURL: thumbnailURL) - - // When - let expectation = expectation(description: "Completion called") - loader.loadPreviewForVideo(with: attachment) { _ in - expectation.fulfill() - } - - // Then - waitForExpectations(timeout: 1) - XCTAssertEqual(loader.receivedURL, attachment.videoURL) - } - - // MARK: - Custom conformer implementing both methods - - func test_loadPreviewForVideoWithAttachment_customImplementationCalled() { - // Given - let loader = FullVideoPreviewLoader() - let attachment = makeVideoAttachment(thumbnailURL: thumbnailURL) - - // When - let expectation = expectation(description: "Completion called") - var receivedImage: UIImage? - loader.loadPreviewForVideo(with: attachment) { result in - receivedImage = try? result.get() - expectation.fulfill() - } - - // Then - waitForExpectations(timeout: 1) - XCTAssertTrue(loader.loadPreviewWithAttachmentCalled) - XCTAssertFalse(loader.loadPreviewAtURLCalled) - XCTAssertNotNil(receivedImage) - } - - func test_loadPreviewForVideoAtURL_customImplementationStillWorks() { - // Given - let loader = FullVideoPreviewLoader() - - // When - let expectation = expectation(description: "Completion called") - var receivedImage: UIImage? - loader.loadPreviewForVideo(at: testURL) { result in - receivedImage = try? result.get() - expectation.fulfill() - } - - // Then - waitForExpectations(timeout: 1) - XCTAssertTrue(loader.loadPreviewAtURLCalled) - XCTAssertFalse(loader.loadPreviewWithAttachmentCalled) - XCTAssertNotNil(receivedImage) - } - - func test_loadPreviewForVideoWithAttachment_receivesCorrectAttachment() { - // Given - let loader = FullVideoPreviewLoader() - let attachment = makeVideoAttachment(thumbnailURL: thumbnailURL) - - // When - let expectation = expectation(description: "Completion called") - loader.loadPreviewForVideo(with: attachment) { _ in - expectation.fulfill() - } - - // Then - waitForExpectations(timeout: 1) - XCTAssertEqual(loader.receivedAttachment?.videoURL, attachment.videoURL) - XCTAssertEqual(loader.receivedAttachment?.payload.thumbnailURL, thumbnailURL) - } - - // MARK: - DefaultVideoPreviewLoader with attachment - - func test_defaultLoader_withAttachment_whenThumbnailURLExists_loadsThumbnailImage() { - // Given - let imageLoader = ConfigurableImageLoader(result: .success(ConfigurableImageLoader.thumbnailImage)) - streamChat = StreamChat( - chatClient: chatClient, - utils: Utils(imageLoader: imageLoader) - ) - let loader = DefaultVideoPreviewLoader() - let attachment = makeVideoAttachment(thumbnailURL: thumbnailURL) - - // When - let expectation = expectation(description: "Completion called") - var receivedImage: UIImage? - loader.loadPreviewForVideo(with: attachment) { result in - receivedImage = try? result.get() - expectation.fulfill() - } - - // Then - waitForExpectations(timeout: 1) - XCTAssertTrue(imageLoader.loadImageCalled) - XCTAssertEqual(imageLoader.receivedURL, thumbnailURL) - XCTAssertEqual(receivedImage, ConfigurableImageLoader.thumbnailImage) - } - - func test_defaultLoader_withAttachment_whenThumbnailURLExists_cachesResult() { - // Given - let imageLoader = ConfigurableImageLoader(result: .success(ConfigurableImageLoader.thumbnailImage)) - streamChat = StreamChat( - chatClient: chatClient, - utils: Utils(imageLoader: imageLoader) - ) - let loader = DefaultVideoPreviewLoader() - let attachment = makeVideoAttachment(thumbnailURL: thumbnailURL) - - // When - first call to populate cache - let firstExpectation = expectation(description: "First completion called") - loader.loadPreviewForVideo(with: attachment) { _ in - firstExpectation.fulfill() - } - waitForExpectations(timeout: 1) - - // Reset tracker - imageLoader.loadImageCalled = false - imageLoader.receivedURL = nil - - // When - second call should hit cache - let secondExpectation = expectation(description: "Second completion called") - var receivedImage: UIImage? - loader.loadPreviewForVideo(with: attachment) { result in - receivedImage = try? result.get() - secondExpectation.fulfill() - } - - // Then - waitForExpectations(timeout: 1) - XCTAssertFalse(imageLoader.loadImageCalled) - XCTAssertEqual(receivedImage, ConfigurableImageLoader.thumbnailImage) - } - - func test_defaultLoader_withAttachment_whenNoThumbnailURL_doesNotCallImageLoader() { - // Given - let imageLoader = ConfigurableImageLoader(result: .success(ConfigurableImageLoader.thumbnailImage)) - streamChat = StreamChat( - chatClient: chatClient, - utils: Utils(imageLoader: imageLoader) - ) - let loader = DefaultVideoPreviewLoader() - let attachment = makeVideoAttachment(thumbnailURL: nil) - - // When - let expectation = expectation(description: "Completion called") - loader.loadPreviewForVideo(with: attachment) { _ in - expectation.fulfill() - } - - // Then - waitForExpectations(timeout: 5) - XCTAssertFalse(imageLoader.loadImageCalled) - } - - func test_defaultLoader_withAttachment_whenThumbnailLoadFails_fallsBackToVideoPreview() { - // Given - let imageLoader = ConfigurableImageLoader(result: .failure(NSError(domain: "test", code: -1))) - streamChat = StreamChat( - chatClient: chatClient, - utils: Utils(imageLoader: imageLoader) - ) - let loader = DefaultVideoPreviewLoader() - let attachment = makeVideoAttachment(thumbnailURL: thumbnailURL) - - // When - let expectation = expectation(description: "Completion called") - var receivedImage: UIImage? - loader.loadPreviewForVideo(with: attachment) { result in - receivedImage = try? result.get() - expectation.fulfill() - } - - // Then - image loader was called but failed, so it fell back to video frame extraction - waitForExpectations(timeout: 5) - XCTAssertTrue(imageLoader.loadImageCalled) - XCTAssertNotEqual(receivedImage, ConfigurableImageLoader.thumbnailImage) - } - - func test_defaultLoader_withAttachment_whenCached_returnsCachedWithoutLoadingThumbnail() { - // Given - let imageLoader = ConfigurableImageLoader(result: .success(ConfigurableImageLoader.thumbnailImage)) - streamChat = StreamChat( - chatClient: chatClient, - utils: Utils(imageLoader: imageLoader) - ) - let loader = DefaultVideoPreviewLoader() - let attachment = makeVideoAttachment(thumbnailURL: thumbnailURL) - - // Pre-populate via the URL-based method (which also populates the cache for the same URL) - let setupExpectation = expectation(description: "Setup completion called") - loader.loadPreviewForVideo(with: attachment) { _ in - setupExpectation.fulfill() - } - waitForExpectations(timeout: 1) - - imageLoader.loadImageCalled = false - - // When - second call with attachment should use cache - let expectation = expectation(description: "Completion called") - var receivedImage: UIImage? - loader.loadPreviewForVideo(with: attachment) { result in - receivedImage = try? result.get() - expectation.fulfill() - } - - // Then - waitForExpectations(timeout: 1) - XCTAssertFalse(imageLoader.loadImageCalled) - XCTAssertNotNil(receivedImage) - } - - // MARK: - Helpers - - private func makeVideoAttachment( - thumbnailURL: URL? = nil - ) -> ChatMessageVideoAttachment { - let attachmentFile = AttachmentFile(type: .mp4, size: 0, mimeType: "video/mp4") - return ChatMessageVideoAttachment( - id: .unique, - type: .video, - payload: VideoAttachmentPayload( - title: "test", - videoRemoteURL: testURL, - thumbnailURL: thumbnailURL, - file: attachmentFile, - extraData: nil - ), - downloadingState: nil, - uploadingState: nil - ) - } -} - -// MARK: - Test Doubles - -/// A conformer that only implements the URL-based method. -/// The attachment-based method should use the default protocol extension. -private class URLOnlyVideoPreviewLoader: VideoPreviewLoader { - var loadPreviewAtURLCalled = false - var receivedURL: URL? - - func loadPreviewForVideo( - at url: URL, - completion: @escaping @MainActor (Result) -> Void - ) { - loadPreviewAtURLCalled = true - receivedURL = url - completion(.success(UIImage())) - } -} - -/// A conformer that implements both methods independently. -private class FullVideoPreviewLoader: VideoPreviewLoader { - var loadPreviewAtURLCalled = false - var loadPreviewWithAttachmentCalled = false - var receivedURL: URL? - var receivedAttachment: ChatMessageVideoAttachment? - - func loadPreviewForVideo(at url: URL, completion: @escaping @MainActor (Result) -> Void) { - loadPreviewAtURLCalled = true - receivedURL = url - completion(.success(UIImage())) - } - - func loadPreviewForVideo( - with attachment: ChatMessageVideoAttachment, - completion: @Sendable @escaping @MainActor (Result) -> Void - ) { - loadPreviewWithAttachmentCalled = true - receivedAttachment = attachment - completion(.success(UIImage())) - } -} - -/// Configurable image loader that can be set to succeed or fail. -private class ConfigurableImageLoader: ImageLoading { - static let thumbnailImage = UIImage(systemName: "star.fill")! - - var loadImageCalled = false - var receivedURL: URL? - private let result: Result - - init(result: Result) { - self.result = result - } - - func loadImage( - url: URL?, - imageCDN: ImageCDN, - resize: Bool, - preferredSize: CGSize?, - completion: @escaping @MainActor (Result) -> Void - ) { - loadImageCalled = true - receivedURL = url - Task { @MainActor in - completion(result) - } - } - - func loadImages( - from urls: [URL], - placeholders: [UIImage], - loadThumbnails: Bool, - thumbnailSize: CGSize, - imageCDN: ImageCDN, - completion: @escaping @MainActor ([UIImage]) -> Void - ) { - Task { @MainActor in - completion([]) - } - } -} diff --git a/StreamChatSwiftUITests/Tests/Utils/ViewFactory_Tests.swift b/StreamChatSwiftUITests/Tests/Utils/ViewFactory_Tests.swift index a24c6a59b..ec1b453d8 100644 --- a/StreamChatSwiftUITests/Tests/Utils/ViewFactory_Tests.swift +++ b/StreamChatSwiftUITests/Tests/Utils/ViewFactory_Tests.swift @@ -16,15 +16,15 @@ import XCTest author: .mock(id: .unique) ) - func test_viewFactory_makeNoChannelsView() { + func test_viewFactory_makeEmptyChannelsView() { // Given let viewFactory = DefaultViewFactory.shared // When - let view = viewFactory.makeNoChannelsView(options: NoChannelsViewOptions()) + let view = viewFactory.makeEmptyChannelsView(options: EmptyChannelsViewOptions()) // Then - XCTAssert(view is NoChannelsView) + XCTAssert(view is EmptyChannelsView) } func test_viewFactory_makeLoadingView() { @@ -65,7 +65,7 @@ import XCTest ) // Then - XCTAssert(view is MoreChannelActionsView) + XCTAssert(view is ModifiedContent, PresentationDetentsModifier>) } func test_viewFactory_makeSearchResultsView() { @@ -121,7 +121,8 @@ import XCTest message: message, isFirst: true, availableWidth: 300, - scrolledId: .constant(nil) + scrolledId: .constant(nil), + translationLanguage: nil ) ) @@ -139,7 +140,8 @@ import XCTest message: message, isFirst: true, availableWidth: 300, - scrolledId: .constant(nil) + scrolledId: .constant(nil), + translationLanguage: nil ) ) @@ -771,20 +773,33 @@ import XCTest XCTAssert(view is ReactionsOverlayContainer) } - func test_viewFactory_makeNewMessagesIndicatorView() { + func test_viewFactory_makeNewMessagesDividerView() { // Given let viewFactory = DefaultViewFactory.shared // When - let view = viewFactory.makeNewMessagesIndicatorView( - options: NewMessagesIndicatorViewOptions( + let view = viewFactory.makeNewMessagesDividerView( + options: NewMessagesDividerViewOptions( newMessagesStartId: .constant(nil), count: 2 ) ) // Then - XCTAssert(view is NewMessagesIndicator) + XCTAssert(view is NewMessagesDivider) + } + + func test_viewFactory_makeThreadRepliesDividerView() { + // Given + let viewFactory = DefaultViewFactory.shared + + // When + let view = viewFactory.makeThreadRepliesDividerView( + options: ThreadRepliesDividerViewOptions(replyCount: 5) + ) + + // Then + XCTAssert(view is ThreadRepliesDivider) } func test_viewFactory_makeComposerTextInputView() { @@ -927,7 +942,8 @@ import XCTest options: PollViewOptions( message: .mock(), poll: Poll.mock(), - isFirst: true + isFirst: true, + availableWidth: 256 ) ) @@ -969,21 +985,21 @@ import XCTest XCTAssert(view is MediaViewer) } - func test_viewFactory_makeMediaViewerHeader() { + func test_viewFactory_makeMediaViewerToolbarModifier() { // Given let viewFactory = DefaultViewFactory.shared - + // When - let view = viewFactory.makeMediaViewerHeader( - options: MediaViewerHeaderOptions( + let modifier = viewFactory.makeMediaViewerToolbarModifier( + options: MediaViewerToolbarModifierOptions( title: .unique, subtitle: .unique, - shown: .constant(true) + isShown: .constant(true) ) ) - + // Then - XCTAssert(view is MediaViewerHeader) + XCTAssert(modifier is MediaViewerToolbarModifier) } func test_viewFactory_makeVideoPlayerHeaderView() { @@ -1003,20 +1019,20 @@ import XCTest XCTAssert(view is MediaViewerHeader) } - func test_viewFactory_makeAddUsersView() { + func test_viewFactory_makeMemberAddView() { // Given let viewFactory = DefaultViewFactory.shared // When - let view = viewFactory.makeAddUsersView( - options: AddUsersViewOptions( + let view = viewFactory.makeMemberAddView( + options: MemberAddViewOptions( options: .init(loadedUserIds: []), onConfirm: { _ in } ) ) // Then - XCTAssert(view is AddUsersView) + XCTAssert(view is MemberAddView) } func test_viewFactory_makeStreamTextView() { @@ -1024,7 +1040,7 @@ import XCTest let viewFactory = DefaultViewFactory.shared // When - let view = viewFactory.makeStreamTextView(options: .init(message: message)) + let view = viewFactory.makeStreamTextView(options: .init(message: message, translationLanguage: nil)) // Then XCTAssert(view is StreamTextView) @@ -1035,7 +1051,7 @@ import XCTest let viewFactory = DefaultViewFactory.shared // When - let view = viewFactory.makeAttachmentTextView(options: .init(message: message)) + let view = viewFactory.makeAttachmentTextView(options: .init(message: message, availableWidth: 300, translationLanguage: nil)) // Then XCTAssert(view is AttachmentTextView) @@ -1051,7 +1067,7 @@ import XCTest ) // Then - XCTAssert(view is ReactionsDetailView) + XCTAssert(view is ReactionsDetailView) } func test_viewFactory_makeMessageTopView() { diff --git a/StreamChatSwiftUITestsApp/StartPage.swift b/StreamChatSwiftUITestsApp/StartPage.swift index 075949b18..d24ebbc8d 100644 --- a/StreamChatSwiftUITestsApp/StartPage.swift +++ b/StreamChatSwiftUITestsApp/StartPage.swift @@ -73,8 +73,7 @@ struct StartPage: View { skipEditedMessageLabel: { message in message.extraData["ai_generated"]?.boolValue == true }, - draftMessagesEnabled: true, - downloadFileAttachmentsEnabled: true + draftMessagesEnabled: true ), composerConfig: ComposerConfig(isVoiceRecordingEnabled: true) ) diff --git a/StreamChatSwiftUITestsAppTests/Robots/UserRobot.swift b/StreamChatSwiftUITestsAppTests/Robots/UserRobot.swift index 1b4ef75eb..7debdc8e7 100644 --- a/StreamChatSwiftUITestsAppTests/Robots/UserRobot.swift +++ b/StreamChatSwiftUITestsAppTests/Robots/UserRobot.swift @@ -273,7 +273,7 @@ extension UserRobot { @discardableResult func tapOnScrollToBottomButton() -> Self { - MessageListPage.scrollToBottomButton.safeTap() + MessageListPage.scrollToBottomButton.wait().safeTap() return self } @@ -376,7 +376,8 @@ extension UserRobot { sendMessage("\(text)", waitForAppearance: false) } else { typeText("/giphy") - sendMessage(text, waitForAppearance: false) + typeText(text) + composer.confirmButton.safeTap() } MessageListPage.Attributes.actionButtons().firstMatch.wait() if send { tapOnSendGiphyButton() } diff --git a/StreamChatSwiftUITestsAppTests/Tests/ChannelList_Tests.swift b/StreamChatSwiftUITestsAppTests/Tests/ChannelList_Tests.swift index ae3523bec..2a299062e 100644 --- a/StreamChatSwiftUITestsAppTests/Tests/ChannelList_Tests.swift +++ b/StreamChatSwiftUITestsAppTests/Tests/ChannelList_Tests.swift @@ -116,36 +116,7 @@ extension ChannelList_Tests { } } - func test_channelPreviewShowsNoMessages_whenTheOnlyMessageInChannelIsDeleted() throws { - linkToScenario(withId: 353) - - throw XCTSkip("https://linear.app/stream/issue/IOS-1317") - - let message = "Hey" - - GIVEN("user opens the channel") { - userRobot - .login() - .openChannel() - } - AND("user sends a message") { - userRobot.sendMessage(message) - } - AND("user deletes the message") { - userRobot.deleteMessage() - } - WHEN("user goes back to the channel list") { - userRobot.tapOnBackButton() - } - THEN("the channel preview shows No messages") { - userRobot.assertLastMessageInChannelPreview("No messages") - } - AND("last message timestamp is hidden") { - userRobot.assertLastMessageTimestampInChannelPreview(isHidden: true) - } - } - - func test_channelPreviewShowsPreviousMessage_whenLastMessageIsDeleted() throws { + func test_channelPreviewShowsDeletedMessage_whenLastMessageIsDeleted() throws { linkToScenario(withId: 354) let message1 = "Previous message" @@ -167,8 +138,8 @@ extension ChannelList_Tests { WHEN("user goes back to the channel list") { userRobot.tapOnBackButton() } - THEN("the channel preview shows previous message") { - userRobot.assertLastMessageInChannelPreview(message1) + THEN("the channel preview shows Message deleted") { + userRobot.assertLastMessageInChannelPreview("Message deleted") } AND("last message timestamp is shown") { userRobot.assertLastMessageTimestampInChannelPreview(isHidden: false) diff --git a/StreamChatSwiftUITestsAppTests/Tests/Message Delivery Status/MessageDeliveryStatus_Tests.swift b/StreamChatSwiftUITestsAppTests/Tests/Message Delivery Status/MessageDeliveryStatus_Tests.swift index 8fed3ac52..aa7876505 100644 --- a/StreamChatSwiftUITestsAppTests/Tests/Message Delivery Status/MessageDeliveryStatus_Tests.swift +++ b/StreamChatSwiftUITestsAppTests/Tests/Message Delivery Status/MessageDeliveryStatus_Tests.swift @@ -167,7 +167,7 @@ final class MessageDeliveryStatus_Tests: StreamTestCase { } } - func test_deliveryStatusHidden_whenMessageIsDeleted() throws { + func test_deliveryStatusShown_whenMessageIsDeleted() throws { linkToScenario(withId: 404) GIVEN("user opens the channel") { @@ -184,8 +184,8 @@ final class MessageDeliveryStatus_Tests: StreamTestCase { WHEN("user removes the message") { userRobot.deleteMessage() } - THEN("delivery status is hidden") { - userRobot.assertMessageDeliveryStatus(nil) + THEN("delivery status is still shown") { + userRobot.assertMessageDeliveryStatus(.sent) } } } @@ -415,7 +415,7 @@ extension MessageDeliveryStatus_Tests { } } - func test_deliveryStatusHidden_whenThreadReplyIsDeleted() throws { + func test_deliveryStatusShown_whenThreadReplyIsDeleted() throws { linkToScenario(withId: 414) GIVEN("user opens the channel") { @@ -435,8 +435,8 @@ extension MessageDeliveryStatus_Tests { WHEN("user removes the message") { userRobot.deleteMessage() } - THEN("delivery status is hidden") { - userRobot.assertMessageDeliveryStatus(nil) + THEN("delivery status is still shown") { + userRobot.assertMessageDeliveryStatus(.sent) } } diff --git a/StreamChatSwiftUITestsAppTests/Tests/MessageList_Tests.swift b/StreamChatSwiftUITestsAppTests/Tests/MessageList_Tests.swift index 3ae465075..c4f8b9440 100644 --- a/StreamChatSwiftUITestsAppTests/Tests/MessageList_Tests.swift +++ b/StreamChatSwiftUITestsAppTests/Tests/MessageList_Tests.swift @@ -410,7 +410,7 @@ extension MessageList_Tests { userRobot.login().openChannel() } AND("user scrolls up") { - userRobot.scrollMessageListUpSlow() + userRobot.scrollMessageListUp() } AND("participant sends some messages") { participantRobot diff --git a/fastlane/Fastfile b/fastlane/Fastfile index 6c1df6883..27d14500a 100644 --- a/fastlane/Fastfile +++ b/fastlane/Fastfile @@ -394,6 +394,20 @@ lane :install_runtime do |options| install_ios_runtime(version: options[:ios], custom_script: 'Scripts/install_ios_runtime.sh') end +desc 'Record UI Snapshots locally' +lane :record_snapshots_locally do + remove_snapshots + + scan( + project: xcode_project, + scheme: 'StreamChatSwiftUI', + testplan: 'StreamChatSwiftUI', + configuration: 'Debug', + devices: ['iPhone 17 Pro (26.2)'], + fail_build: false + ) +end + desc 'Remove UI Snapshots' lane :remove_snapshots do |options| snapshots_path = "../StreamChatSwiftUITests/**/__Snapshots__/**/*.png" diff --git a/fastlane/Pluginfile b/fastlane/Pluginfile index a8c869d9d..b214e1da1 100644 --- a/fastlane/Pluginfile +++ b/fastlane/Pluginfile @@ -4,5 +4,5 @@ gem 'fastlane-plugin-versioning' gem 'fastlane-plugin-sonarcloud_metric_kit' -gem 'fastlane-plugin-stream_actions', '0.3.110' +gem 'fastlane-plugin-stream_actions', '0.4.0' gem 'fastlane-plugin-xcsize', '1.2.0'