Simplify and fix implementation

This commit is contained in:
Stefan Ceriu
2026-04-15 13:57:51 +03:00
committed by Stefan Ceriu
parent cfd6703bf5
commit 635ebb720a
3 changed files with 47 additions and 53 deletions

View File

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

View File

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

View File

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