From 4d7d61dae7f31a2a06607261f413bdf533a2180f Mon Sep 17 00:00:00 2001 From: Mauro <34335419+Velin92@users.noreply.github.com> Date: Mon, 27 Jul 2026 18:46:15 +0200 Subject: [PATCH] Render galleries with non-visual attachments as a list (#5932) * Render galleries with non-visual attachments as a list Adds GalleryListView (with GalleryDivider) for galleries containing a file or audio item, extracting the shared FileTypeIconView from FileRoomTimelineView. GalleryRoomTimelineView picks the list vs the grid via usesListLayout. Tapping to open the preview lands in a follow-up. Co-authored-by: svetoslav.mitov * pr suggestions --------- Co-authored-by: svetoslav.mitov --- ElementX.xcodeproj/project.pbxproj | 4 + .../FileRoomTimelineView.swift | 35 +++-- .../TimelineItemViews/GalleryListView.swift | 132 ++++++++++++++++++ .../GalleryRoomTimelineView.swift | 75 ++++++++-- .../GalleryRoomTimelineItemContent.swift | 18 +++ ...yRoomTimelineView.File-list-iPad-en-GB.png | 3 + ...RoomTimelineView.File-list-iPad-pseudo.png | 3 + ...oomTimelineView.File-list-iPhone-en-GB.png | 3 + ...omTimelineView.File-list-iPhone-pseudo.png | 3 + ...ew.Mixed-content-scan-files-iPad-en-GB.png | 3 + ...w.Mixed-content-scan-files-iPad-pseudo.png | 3 + ....Mixed-content-scan-files-iPhone-en-GB.png | 3 + ...Mixed-content-scan-files-iPhone-pseudo.png | 3 + 13 files changed, 266 insertions(+), 22 deletions(-) create mode 100644 ElementX/Sources/Screens/Timeline/View/TimelineItemViews/GalleryListView.swift create mode 100644 PreviewTests/Sources/__Snapshots__/PreviewTests/galleryRoomTimelineView.File-list-iPad-en-GB.png create mode 100644 PreviewTests/Sources/__Snapshots__/PreviewTests/galleryRoomTimelineView.File-list-iPad-pseudo.png create mode 100644 PreviewTests/Sources/__Snapshots__/PreviewTests/galleryRoomTimelineView.File-list-iPhone-en-GB.png create mode 100644 PreviewTests/Sources/__Snapshots__/PreviewTests/galleryRoomTimelineView.File-list-iPhone-pseudo.png create mode 100644 PreviewTests/Sources/__Snapshots__/PreviewTests/galleryRoomTimelineView.Mixed-content-scan-files-iPad-en-GB.png create mode 100644 PreviewTests/Sources/__Snapshots__/PreviewTests/galleryRoomTimelineView.Mixed-content-scan-files-iPad-pseudo.png create mode 100644 PreviewTests/Sources/__Snapshots__/PreviewTests/galleryRoomTimelineView.Mixed-content-scan-files-iPhone-en-GB.png create mode 100644 PreviewTests/Sources/__Snapshots__/PreviewTests/galleryRoomTimelineView.Mixed-content-scan-files-iPhone-pseudo.png diff --git a/ElementX.xcodeproj/project.pbxproj b/ElementX.xcodeproj/project.pbxproj index b06f9ffe8..a0af5e0cd 100644 --- a/ElementX.xcodeproj/project.pbxproj +++ b/ElementX.xcodeproj/project.pbxproj @@ -1494,6 +1494,7 @@ F382E2FE3AC3719BC1F22D9C /* MapURLs.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB08D1F7C27A8C24EF81073C /* MapURLs.swift */; }; F38D32C1B0232AAFE6A0822C /* ExtensionLogger.swift in Sources */ = {isa = PBXBuildFile; fileRef = 41A8571A8A071FB41778C016 /* ExtensionLogger.swift */; }; F3C9CAD26FD4D7D6EBACF501 /* HTMLFixtures.swift in Sources */ = {isa = PBXBuildFile; fileRef = 27A5FBB74981BF8EFFDAE90D /* HTMLFixtures.swift */; }; + F3D5C73C2A0B7AA00BF3781C /* GalleryListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19FF46006358DF7E6F47A61A /* GalleryListView.swift */; }; F3E2D3F7ACDED65A4E5CD8DE /* RoomMembersListScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECF79FB25E2D4BD6F50CE7C9 /* RoomMembersListScreenViewModel.swift */; }; F3ECA377FF77E81A4F1FA062 /* TimelineItemSendInfoLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 753B4C6C0EDDCBF0708DC384 /* TimelineItemSendInfoLabel.swift */; }; F3F38062C6CA21CF403C5C90 /* AudioConverterProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2757B1BE23DF8AA239937243 /* AudioConverterProtocol.swift */; }; @@ -1814,6 +1815,7 @@ 1912062B53CE95E6F700DA60 /* Pagination.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Pagination.swift; sourceTree = ""; }; 196004E7695FBA292A7944AF /* ScreenTrackerViewModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScreenTrackerViewModifier.swift; sourceTree = ""; }; 19DD166C3625EE426203FA29 /* AppLockSetupTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppLockSetupTests.swift; sourceTree = ""; }; + 19FF46006358DF7E6F47A61A /* GalleryListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GalleryListView.swift; sourceTree = ""; }; 1A02406480C351B8C6E0682C /* MediaLoaderProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaLoaderProtocol.swift; sourceTree = ""; }; 1A1265FAF2C0AF1C30605BE7 /* SessionVerificationRequestDetailsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionVerificationRequestDetailsView.swift; sourceTree = ""; }; 1A13364350970987B93F6018 /* JoinRoomByAddressView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JoinRoomByAddressView.swift; sourceTree = ""; }; @@ -6586,6 +6588,7 @@ C258C9C815272911A5B132C3 /* FormattedBodyText.swift */, EEE0273EC14A781BBF715E37 /* GalleryGridView.swift */, 7927284C6F70D60BE5949F8C /* GalleryItemTileView.swift */, + 19FF46006358DF7E6F47A61A /* GalleryListView.swift */, A04EFA0E3139C01E1CFDC93B /* GalleryRoomTimelineView.swift */, 59B7CC77B82C6C67DE3AD869 /* HighlightedTimelineItemModifier.swift */, C5599255A6C98EBDA77B76E6 /* ImageRoomTimelineView.swift */, @@ -8561,6 +8564,7 @@ 46BA7F4B4D3A7164DED44B88 /* FullscreenDialog.swift in Sources */, 82D1368B43020B55347E1743 /* GalleryGridView.swift in Sources */, 52BE121FC21CE88803D2D8B5 /* GalleryItemTileView.swift in Sources */, + F3D5C73C2A0B7AA00BF3781C /* GalleryListView.swift in Sources */, E08DFC18E97623B5C91C5025 /* GalleryRoomTimelineItem.swift in Sources */, 1CA6E1843E1B3680544EB584 /* GalleryRoomTimelineItemContent.swift in Sources */, 30DA1A668482E5B95E8F1F2B /* GalleryRoomTimelineView.swift in Sources */, diff --git a/ElementX/Sources/Screens/Timeline/View/TimelineItemViews/FileRoomTimelineView.swift b/ElementX/Sources/Screens/Timeline/View/TimelineItemViews/FileRoomTimelineView.swift index b290df37a..44f28355c 100644 --- a/ElementX/Sources/Screens/Timeline/View/TimelineItemViews/FileRoomTimelineView.swift +++ b/ElementX/Sources/Screens/Timeline/View/TimelineItemViews/FileRoomTimelineView.swift @@ -102,24 +102,35 @@ struct MediaFileRoomTimelineContent: View { .foregroundStyle(.compound.textPrimary) .lineLimit(2) } icon: { - Group { - if isScanning { - ProgressView() - .scaledFrame(size: CompoundIcon.Size.medium.value, relativeTo: .body) - } else { - CompoundIcon(icon, size: .medium, relativeTo: .body) - .foregroundColor(.compound.iconPrimary) - } - } - .scaledPadding(6) - .background(.compound.iconOnSolidPrimary, - in: RoundedRectangle(cornerRadius: 4, style: .continuous)) + FileTypeIconView(icon: icon, isScanning: isScanning) } .labelStyle(.custom(spacing: 8, alignment: .center)) .padding(.horizontal, 4) // Add to the styler's padding of 8, as we use the default insets for the caption. } } +/// The rounded icon badge used as the leading accessory of a file/audio row, either showing the +/// file-type icon or a scanning spinner. +struct FileTypeIconView: View { + let icon: KeyPath + var isScanning = false + + var body: some View { + Group { + if isScanning { + ProgressView() + .scaledFrame(size: CompoundIcon.Size.medium.value, relativeTo: .compound.bodyLG) + } else { + CompoundIcon(icon) + .foregroundColor(.compound.iconPrimary) + } + } + .scaledPadding(6) + .background(.compound.iconOnSolidPrimary, + in: RoundedRectangle(cornerRadius: 4)) + } +} + // MARK: - Previews struct FileRoomTimelineView_Previews: PreviewProvider, TestablePreview { diff --git a/ElementX/Sources/Screens/Timeline/View/TimelineItemViews/GalleryListView.swift b/ElementX/Sources/Screens/Timeline/View/TimelineItemViews/GalleryListView.swift new file mode 100644 index 000000000..513117ed3 --- /dev/null +++ b/ElementX/Sources/Screens/Timeline/View/TimelineItemViews/GalleryListView.swift @@ -0,0 +1,132 @@ +// +// Copyright 2026 Element Creations Ltd. +// +// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. +// Please see LICENSE files in the repository root for full details. +// + +import Compound +import SwiftUI + +/// A vertical list of file rows for a gallery message. Used when a gallery has a non-visual +/// attachment (file/audio), where the grid layout doesn't read well. +struct GalleryListView: View { + let items: [GalleryItem] + let mediaProvider: MediaProviderProtocol? + let contentScannerService: ContentScannerServiceProtocol? + let onItemTap: (Int) -> Void + + var body: some View { + VStack(alignment: .leading, spacing: 0) { + ForEach(Array(items.enumerated()), id: \.element.id) { index, item in + if index > 0 { + GalleryDivider() + } + + GalleryListRow(item: item, + mediaProvider: mediaProvider, + contentScannerService: contentScannerService) { + onItemTap(index) + } + } + } + } +} + +/// A hairline divider used between gallery file-list rows (and above the caption). +struct GalleryDivider: View { + @Environment(\.pixelLength) private var pixelLength + + var body: some View { + Rectangle() + .fill(Color.compound.borderInteractiveSecondary) + .frame(height: pixelLength) + } +} + +private struct GalleryListRow: View { + let item: GalleryItem + let mediaProvider: MediaProviderProtocol? + let contentScannerService: ContentScannerServiceProtocol? + let onTap: () -> Void + + private var fileDescription: String { + item.filename.validatedFileExtension.uppercased() + } + + private var iconKeyPath: KeyPath { + item.isAudio ? \.audio : \.attachment + } + + var body: some View { + ContentScanningView(contentScannerService: contentScannerService, + mediaSource: item.mediaSource, + thumbnailSource: item.thumbnailSource, + containerShowsFailure: false) { + row(icon: icon) + .contentShape(Rectangle()) + .onTapGesture { onTap() } + } scanningContent: { + row(icon: scanningIcon) + } unsafeContent: { failure in + failureRow(failure) + } + } + + private func row(icon: some View) -> some View { + Label { + VStack(alignment: .leading, spacing: 0) { + Text(item.filename) + .foregroundStyle(.compound.textPrimary) + .font(.compound.bodyLG) + Text(fileDescription) + .font(.compound.bodySM) + .foregroundStyle(.compound.textSecondary) + } + .lineLimit(2) + } icon: { + icon + } + .labelStyle(.custom(spacing: 8, alignment: .center)) + .padding(.vertical, 12) + } + + /// The critical row shown when an item fails content scanning. Reuses ``ContentScanningFailureView`` + /// (icon + title + message) inside its own critical container as the surrounding bubble stays regular. + private func failureRow(_ failure: ContentScanningFailure) -> some View { + ContentScanningFailureView(failure: failure) + .frame(maxWidth: .infinity, alignment: .leading) + .padding(.horizontal, 12) + .padding(.vertical, 4) + .background(Color.compound.bgCriticalSubtle, in: RoundedRectangle(cornerRadius: 6)) + .overlay { + RoundedRectangle(cornerRadius: 6) + .stroke(Color.compound.borderCriticalSubtle) + } + .padding(.vertical, 8) + } + + @ViewBuilder + private var icon: some View { + if item.hasThumbnail, let source = item.thumbnailSource ?? item.mediaSource { + LoadableImage(mediaSource: source, + mediaType: .timelineItem(uniqueID: item.id.timelineItemUniqueID), + blurhash: item.blurhash, + size: item.size, + mediaProvider: mediaProvider) { imageView in + imageView + .aspectRatio(contentMode: .fill) + } placeholder: { + Color.compound.bgSubtleSecondary + } + .frame(width: 36, height: 36) + .clipShape(RoundedRectangle(cornerRadius: 4, style: .continuous)) + } else { + FileTypeIconView(icon: iconKeyPath) + } + } + + private var scanningIcon: some View { + FileTypeIconView(icon: iconKeyPath, isScanning: true) + } +} diff --git a/ElementX/Sources/Screens/Timeline/View/TimelineItemViews/GalleryRoomTimelineView.swift b/ElementX/Sources/Screens/Timeline/View/TimelineItemViews/GalleryRoomTimelineView.swift index f72eac9b2..28dd9a25b 100644 --- a/ElementX/Sources/Screens/Timeline/View/TimelineItemViews/GalleryRoomTimelineView.swift +++ b/ElementX/Sources/Screens/Timeline/View/TimelineItemViews/GalleryRoomTimelineView.swift @@ -16,16 +16,32 @@ struct GalleryRoomTimelineView: View { timelineItem.content.caption?.isBlank == false } + // List layout when any item is non-visual (file/audio); a grid reads badly for documents. + private var usesListLayout: Bool { + timelineItem.content.items.contains { !$0.isImage && !$0.isVideo } + } + var body: some View { TimelineStyler(timelineItem: timelineItem) { VStack(alignment: .leading, spacing: 8) { - GalleryGridView(items: timelineItem.content.items, - mediaProvider: context?.mediaProvider, - contentScannerService: context?.contentScannerService) { _ in - // Tapping to open the full-screen preview lands in a follow-up. + if usesListLayout { + GalleryListView(items: timelineItem.content.items, + mediaProvider: context?.mediaProvider, + contentScannerService: context?.contentScannerService) { _ in + // Tapping to open the full-screen preview lands in a follow-up. + } + } else { + GalleryGridView(items: timelineItem.content.items, + mediaProvider: context?.mediaProvider, + contentScannerService: context?.contentScannerService) { _ in + // Tapping to open the full-screen preview lands in a follow-up. + } } if hasMediaCaption { + if usesListLayout { + GalleryDivider() + } caption } } @@ -60,12 +76,10 @@ struct GalleryRoomTimelineView_Previews: PreviewProvider, TestablePreview { // swiftlint:enable force_try static let mixedScanViewModel = TimelineViewModel.mock(contentScannerService: ContentScannerServiceMock(.init { source in - if source.url == unsafeSource.url { - false - } else if source.url == scanningSource.url { - nil - } else { - true + switch source.url { + case .mockMXCUnsafe: false + case .mockMXCScanning: nil + default: true } })) @@ -77,6 +91,8 @@ struct GalleryRoomTimelineView_Previews: PreviewProvider, TestablePreview { makeView(makeItem(itemCount: 5), viewModel).previewDisplayName("5 images") makeView(makeItem(itemCount: 9, caption: "A trip to remember 🌅"), viewModel).previewDisplayName("6+ images with caption") makeView(makeMixedScanItem(), mixedScanViewModel).previewDisplayName("Mixed content scan") + makeView(makeFileListItem(caption: "Quarterly reports"), viewModel).previewDisplayName("File list") + makeView(makeMixedScanFileListItem(), mixedScanViewModel).previewDisplayName("Mixed content scan (files)") } static func makeView(_ item: GalleryRoomTimelineItem, _ viewModel: TimelineViewModel) -> some View { @@ -123,4 +139,43 @@ struct GalleryRoomTimelineView_Previews: PreviewProvider, TestablePreview { items: items), properties: .init()) } + + private static func makeFileListItem(caption: String?) -> GalleryRoomTimelineItem { + let items: [GalleryItem] = [ + .mockImage(index: 0, filename: "photo.jpg"), + .mockFile(index: 1, filename: "report.pdf"), + .mockAudio(index: 2, filename: "meeting.m4a") + ] + + return GalleryRoomTimelineItem(id: .randomEvent, + timestamp: .mock, + isOutgoing: false, + isEditable: false, + canBeRepliedTo: true, + sender: .init(id: "Bob"), + content: .init(body: "Mixed gallery", + caption: caption, + items: items), + properties: .init()) + } + + private static func makeMixedScanFileListItem() -> GalleryRoomTimelineItem { + // Safe/unsafe/scanning rows via the mixed-scan sources. + let items: [GalleryItem] = [ + .mockFile(index: 0, filename: "report.zip", source: safeSource, contentType: .zip), + .mockFile(index: 1, filename: "contract.pdf", source: unsafeSource), + .mockAudio(index: 2, filename: "meeting.m4a", source: scanningSource) + ] + + return GalleryRoomTimelineItem(id: .randomEvent, + timestamp: .mock, + isOutgoing: false, + isEditable: false, + canBeRepliedTo: true, + sender: .init(id: "Bob"), + content: .init(body: "Files", + caption: "Mixed scan states", + items: items), + properties: .init()) + } } diff --git a/ElementX/Sources/Services/Timeline/TimelineItems/Items/Messages/GalleryRoomTimelineItemContent.swift b/ElementX/Sources/Services/Timeline/TimelineItems/Items/Messages/GalleryRoomTimelineItemContent.swift index 997ab3c2c..b52e27bfb 100644 --- a/ElementX/Sources/Services/Timeline/TimelineItems/Items/Messages/GalleryRoomTimelineItemContent.swift +++ b/ElementX/Sources/Services/Timeline/TimelineItems/Items/Messages/GalleryRoomTimelineItemContent.swift @@ -175,4 +175,22 @@ nonisolated extension GalleryItem { return .video(id: .mock(index), .init(filename: filename, videoInfo: .mockVideo(duration: duration), thumbnailInfo: thumbnailInfo, blurhash: blurhash, contentType: contentType)) } + + static func mockFile(index: Int = 0, + filename: String = "document.pdf", + source: MediaSourceProxy? = nil, + thumbnailSource: MediaSourceProxy? = nil, + contentType: UTType? = .pdf) -> GalleryItem { + .file(id: .mock(index), + .init(filename: filename, source: source, fileSize: nil, thumbnailSource: thumbnailSource, contentType: contentType)) + } + + static func mockAudio(index: Int = 0, + filename: String = "audio.m4a", + source: MediaSourceProxy? = nil, + duration: TimeInterval = 65, + contentType: UTType? = .mpeg4Audio) -> GalleryItem { + .audio(id: .mock(index), + .init(filename: filename, duration: duration, waveform: nil, source: source, fileSize: nil, contentType: contentType)) + } } diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/galleryRoomTimelineView.File-list-iPad-en-GB.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/galleryRoomTimelineView.File-list-iPad-en-GB.png new file mode 100644 index 000000000..1a822f4b4 --- /dev/null +++ b/PreviewTests/Sources/__Snapshots__/PreviewTests/galleryRoomTimelineView.File-list-iPad-en-GB.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2a04cfde76dda32e6b03de15287fba371469a9a976a276de1170be101e6a4b47 +size 114825 diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/galleryRoomTimelineView.File-list-iPad-pseudo.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/galleryRoomTimelineView.File-list-iPad-pseudo.png new file mode 100644 index 000000000..075fbed4e --- /dev/null +++ b/PreviewTests/Sources/__Snapshots__/PreviewTests/galleryRoomTimelineView.File-list-iPad-pseudo.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5af56b0ee13ff01980b521308e355dd2a97e3e544292c00d1d06e66ea7053a2f +size 115619 diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/galleryRoomTimelineView.File-list-iPhone-en-GB.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/galleryRoomTimelineView.File-list-iPhone-en-GB.png new file mode 100644 index 000000000..305dce033 --- /dev/null +++ b/PreviewTests/Sources/__Snapshots__/PreviewTests/galleryRoomTimelineView.File-list-iPhone-en-GB.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:096ad88c39dac4de5ec8a07365abef703b0ec981081d5b99c58625cc7fb117d5 +size 70447 diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/galleryRoomTimelineView.File-list-iPhone-pseudo.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/galleryRoomTimelineView.File-list-iPhone-pseudo.png new file mode 100644 index 000000000..3274628bb --- /dev/null +++ b/PreviewTests/Sources/__Snapshots__/PreviewTests/galleryRoomTimelineView.File-list-iPhone-pseudo.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8ab463160327c4900a4687c2373617f3ce8e1b56da316e50b5ae142a905046c8 +size 71049 diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/galleryRoomTimelineView.Mixed-content-scan-files-iPad-en-GB.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/galleryRoomTimelineView.Mixed-content-scan-files-iPad-en-GB.png new file mode 100644 index 000000000..7eed54f9b --- /dev/null +++ b/PreviewTests/Sources/__Snapshots__/PreviewTests/galleryRoomTimelineView.Mixed-content-scan-files-iPad-en-GB.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0aef46856afe160305ec163ff9edd2abdc34f7bcbc0f5e3b9cd20227a501a79a +size 108840 diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/galleryRoomTimelineView.Mixed-content-scan-files-iPad-pseudo.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/galleryRoomTimelineView.Mixed-content-scan-files-iPad-pseudo.png new file mode 100644 index 000000000..3557ad645 --- /dev/null +++ b/PreviewTests/Sources/__Snapshots__/PreviewTests/galleryRoomTimelineView.Mixed-content-scan-files-iPad-pseudo.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:dd673d411dbf04a146fc5889e3e98f11f2837ab8e59fe1238140d493621dbae2 +size 121207 diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/galleryRoomTimelineView.Mixed-content-scan-files-iPhone-en-GB.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/galleryRoomTimelineView.Mixed-content-scan-files-iPhone-en-GB.png new file mode 100644 index 000000000..7bfc3e2b4 --- /dev/null +++ b/PreviewTests/Sources/__Snapshots__/PreviewTests/galleryRoomTimelineView.Mixed-content-scan-files-iPhone-en-GB.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:927bb7fd0f12f6817247b1f15c3c4fb27573120d280f2a0fd6a17170a7927bc2 +size 62747 diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/galleryRoomTimelineView.Mixed-content-scan-files-iPhone-pseudo.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/galleryRoomTimelineView.Mixed-content-scan-files-iPhone-pseudo.png new file mode 100644 index 000000000..5317e041f --- /dev/null +++ b/PreviewTests/Sources/__Snapshots__/PreviewTests/galleryRoomTimelineView.Mixed-content-scan-files-iPhone-pseudo.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a6ca4d4e763aacdfc31d978c641072fd506c44d271b42a750659199bf2738962 +size 71840