From 236070ccc9d9d34d972978c82aae6c2fbacf1b95 Mon Sep 17 00:00:00 2001 From: James Magahern Date: Sat, 30 Aug 2025 00:39:35 -0600 Subject: [PATCH] Better attachment placeholders --- .../TranscriptDisplayItemViews.swift | 80 +++++++++++-------- 1 file changed, 48 insertions(+), 32 deletions(-) diff --git a/kordophone2/Transcript/TranscriptDisplayItemViews.swift b/kordophone2/Transcript/TranscriptDisplayItemViews.swift index 7459ded..34b471a 100644 --- a/kordophone2/Transcript/TranscriptDisplayItemViews.swift +++ b/kordophone2/Transcript/TranscriptDisplayItemViews.swift @@ -88,47 +88,29 @@ struct ImageItemView: View @State private var img: NSImage? @Environment(\.xpcClient) var xpcClient - private let imageMaxWidth: CGFloat = 340.0 @State private var containerWidth: CGFloat? = nil - var aspectRatio: CGFloat { - if let size = attachment.size, size.height > 0 { - return size.width / size.height - } else { - return 1.0 - } + private var aspectRatio: CGFloat { + attachment.size?.aspectRatio ?? 1.0 } - - var preferredSize: CGSize { - return CGSize( - width: preferredWidth, - height: preferredWidth / aspectRatio - ) - } - - var preferredWidth: CGFloat { - if let containerWidth, let attachmentWidth = attachment.size?.width { - return CGFloat.minimum(containerWidth, attachmentWidth) - } else if let containerWidth { - return containerWidth - } else { - return 200.0 // fallback - } + + private var preferredWidth: CGFloat { + preferredBubbleWidth(forAttachmentSize: attachment.size, containerWidth: containerWidth, maxWidth: .imageMaxWidth) } var body: some View { BubbleView(sender: sender, date: date) { + let maxWidth = CGFloat.minimum(.imageMaxWidth, containerWidth ?? .imageMaxWidth) if let img { Image(nsImage: img) .resizable() .scaledToFit() - .frame( - maxWidth: CGFloat.minimum(imageMaxWidth, containerWidth ?? imageMaxWidth) - ) + .frame(maxWidth: maxWidth) } else { Rectangle() - .fill(.gray) - + .fill(.gray.opacity(0.4)) + .frame(width: preferredWidth, height: preferredWidth / aspectRatio) + .frame(maxWidth: maxWidth) } } .onGeometryChange(for: CGFloat.self, @@ -159,19 +141,38 @@ struct PlaceholderImageItemView: View { let sender: Display.Sender let date: Date - let size: CGSize + let size: CGSize? + @State private var containerWidth: CGFloat? = nil + + private var aspectRatio: CGFloat { + size?.aspectRatio ?? 1.0 + } + + private var preferredWidth: CGFloat { + preferredBubbleWidth(forAttachmentSize: size, containerWidth: containerWidth, maxWidth: .imageMaxWidth) + } + init(sender: Display.Sender, date: Date, size: CGSize?) { self.sender = sender self.date = date - self.size = size ?? CGSize(width: 250.0, height: 100.0) + self.size = size } var body: some View { BubbleView(sender: sender, date: date) { - Color.gray - .frame(width: size.width, height: size.height) + ZStack { + Rectangle() + .fill(.gray.opacity(0.4)) + .frame(width: preferredWidth, height: preferredWidth / aspectRatio) + .frame(maxWidth: .imageMaxWidth) + + ProgressView() + } } + .onGeometryChange(for: CGFloat.self, + of: { $0.size.width }, + action: { containerWidth = $0 }) } } @@ -222,4 +223,19 @@ fileprivate extension CGFloat { static let dominantCornerRadius = 16.0 static let minorCornerRadius = 4.0 static let minimumBubbleHorizontalPadding = 80.0 + static let imageMaxWidth = 380.0 +} + +fileprivate extension CGSize { + var aspectRatio: CGFloat { width / height } +} + +fileprivate func preferredBubbleWidth(forAttachmentSize attachmentSize: CGSize?, containerWidth: CGFloat?, maxWidth: CGFloat) -> CGFloat { + if let containerWidth, let attachmentWidth = attachmentSize?.width { + return .minimum(maxWidth, .minimum(containerWidth, attachmentWidth)) + } else if let containerWidth { + return containerWidth + } else { + return 200.0 // fallback + } }