diff --git a/ElementX/Sources/Other/SwiftUI/Layout/TimelineMediaFrame.swift b/ElementX/Sources/Other/SwiftUI/Layout/TimelineMediaFrame.swift index e93a6a17f..4243dc4fd 100644 --- a/ElementX/Sources/Other/SwiftUI/Layout/TimelineMediaFrame.swift +++ b/ElementX/Sources/Other/SwiftUI/Layout/TimelineMediaFrame.swift @@ -8,25 +8,32 @@ import SwiftUI +enum TimelineMediaFrame { + /// The maximum height of a media item in the timeline. + static let maxMediaHeight = 300.0 + /// The minimum height of a media item in the timeline. + static let minMediaHeight = 100.0 + /// The size of a media item with an unknown aspect ratio. + static let defaultMediaSize = 100.0 + /// The maximum width of a timeline link preview + static let maxLinkPreviewWidth = 300.0 +} + extension View { /// Constrains the max height of a media item in the timeline, whilst preserving its aspect ratio. @ViewBuilder func timelineMediaFrame(imageInfo: ImageInfoProxy?) -> some View { - let defaultMediaSize = 100.0 - let minMediaHeight = 100.0 - let maxMediaHeight = 300.0 - - if let contentHeight = imageInfo?.size?.height, contentHeight < minMediaHeight { // Special case very small images + if let contentHeight = imageInfo?.size?.height, contentHeight < TimelineMediaFrame.minMediaHeight { // Special case very small images aspectRatio(imageInfo?.aspectRatio, contentMode: .fit) - .frame(minHeight: minMediaHeight, maxHeight: minMediaHeight) + .frame(minHeight: TimelineMediaFrame.minMediaHeight, maxHeight: TimelineMediaFrame.minMediaHeight) } else { if let contentAspectRatio = imageInfo?.aspectRatio { aspectRatio(contentAspectRatio, contentMode: .fit) - .frame(maxHeight: min(maxMediaHeight, max(minMediaHeight, imageInfo?.size?.height ?? .infinity))) + .frame(maxHeight: min(TimelineMediaFrame.maxMediaHeight, max(TimelineMediaFrame.minMediaHeight, imageInfo?.size?.height ?? .infinity))) // Required to prevent the reply details to get higher priority in rendering the width of the view. .aspectRatio(contentAspectRatio, contentMode: .fit) - } else { // Otherwise force the image to be `defaultMediaSize` x `defaultMediaSize` - frame(width: defaultMediaSize, height: defaultMediaSize) + } else { // Otherwise force the image to be `defaultSize` x `defaultSize` + frame(width: TimelineMediaFrame.defaultMediaSize, height: TimelineMediaFrame.defaultMediaSize) } } } diff --git a/ElementX/Sources/Screens/Timeline/View/TimelineItemViews/TextRoomTimelineView.swift b/ElementX/Sources/Screens/Timeline/View/TimelineItemViews/TextRoomTimelineView.swift index 072d3690c..7c4aca875 100644 --- a/ElementX/Sources/Screens/Timeline/View/TimelineItemViews/TextRoomTimelineView.swift +++ b/ElementX/Sources/Screens/Timeline/View/TimelineItemViews/TextRoomTimelineView.swift @@ -43,6 +43,8 @@ struct TextRoomTimelineView: View, TextBasedRoomTimelineViewProtocol { LinkPreviewView(url: url, metadata: metadata) } } + // Link previews report the full proposed width, which would otherwise stretch the bubble across the timeline. + .frame(maxWidth: TimelineMediaFrame.maxLinkPreviewWidth) .padding(.bottom, 16) } }