diff --git a/ElementX/Sources/Screens/FilePreviewScreen/TimelineMediaPreviewDataSource.swift b/ElementX/Sources/Screens/FilePreviewScreen/TimelineMediaPreviewDataSource.swift index c5b15518a..083894d77 100644 --- a/ElementX/Sources/Screens/FilePreviewScreen/TimelineMediaPreviewDataSource.swift +++ b/ElementX/Sources/Screens/FilePreviewScreen/TimelineMediaPreviewDataSource.swift @@ -269,23 +269,16 @@ enum TimelineMediaPreviewItem: Equatable { } } + var hasCaption: Bool { + timelineItem.hasMediaCaption + } + var caption: String? { timelineItem.mediaCaption } var formattedCaption: AttributedString? { - switch timelineItem { - case let audioItem as AudioRoomTimelineItem: - audioItem.content.formattedCaption - case let fileItem as FileRoomTimelineItem: - fileItem.content.formattedCaption - case let imageItem as ImageRoomTimelineItem: - imageItem.content.formattedCaption - case let videoItem as VideoRoomTimelineItem: - videoItem.content.formattedCaption - default: - nil - } + timelineItem.formattedMediaCaption } var contentType: String? { diff --git a/ElementX/Sources/Screens/FilePreviewScreen/View/TimelineMediaPreviewController.swift b/ElementX/Sources/Screens/FilePreviewScreen/View/TimelineMediaPreviewController.swift index e0a7b7ace..cca4853dd 100644 --- a/ElementX/Sources/Screens/FilePreviewScreen/View/TimelineMediaPreviewController.swift +++ b/ElementX/Sources/Screens/FilePreviewScreen/View/TimelineMediaPreviewController.swift @@ -317,51 +317,46 @@ private struct CaptionView: View { context.viewState.currentItem } - private let maxCaptionHeight: CGFloat = 120 - var body: some View { - if case let .media(mediaItem) = currentItem, mediaItem.caption != nil { - CaptionScrollView(mediaItem: mediaItem, maxHeight: maxCaptionHeight) + if case let .media(mediaItem) = currentItem, mediaItem.hasCaption { + CaptionScrollView(mediaItem: mediaItem) .transition(.move(edge: .bottom).combined(with: .opacity)) } } } private struct CaptionScrollView: View { + private let maxHeight: CGFloat = 120 + let mediaItem: TimelineMediaPreviewItem.Media - let maxHeight: CGFloat - - @State private var contentHeight: CGFloat = 0 - @State private var isScrollable: Bool = false - - private var shouldShowFade: Bool { - contentHeight > maxHeight - } - + + @State private var shouldShowFade = false + var body: some View { - VStack(alignment: .leading, spacing: 0) { - ScrollView(.vertical, showsIndicators: false) { + ZStack(alignment: .bottom) { + ScrollView(.vertical) { captionContent - .background(SizePreferenceKey()) + .background { + GeometryReader { geometry in + DispatchQueue.main.async { + shouldShowFade = geometry.size.height > maxHeight + } + return Color.clear + } + } } - .onPreferenceChange(SizePreferenceKey.self) { size in - contentHeight = size.height - isScrollable = size.height > maxHeight - } - .frame(height: maxHeight) - .clipped() - + .frame(maxHeight: maxHeight) + .padding(16) + if shouldShowFade { LinearGradient(stops: [.init(color: .clear, location: 0.0), - .init(color: .black.opacity(0.5), location: 1.0)], - startPoint: .top, - endPoint: .bottom) - .frame(height: 40) - .allowsHitTesting(false) + .init(color: .black.opacity(0.5), location: 1.0)], + startPoint: .top, + endPoint: .bottom) + .frame(height: 40) } } .frame(maxWidth: .infinity, alignment: .leading) - .padding(16) .background { BlurEffectView(style: .systemChromeMaterial) .ignoresSafeArea() @@ -373,20 +368,11 @@ private struct CaptionScrollView: View { if let formattedCaption = mediaItem.formattedCaption { FormattedBodyText(attributedString: formattedCaption) } else if let caption = mediaItem.caption { - Text(caption) - .font(.compound.bodyLG) - .foregroundStyle(.compound.textPrimary) + FormattedBodyText(text: caption) } } } -private struct SizePreferenceKey: PreferenceKey { - static var defaultValue: CGSize = .zero - static func reduce(value: inout CGSize, nextValue: () -> CGSize) { - value = nextValue() - } -} - private struct DownloadIndicatorView: View { @ObservedObject var context: TimelineMediaPreviewViewModel.Context private var currentItem: TimelineMediaPreviewItem { diff --git a/ElementX/Sources/Services/Timeline/TimelineItems/EventBasedMessageTimelineItemProtocol.swift b/ElementX/Sources/Services/Timeline/TimelineItems/EventBasedMessageTimelineItemProtocol.swift index 663071330..a31cd9dcc 100644 --- a/ElementX/Sources/Services/Timeline/TimelineItems/EventBasedMessageTimelineItemProtocol.swift +++ b/ElementX/Sources/Services/Timeline/TimelineItems/EventBasedMessageTimelineItemProtocol.swift @@ -34,6 +34,10 @@ extension EventBasedMessageTimelineItemProtocol { } } + var hasMediaCaption: Bool { + mediaCaption != nil + } + var mediaCaption: String? { switch contentType { case .audio(let content): @@ -49,7 +53,18 @@ extension EventBasedMessageTimelineItemProtocol { } } - var hasMediaCaption: Bool { - mediaCaption != nil + var formattedMediaCaption: AttributedString? { + switch contentType { + case .audio(let content): + content.formattedCaption + case .file(let content): + content.formattedCaption + case .image(let content): + content.formattedCaption + case .video(let content): + content.formattedCaption + case .emote, .notice, .text, .location, .voice: + nil + } } }