Private
Public Access
1
0

Better attachment placeholders

This commit is contained in:
2025-08-30 00:39:35 -06:00
parent 8257b8dbd6
commit 236070ccc9

View File

@@ -88,47 +88,29 @@ struct ImageItemView: View
@State private var img: NSImage? @State private var img: NSImage?
@Environment(\.xpcClient) var xpcClient @Environment(\.xpcClient) var xpcClient
private let imageMaxWidth: CGFloat = 340.0
@State private var containerWidth: CGFloat? = nil @State private var containerWidth: CGFloat? = nil
var aspectRatio: CGFloat { private var aspectRatio: CGFloat {
if let size = attachment.size, size.height > 0 { attachment.size?.aspectRatio ?? 1.0
return size.width / size.height
} else {
return 1.0
}
} }
var preferredSize: CGSize { private var preferredWidth: CGFloat {
return CGSize( preferredBubbleWidth(forAttachmentSize: attachment.size, containerWidth: containerWidth, maxWidth: .imageMaxWidth)
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
}
} }
var body: some View { var body: some View {
BubbleView(sender: sender, date: date) { BubbleView(sender: sender, date: date) {
let maxWidth = CGFloat.minimum(.imageMaxWidth, containerWidth ?? .imageMaxWidth)
if let img { if let img {
Image(nsImage: img) Image(nsImage: img)
.resizable() .resizable()
.scaledToFit() .scaledToFit()
.frame( .frame(maxWidth: maxWidth)
maxWidth: CGFloat.minimum(imageMaxWidth, containerWidth ?? imageMaxWidth)
)
} else { } else {
Rectangle() Rectangle()
.fill(.gray) .fill(.gray.opacity(0.4))
.frame(width: preferredWidth, height: preferredWidth / aspectRatio)
.frame(maxWidth: maxWidth)
} }
} }
.onGeometryChange(for: CGFloat.self, .onGeometryChange(for: CGFloat.self,
@@ -159,19 +141,38 @@ struct PlaceholderImageItemView: View
{ {
let sender: Display.Sender let sender: Display.Sender
let date: Date 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?) { init(sender: Display.Sender, date: Date, size: CGSize?) {
self.sender = sender self.sender = sender
self.date = date self.date = date
self.size = size ?? CGSize(width: 250.0, height: 100.0) self.size = size
} }
var body: some View { var body: some View {
BubbleView(sender: sender, date: date) { BubbleView(sender: sender, date: date) {
Color.gray ZStack {
.frame(width: size.width, height: size.height) 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 dominantCornerRadius = 16.0
static let minorCornerRadius = 4.0 static let minorCornerRadius = 4.0
static let minimumBubbleHorizontalPadding = 80.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
}
} }