diff --git a/Packages/ComposeUI/Sources/ComposeUI/Views/AttachmentThumbnailView.swift b/Packages/ComposeUI/Sources/ComposeUI/Views/AttachmentThumbnailView.swift index eefc44a98..9de4343da 100644 --- a/Packages/ComposeUI/Sources/ComposeUI/Views/AttachmentThumbnailView.swift +++ b/Packages/ComposeUI/Sources/ComposeUI/Views/AttachmentThumbnailView.swift @@ -46,6 +46,9 @@ private struct AttachmentThumbnailViewContent: View { Image(uiImage: image) .resizable() .aspectRatio(contentMode: contentMode) + .task(id: attachment.drawingData) { + await loadThumbnail() + } case .gifController(let controller): GIFViewWrapper(controller: controller) } diff --git a/Packages/ComposeUI/Sources/ComposeUI/Views/Attachments/AttachmentCollectionViewCell.swift b/Packages/ComposeUI/Sources/ComposeUI/Views/Attachments/AttachmentCollectionViewCell.swift index 2394fb042..1081ba61a 100644 --- a/Packages/ComposeUI/Sources/ComposeUI/Views/Attachments/AttachmentCollectionViewCell.swift +++ b/Packages/ComposeUI/Sources/ComposeUI/Views/Attachments/AttachmentCollectionViewCell.swift @@ -23,28 +23,36 @@ struct AttachmentCollectionViewCellView: View { .fill(.quaternary) } .overlay(alignment: .bottomLeading) { - if recognizingText { - ProgressView() - .progressViewStyle(.circular) - } else { - AttachmentDescriptionLabel(attachment: attachment) - } + AttachmentDescriptionLabel(attachment: attachment, recognizingText: recognizingText) + } + .overlay(alignment: .topLeading) { + AttachmentOptionsMenu(attachment: attachment, recognizingText: $recognizingText) } .overlay(alignment: .topTrailing) { AttachmentRemoveButton(attachment: attachment) } .clipShape(RoundedSquare(cornerRadius: 5)) - // TODO: context menu preview? - .contextMenu { - if attachment.drawingData != nil { - EditDrawingButton(attachment: attachment) - } else if attachment.type == .image { - RecognizeTextButton(attachment: attachment, recognizingText: $recognizingText) - } - } } } +} + +private struct AttachmentOptionsMenu: View { + let attachment: DraftAttachment + @Binding var recognizingText: Bool + var body: some View { + Menu { + if attachment.drawingData != nil { + EditDrawingButton(attachment: attachment) + } else if attachment.type == .image { + RecognizeTextButton(attachment: attachment, recognizingText: $recognizingText) + } + } label: { + Label("Options", systemImage: "ellipsis.circle.fill") + } + .buttonStyle(AttachmentOverlayButtonStyle()) + .padding([.top, .leading], 2) + } } private struct RecognizeTextButton: View { @@ -138,29 +146,47 @@ private struct AttachmentRemoveButton: View { draft.attachments = attachments DraftsPersistentContainer.shared.viewContext.delete(attachment) } - .labelStyle(.iconOnly) - .imageScale(.large) - .foregroundStyle(.white) - .shadow(radius: 2) + .buttonStyle(AttachmentOverlayButtonStyle()) .padding([.top, .trailing], 2) } } +private struct AttachmentOverlayButtonStyle: ButtonStyle { + func makeBody(configuration: Configuration) -> some View { + configuration.label + .labelStyle(.iconOnly) + .imageScale(.large) + .foregroundStyle(.white) + .shadow(radius: 2) + } +} + private struct AttachmentDescriptionLabel: View { @ObservedObject var attachment: DraftAttachment + let recognizingText: Bool var body: some View { ZStack(alignment: .bottomLeading) { LinearGradient( - stops: [.init(color: .clear, location: 0), .init(color: .clear, location: 0.6), .init(color: .black.opacity(0.5), location: 1)], + stops: [.init(color: .clear, location: 0.6), .init(color: .black.opacity(0.15), location: 0.7), .init(color: .black.opacity(0.5), location: 1)], startPoint: .top, endPoint: .bottom ) + labelOrProgress + .padding([.horizontal, .bottom], 4) + } + } + + @ViewBuilder + private var labelOrProgress: some View { + if recognizingText { + ProgressView() + .progressViewStyle(.circular) + } else { label .foregroundStyle(.white) - .shadow(color: .black.opacity(0.5), radius: 1) - .padding([.horizontal, .bottom], 4) + .shadow(color: .black.opacity(0.75), radius: 1) } }